Jump to content

[1.15] I have multiple questions about a few things.


Tavi007

Recommended Posts

Hello!

I know, the title is not saying much, but I didn't want to open multiple threads for maybe easy questions. First thing first, here is my repository.

 

1. I use a capability to store extra information for an itemstack. I want to fill this capability, with default values (this works) and also when the item has a certain enchantment. For the default values I use the attachCapabilityEvent and this works just fine. However I can't do the same for the enchantments, because the enchantments haven't be applied to the itemstack in this event yet. If I call "EnchantmentHelper.getEnchantments(item)" in this event, I will always get an empty map, even if the actual itemstack has an enchantment ingame. My question is, which event should I use instead? The event only needs to be fired once, so I can check for the right enchantment and add the data to the capability.

 

2. Speaking of capabilities. I still have one problem with mine. Please take a look at the defense capability. It has 2 sets, but theire data won't get saved. This is most likely due to an error in the readNBT functions, because I don't know how use "NBTHelper.fromNBTToSet(...)" properly.

 

3. I would like to change the 'hurt'-animation of an LivingEntity (the mob-flashes-red-animation). In fact, I only want to change the color of it to either be yellow or green. Is this possible at all and if so, which event would I need to use?

4. How can I disable vanilla enchantments? In this case, I don't want the fire resistance enchantment to be obtainable ingame. Unregistering this enchantment is probably to much and will only cause problems down the line.

 

Thank you in advance, if you have an answere for any of my questions :)

Link to comment
Share on other sites

22 hours ago, diesieben07 said:
  1. Lazily populate the values whenever they are accessed. E.g in your capability make a method getSomeValue(ItemStack). When it's called, check if "some value" is set. If not, compute it first using the provided ItemStack. Otherwise just return it. Then whenever you need "some value", call this method.
  2. The 2nd parameter for CompoundNBT#getList is the type ID for the tag contained in the list. So if you have a list of strings, you need to pass the NBT ID for string. Use Constants.NBT for the NBT type IDs. Currently you are always passing the type ID for "list" (think a bit about why that is). This means you want a list of lists. getList will realize the actual list stored is a list of strings and return an empty list instead because the types don't match.

That helped a lot! I could fix both these issues.

 

22 hours ago, diesieben07 said:
  1. The hurt overlay is, as far as I can tell, handled by OverlayTexture. You need to replicate what the constructor does in FMLClientSetupEvent (use DeferredWorkQueue to run on the main thread). You can get the OverlayTexture instance from Minecraft#gameRenderer. You'll need some reflection to get it's internal values, but then you should be able to overwrite the image data and re-upload it using OpenGL (like done in it's constructor).

This sounds like I would override the red overlayTexture completly and only my yellow/green one would be applied, which I don't want. I formulated my question badly, so this is on me. What I want is to change this overlayTexture to a yellow one, if the damage is 0 and to a green one, if the damage is negativ (aka healing the entity). Would your suggestion still work in this case? (I haven't started to read the code yet. All I want is a heads up from someone more advanced on this topic.)

 

22 hours ago, diesieben07 said:
  1. Add your own EnchantmentType (EnchantmentType.create, note that the name must include your ModID to avoid collisions). This allows you to provide a predicate that chooses which items can be enchanted by this type. In your case you can just make a predicate that always returns false. Then set Enchantment#type to your new EnchantmentType for whichever Enchantments you want to disable. Note that individual items can still override this behavior by overriding IForgeItem#canApplyAtEnchantingTable. There is no way to prevent this. And yes, unregistering things is not supported.
    This won't disable enchanted books for this enchantment, but the books are not usable.

From a player perspective I would be annoyed, if I have an enchanted book, that can't be applied to any of my items. I want this enchantment to be removed, because I changed the damage calculation and currently this enchantment would reduce fire damage twice. If I could disable the calculation in ProtectionEnchantment::calcModifierDamage for the FIRE case, I would be happy too. With 1.16 forge added mixins, which I played around with through fabric. Could applying a mixin in this method be a solution? If you don't have a better idea, I might go with your suggested solution.

Link to comment
Share on other sites

7 minutes ago, diesieben07 said:

There is no "negative damage" in Minecraft.

Healing an entity does not cause an overlay currently, you'd have to somehow add a new overlay for when an entity is healed (LivingHealEvent, most likely a server-only event).

Please take a look at https://github.com/Tavi007/ElementalCombat/blob/00f3f7b3bef6f065f4ef264b82bdba53bce853ac/1.15.2/src/main/java/Tavi007/ElementalCombat/events/ElementifyLivingHurtEvent.java#L185

ignore the setCanceled(), because this was from testing (I hoped this would cancel the red overlay from being applied). In my method I could differentiate between the 3 damage cases (damage>0, damage=0 and damage<0). If damage>0, I want to apply the red overlay. if damage=0, apply yellow overlay and so on. So I would have to cancel the red overlay (if the right conditions are met) and instead apply my costum overlays. But I don't know where to start with this. Do you know by chance, which vanilla class I should take a look at?

 

19 minutes ago, diesieben07 said:

You could use registry-replacement (simply register a new enchantment with the same name) and override canApplyAtEnchantingTable and isAllowedOnBooks to return false.

Coremodding is a last-resort and not necessary here.

I will try this and hopefully it works as I want :)

Link to comment
Share on other sites

23 hours ago, diesieben07 said:

You could use registry-replacement (simply register a new enchantment with the same name) and override canApplyAtEnchantingTable and isAllowedOnBooks to return false.

Coremodding is a last-resort and not necessary here.

Here is what I tried. I call this line in a Register<Enchantment> event, which should replace the vanilla enchantment with my costum one.

event.getRegistry().register(ElementalEnchantments.FIRE_PROTECTION.setRegistryName(Enchantments.FIRE_PROTECTION.getRegistryName()));
		

However this fails on runtime:

[31Jul2020 17:00:48.655] [Render thread/ERROR] [net.minecraftforge.fml.javafmlmod.FMLModContainer/]: Exception caught during firing event: Attempted to set registry name with existing registry name! New: minecraft:fire_protection Old: elementalcombat:fire_protection
	Index: 2
	Listeners:
		0: NORMAL
		1: ASM: class Tavi007.ElementalCombat.StartupCommon onIParticleTypeRegistration(Lnet/minecraftforge/event/RegistryEvent$Register;)V
		2: ASM: class Tavi007.ElementalCombat.StartupCommon registerEnchantments(Lnet/minecraftforge/event/RegistryEvent$Register;)V
java.lang.IllegalStateException: Attempted to set registry name with existing registry name! New: minecraft:fire_protection Old: elementalcombat:fire_protection
	at net.minecraftforge.registries.ForgeRegistryEntry.setRegistryName(ForgeRegistryEntry.java:43)
	at net.minecraftforge.registries.ForgeRegistryEntry.setRegistryName(ForgeRegistryEntry.java:50)
	at Tavi007.ElementalCombat.StartupCommon.registerEnchantments(StartupCommon.java:61)
	at net.minecraftforge.eventbus.ASMEventHandler_1_StartupCommon_registerEnchantments_Register.invoke(.dynamic)
	at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:80)
	at net.minecraftforge.eventbus.EventBus.post(EventBus.java:258)
	at net.minecraftforge.fml.javafmlmod.FMLModContainer.fireEvent(FMLModContainer.java:106)
	at java.util.function.Consumer.lambda$andThen$0(Unknown Source)
	at java.util.function.Consumer.lambda$andThen$0(Unknown Source)
	at net.minecraftforge.fml.ModContainer.transitionState(ModContainer.java:112)
	at net.minecraftforge.fml.ModList.lambda$dispatchSynchronousEvent$5(ModList.java:126)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
	at java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
	at net.minecraftforge.fml.ModList.dispatchSynchronousEvent(ModList.java:126)
	at net.minecraftforge.fml.ModList.lambda$static$1(ModList.java:96)
	at net.minecraftforge.fml.LifecycleEventProvider.dispatch(LifecycleEventProvider.java:71)
	at net.minecraftforge.fml.ModLoader.dispatchAndHandleError(ModLoader.java:214)
	at net.minecraftforge.fml.ModLoader.lambda$gatherAndInitializeMods$25(ModLoader.java:206)
	at net.minecraftforge.registries.GameData.fireRegistryEvents(GameData.java:973)
	at net.minecraftforge.fml.ModLoader.gatherAndInitializeMods(ModLoader.java:206)
	at net.minecraftforge.fml.client.ClientModLoader.lambda$begin$2(ClientModLoader.java:97)
	at net.minecraftforge.fml.client.ClientModLoader.lambda$createRunnableWithCatch$5(ClientModLoader.java:113)
	at net.minecraftforge.fml.client.ClientModLoader.begin(ClientModLoader.java:97)
	at net.minecraft.client.Minecraft.<init>(Minecraft.java:397)
	at net.minecraft.client.main.Main.main(Main.java:141)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at net.minecraftforge.userdev.FMLUserdevClientLaunchProvider.lambda$launchService$0(FMLUserdevClientLaunchProvider.java:55)
	at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37)
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:54)
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:72)
	at cpw.mods.modlauncher.Launcher.run(Launcher.java:81)
	at cpw.mods.modlauncher.Launcher.main(Launcher.java:65)
	at net.minecraftforge.userdev.LaunchTesting.main(LaunchTesting.java:102)

I'm kinda stumped now. An idea how I could fix this?

Link to comment
Share on other sites

Nevermind,

 

I just had an idea and it worked out. I have to set the registryName in the constructor of my costum enchantment like this

	public FireResistanceEnchantment() {
		super(Rarity.VERY_RARE, EnchantmentType.ARMOR, ARMOR_SLOTS);
		//this.setRegistryName("fire_protection");
		this.setRegistryName(Enchantments.FIRE_PROTECTION.getRegistryName());
		super.name = "New Fire Protection";
	}

 

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

Okay, before you continue: You are currently creating all your registry entries in a static initializer.

You cannot do this. Registry entries must be created in their appropriate registry event. 

 

The error you get is because you called setRegistryName twice for the same registry entry.

oh, okay. I will fix this

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

Okay, before you continue: You are currently creating all your registry entries in a static initializer.

You cannot do this. Registry entries must be created in their appropriate registry event. 

 

The error you get is because you called setRegistryName twice for the same registry entry.

Is this better now?

 

	@SubscribeEvent
	public static void registerEnchantments(Register<Enchantment> event) {
		event.getRegistry().register(new ElementalResistanceEnchantment(ElementalResistanceEnchantment.Type.FIRE).setRegistryName(Enchantments.FIRE_PROTECTION.getRegistryName()));
		event.getRegistry().register(new ElementalResistanceEnchantment(ElementalResistanceEnchantment.Type.ICE).setRegistryName("ice_protection"));
		event.getRegistry().register(new ElementalResistanceEnchantment(ElementalResistanceEnchantment.Type.WATER).setRegistryName("water_protection"));
		event.getRegistry().register(new ElementalResistanceEnchantment(ElementalResistanceEnchantment.Type.THUNDER).setRegistryName("thunder_protection"));

		event.getRegistry().register(new ElementalWeaponEnchantment(ElementalWeaponEnchantment.Type.ICE).setRegistryName("ice_aspect"));
		event.getRegistry().register(new ElementalWeaponEnchantment(ElementalWeaponEnchantment.Type.WATER).setRegistryName("water_aspect"));
		event.getRegistry().register(new ElementalWeaponEnchantment(ElementalWeaponEnchantment.Type.THUNDER).setRegistryName("thunder_aspect"));
	}

 

sometimes I wish the example mod would provide more code. A proper example for a particle/an item/a block/an enchantment/whatever could reduce a lot of question... I would support you, but since I'm a newbie, I wouldn't be helpful :/

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.