Tavi007
Members-
Posts
145 -
Joined
-
Last visited
Everything posted by Tavi007
-
Hey all, See title. I think, there are 2 solutions: Either it is possible to get from the entity to the itemstack directly or I fill a capability from the arrow the moment it gets created. However I don't know how to do either. Is there an event, that I can use for filling the capability? I know about ArrowLooseEvent, but I can't find the arrowEntity here, so I assume, that it will be created after this event. I hope, someone knows more. (sorry for triple posting. Some error occured while posting, so I tried it a few times, without realising that it worked already the first time)
-
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Thanks a lot for all your help! Everything works now. should i write a summary in the OP? Or would this be unnecessary, because 1.16 is around the corner? -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Yup got it. Loading a datapack works just fine now. Last problem now (I swear!). How do I get the mod id of the mob? I found LivingEntity entity = event.getEntityLiving(); String modid = RegistryManager.ACTIVE.getRegistry(entity.getClass()).getRegistryName().getNamespace(); but this fails: C:\Minecraft Modding\ElementalCombat\src\main\java\Tavi007\ElementalCombat\events\ElementifyLivingEntitySpawnEvent.java:43: error: no suitable method found for getRegistry(Class<CAP#1>) String modid = RegistryManager.ACTIVE.getRegistry(e).getRegistryName().getNamespace(); ^ method RegistryManager.<V#1>getRegistry(ResourceLocation) is not applicable (cannot infer type-variable(s) V#1 (argument mismatch; Class<CAP#1> cannot be converted to ResourceLocation)) method RegistryManager.<V#2>getRegistry(Class<? super V#2>) is not applicable (cannot infer type-variable(s) V#2 (argument mismatch; Class<CAP#1> cannot be converted to Class<? super V#2>)) method RegistryManager.<V#3>getRegistry(ResourceLocation,RegistryManager) is not applicable (cannot infer type-variable(s) V#3 (actual and formal argument lists differ in length)) where V#1,V#2,V#3 are type-variables: V#1 extends IForgeRegistryEntry<V#1> declared in method <V#1>getRegistry(ResourceLocation) V#2 extends IForgeRegistryEntry<V#2> declared in method <V#2>getRegistry(Class<? super V#2>) V#3 extends IForgeRegistryEntry<V#3> declared in method <V#3>getRegistry(ResourceLocation,RegistryManager) where CAP#1 is a fresh type-variable: CAP#1 extends Entity from capture of ? extends Entity 1 error getRegistry() wants a namespace in this case. But it can also take Class<? super V> cls as an input, which i thought, I could do like this. -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
So for a vanilla zombie it would be minecraft:elementalcombat/entities/zombie,json? And for any mob from another mod it would be <their mod id>:elementalcombat/entities/<their mob id>.json? But I would also like to have the possibility for people to change the provided elemental properties via datapack. What would change to the resourceLocation of minecraft:elementalcombat/zombie.json, if someone installs a pack? Will the data of the pack override the default one? I might rename elementalcombat to elementalproperties to be more comprehensible for others... . -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Figure it out myself. I didn't notice there were sub classes in LivingSpawnEvent. Using CheckSpawn and SpecialSpawn I could exactly do, what I wanted Any comment on this? This is the last problem, that I need to understand -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Home stretch! The loading seems to be working now. To acces the data I use the map <ResourceLocation, ElementalData> from the ElemenDataManager and give it the right ResourceLocation, right? Now I only need the right ResourceLocation, which can change with the choosen datapack. Going by Alpvax I have the following folder structure: data/<datapackid>/<your mod id>/entities/<modid>/<mobname>.json or with actual ids: data/default/elementalcomabt/entities/minecraft/zombie.json. I plan on adding elemental properties to itemstacks in the same fashion, so i would have a folder on the same level as entities called 'items'. Using this format the ResourceLocation for Zombie currently looks like this: default:entities/minecraft/zombie I don't know much about handling a DataPack yet, but this ResourceLocation seems kinda wrong to me. Shouldn't the namespace be my mod id? Also this way I would need to figure out from which mod the entity is coming from. On another topic: how can I set this data as default for a spawning mob? I tried using the LivingSpawnEvent, thinking it would only fire, if the spawn would be succesful. But it turns out to be firing a lot, without actually spawning anything. Using this event would drastically increase computing time, which I don't like. But it would work tho. The capability is a lot more flexible. By using a capability each mob of the same type can have different elemental properties. Imagine a mob which has an ice resistance aura. A zombie in range of said aura would have "ice" in its resistance list, while a zombie outside would not. Or imagine a boss, that changes his properties throught the fight. The player would have to adapt mid fight, which could be fun. -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Ahhh okay. I think, I got it now. I copied a lot from LootTableManager and changed some bits accordingly. My mod compiles and nothing crashes so far, but I don't know, if it ran through my code. I would assume not, because I haven't registered it nor fired an event for it. So what would I have to do? -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
I tried to understand it a little bit more, but I sitll have problems wrapping my head around some functions of LootTableManager. //from LoottableManager: public static void func_227508_a_(ValidationTracker p_227508_0_, ResourceLocation p_227508_1_, LootTable p_227508_2_) { p_227508_2_.func_227506_a_(p_227508_0_.func_227529_a_(p_227508_2_.getParameterSet()).func_227531_a_("{" + p_227508_1_ + "}", p_227508_1_)); } Why are the function and variable names so cryptic? Is there any reason? What is even happening here? Anyway please take a look at my current files. First ElementalData, where I do not know, if it's the right approach. package Tavi007.ElementalCombat; import java.util.Set; import com.google.common.collect.Sets; import net.minecraft.util.ResourceLocation; public class ElementalData { public static final ResourceLocation EMPTY = new ResourceLocation(ElementalCombat.MOD_ID, "empty"); private final Set<String> weakSet; private final Set<String> resiSet; private final Set<String> wallSet; private final Set<String> absoSet; private final Set<String> atckSet; public ElementalData(Set<String> weak, Set<String> resi, Set<String> wall, Set<String> abso, Set<String> atck) { this.weakSet = weak; this.resiSet = resi; this.wallSet = wall; this.absoSet = abso; this.atckSet = atck; } public ElementalData() { this.weakSet = Sets.newHashSet(); this.resiSet = Sets.newHashSet(); this.wallSet = Sets.newHashSet(); this.absoSet = Sets.newHashSet(); this.atckSet = Sets.newHashSet(); } public Set<String> getWeaknessSet() { return this.weakSet; } public Set<String> getResistanceSet() { return this.resiSet; } public Set<String> getWallSet() { return this.wallSet; } public Set<String> getAbsorbSet() { return this.absoSet; } public Set<String> getAttackSet() { return this.atckSet; } } And secondly the ElementalDataManager, which I've been building up like LootTableManager: package Tavi007.ElementalCombat; import java.util.Map; import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.client.resources.JsonReloadListener; import net.minecraft.profiler.IProfiler; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.ValidationTracker; public class ElementalDataManager extends JsonReloadListener { private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create(); private static final Logger LOGGER = LogManager.getLogger(); private Map<ResourceLocation, ElementalData> registeredElementalData = ImmutableMap.of(); public ElementalDataManager() { super(GSON, "elementalcombat"); } protected void apply(Map<ResourceLocation, JsonObject> objectIn, IResourceManager resourceManagerIn, IProfiler profilerIn) { Builder<ResourceLocation, ElementalData> builder = ImmutableMap.builder(); JsonObject jsonobject = objectIn.remove(ElementalData.EMPTY); if (jsonobject != null) { LOGGER.warn("Datapack tried to redefine {} elemental entity data, ignoring", (Object)ElementalData.EMPTY); } objectIn.forEach((rl, json) -> { try (net.minecraft.resources.IResource res = resourceManagerIn.getResource(getPreparedPath(rl));) { ElementalData elementalData = new ElementalData(); //what do I have to do here? Empty for now //copied from LootTableManager: //LootTable loottable = net.minecraftforge.common.ForgeHooks.loadLootTable(GSON_INSTANCE, rl, json, res == null || !res.getPackName().equals("Default"), this); builder.put(rl, elementalData); } catch (Exception exception) { LOGGER.error("Couldn't parse elemental entity data {}", rl, exception); } }); builder.put(ElementalData.EMPTY, new ElementalData()); ImmutableMap<ResourceLocation, ElementalData> immutablemap = builder.build(); //this mapping contains attack and defense data. //validation of immutablemap missing //copied from LootTable: //ValidationTracker validationtracker = new ValidationTracker(LootParameterSets.GENERIC, this.field_227507_d_::func_227517_a_, immutablemap::get); //immutablemap.forEach((rl, json) -> //{ // func_227508_a_(validationtracker, rl, json); //}); //validationtracker.getProblems().forEach((rl, json) -> //{ // LOGGER.warn("Found validation problem in " + rl + ": " + json); //}); this.registeredElementalData = immutablemap; } public static JsonElement toJson(ElementalData elementalData) { return GSON.toJsonTree(elementalData); } public Set<ResourceLocation> getElementalDataKeys() { return this.registeredElementalData.keySet(); } } I do know, that I should not create an empty ElementalData. But I also don't understand, what is happening at the same line in LootTableManager. Can anyone please elaborate? Is there an easy way for me to validate the immutableMap or do I have to write my own function for it? And my last question: Where do I have to use the Manager? Do I have to register it somewhere or do I have to call a certain event? -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
I know. They are placeholders for now, so nothing breaks when i compile. Good call. But I still don't know, how I would get the complete hierarchy. I need to find out, which folder/file (aka mods or mobs) exist. -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Oh man, what did I get myself into. Understanding uncommmented code is such a pain, especially with so many classes. If I understood everything correctly I need a bunch of difference classes. First the actually storage for all the resourceLocation: ElementalDataStorage public class ElementalEntityData { private static final Set<ResourceLocation> ELEMENTAL_ENTITY_DATA = Sets.newHashSet(); public static final ResourceLocation EMPTY = new ResourceLocation(ElementalCombat.MOD_ID, "empty"); public ElementalEntityData() { Set<String> modFolderList = Sets.newHashSet(); for (final String modFolder : modFolderList)//loop over supported mods { Set<String> mobFileList = Sets.newHashSet(); for (final String mobFile : mobFileList)//loop over supported mobs (not listed mobs will use 'empty' as default) { register("entities/" + modFolder + "/" + mobFile); } } } private static ResourceLocation register(String id) { return register(new ResourceLocation(ElementalCombat.MOD_ID, id)); } private static ResourceLocation register(ResourceLocation id) { if (ELEMENTAL_ENTITY_DATA.add(id)) { return id; } else { throw new IllegalArgumentException(id + " is already registered elemental entity data"); } } } My first problem arises, when i want to find every json-file. My folder hierarchy looks like this: data/entities/<supported mod>/<mobs from mod>, where <supported mod> should be the mod id. For the vanilla mobs, this will be named 'minecraft'. Inside this folder one can find the json-file for a mob, i.e zombie_elementalproperties.json. Now I would like to find every file, that uses this directory format. This should hopefully make adding support for other mods easier later on. But how can I find modFolderList and mobFile? After ElementalEntityData is done, I need to create the class ElementalDataManager, which extends JsonReloadListener just like LootTableManager or RecipeManager. If I understood it correctly, this class handles the json-object, that got loaded with the help of ElementalEntityData. Could you give me some insight on the function apply(), please? I don't fully understand, what it is doing. -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Well, now I feel dumb. I think, I'm doing every noobish error there is Anyway, I did a little bit more progress and now I finally have a working capability (I think). The last remaing part, would be the actual loading of the data from a json file. Preferably I would like to load the data from the files once and set them as default values for the different LivingEntities. I.e. load ZombieData.json once at set its content as default values for every spawning zombie entity. Is this somehow possible? -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
I finally got my code to compile, but it crashes, whenever I try to play a world due to a NullPointerException. Here is the crash report: ---- Minecraft Crash Report ---- // Daisy, daisy... Time: 07.06.20 17:37 Description: Ticking memory connection java.lang.NullPointerException: Ticking memory connection at Tavi007.ElementalCombat.capabilities.ElementalDefenceDataCapability.<init>(ElementalDefenceDataCapability.java:20) ~[main/:?] {re:classloading,pl:capability_inject_definalize:A} at Tavi007.ElementalCombat.ElementalCombatForgeEventBusSub.onAttachEntity(ElementalCombatForgeEventBusSub.java:19) ~[main/:?] {re:classloading} at net.minecraftforge.eventbus.ASMEventHandler_1_ElementalCombatForgeEventBusSub_onAttachEntity_AttachCapabilitiesEvent.invoke(.dynamic) ~[?:?] {} at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:80) ~[eventbus-2.2.0-service.jar:?] {} at net.minecraftforge.eventbus.EventBus.post(EventBus.java:258) ~[eventbus-2.2.0-service.jar:?] {} at net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(ForgeEventFactory.java:564) ~[?:?] {re:classloading} at net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(ForgeEventFactory.java:558) ~[?:?] {re:classloading} at net.minecraftforge.common.capabilities.CapabilityProvider.gatherCapabilities(CapabilityProvider.java:48) ~[?:?] {re:classloading} at net.minecraftforge.common.capabilities.CapabilityProvider.gatherCapabilities(CapabilityProvider.java:44) ~[?:?] {re:classloading} at net.minecraft.entity.Entity.<init>(Entity.java:221) ~[?:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.entity.LivingEntity.<init>(LivingEntity.java:198) ~[?:?] {re:classloading} at net.minecraft.entity.player.PlayerEntity.<init>(PlayerEntity.java:163) ~[?:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.entity.player.ServerPlayerEntity.<init>(ServerPlayerEntity.java:158) ~[?:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.server.management.PlayerList.createPlayerForUser(PlayerList.java:382) ~[?:?] {re:classloading} at net.minecraft.network.login.ServerLoginNetHandler.tryAcceptPlayer(ServerLoginNetHandler.java:116) ~[?:?] {re:classloading} at net.minecraft.network.login.ServerLoginNetHandler.tick(ServerLoginNetHandler.java:63) ~[?:?] {re:classloading} at net.minecraft.network.NetworkManager.tick(NetworkManager.java:224) ~[?:?] {re:classloading} at net.minecraft.network.NetworkSystem.tick(NetworkSystem.java:135) ~[?:?] {re:classloading} at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:866) ~[?:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:784) ~[?:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:114) ~[?:?] {re:classloading,pl:runtimedistcleaner:A} at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:637) [?:?] {re:classloading,pl:accesstransformer:B} at java.lang.Thread.run(Thread.java:748) [?:1.8.0_251] {} A detailed walkthrough of the error, its code path and all known details is as follows: --------------------------------------------------------------------------------------- -- Head -- Thread: Server thread Stacktrace: at Tavi007.ElementalCombat.capabilities.ElementalDefenceDataCapability.<init>(ElementalDefenceDataCapability.java:20) at Tavi007.ElementalCombat.ElementalCombatForgeEventBusSub.onAttachEntity(ElementalCombatForgeEventBusSub.java:19) at net.minecraftforge.eventbus.ASMEventHandler_1_ElementalCombatForgeEventBusSub_onAttachEntity_AttachCapabilitiesEvent.invoke(.dynamic) at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:80) at net.minecraftforge.eventbus.EventBus.post(EventBus.java:258) at net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(ForgeEventFactory.java:564) at net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(ForgeEventFactory.java:558) at net.minecraftforge.common.capabilities.CapabilityProvider.gatherCapabilities(CapabilityProvider.java:48) at net.minecraftforge.common.capabilities.CapabilityProvider.gatherCapabilities(CapabilityProvider.java:44) at net.minecraft.entity.Entity.<init>(Entity.java:221) at net.minecraft.entity.LivingEntity.<init>(LivingEntity.java:198) at net.minecraft.entity.player.PlayerEntity.<init>(PlayerEntity.java:163) at net.minecraft.entity.player.ServerPlayerEntity.<init>(ServerPlayerEntity.java:158) at net.minecraft.server.management.PlayerList.createPlayerForUser(PlayerList.java:382) at net.minecraft.network.login.ServerLoginNetHandler.tryAcceptPlayer(ServerLoginNetHandler.java:116) at net.minecraft.network.login.ServerLoginNetHandler.tick(ServerLoginNetHandler.java:63) at net.minecraft.network.NetworkManager.tick(NetworkManager.java:224) -- Ticking connection -- Details: Connection: net.minecraft.network.NetworkManager@1f59faee Stacktrace: at net.minecraft.network.NetworkSystem.tick(NetworkSystem.java:135) at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:866) at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:784) at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:114) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:637) at java.lang.Thread.run(Thread.java:748) -- System Details -- Details: Minecraft Version: 1.15.2 Minecraft Version ID: 1.15.2 Operating System: Windows 10 (amd64) version 10.0 Java Version: 1.8.0_251, Oracle Corporation Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation Memory: 102800968 bytes (98 MB) / 694681600 bytes (662 MB) up to 954728448 bytes (910 MB) CPUs: 2 JVM Flags: 2 total; -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -Xmx1024m ModLauncher: 5.1.0+69+master.79f13f7 ModLauncher launch target: fmluserdevclient ModLauncher naming: mcp ModLauncher services: /eventbus-2.2.0-service.jar eventbus PLUGINSERVICE /forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1-launcher.jar object_holder_definalize PLUGINSERVICE /forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1-launcher.jar runtime_enum_extender PLUGINSERVICE /accesstransformers-2.1.1-shadowed.jar accesstransformer PLUGINSERVICE /forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1-launcher.jar capability_inject_definalize PLUGINSERVICE /forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1-launcher.jar runtimedistcleaner PLUGINSERVICE /forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1-launcher.jar fml TRANSFORMATIONSERVICE FML: 31.2 Forge: net.minecraftforge:31.2.0 FML Language Providers: [email protected] minecraft@1 Mod List: client-extra.jar Minecraft {[email protected] DONE} forge-1.15.2-31.2.0_mapped_snapshot_20200514-1.15.1.jar Forge {[email protected] DONE} main Elemental Combat {[email protected] DONE} Player Count: 0 / 8; [] Data Packs: vanilla, mod:forge (incompatible), mod:elementalcombat Type: Integrated Server (map_client.txt) Is Modded: Definitely; Client brand changed to 'forge' I tried to get it to work yesterday, but couldn't figure it out. I've been writing this compability like in this repository: https://github.com/soravoid/Exceed/tree/master/src/main/java/com/github/soravoid/exceed This repository does indeed work (I tested it), but uses forge 31.1.12, while I use 31.2.0. Not sure if this makes a huge difference. By the way, here is a link to my repository: https://github.com/Tavi007/ElementalCombat. On a completly different note I'm trying to design this mod to be efficient and I was wondering, if I'm on the right path. Basically I want every LivingEntity to have elemental weaknesses/resistance lists as public variables (So I can check them in combat). I also want to set these variables for each entity type (Zombie/Skeleton/Pig/...) once and not every time the entity spawns into the world. I dont't want the game to load up the weakness/resistance list from the json-file everytime the entity spawns, because that seems to be heavy on the computation side... -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
I tried to do, what you told me. But I still have 2 remaining problems. First my code again: package Tavi007.ElementalCombat.capabilities; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.StringNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; public class ElementalDefenceDataStorage implements Capability.IStorage<IElementalDefenceData> { @Nullable @Override public INBT writeNBT(Capability<IElementalDefenceData> capability, IElementalDefenceData instance, Direction side) { List<String> weakList = instance.getWeaknessList(); //fill nbt with data CompoundNBT nbt = new CompoundNBT(); nbt.put("elem_weak", fromListToNBT(weakList)); return nbt; } @Override public void readNBT(Capability<IElementalDefenceData> capability, IElementalDefenceData instance, Direction side, INBT nbt) { if (!(instance instanceof ElementalDefenceData)) throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation"); //fill lists with nbt data CompoundNBT nbtCompound = (CompoundNBT)nbt; instance.setWeaknessList( fromNBTToList(nbtCompound.getList("elem_weak", ????))); } private List<String> fromNBTToList(ListNBT nbt) { List<String> list = new ArrayList<String>(); Iterator<INBT> iterator = nbt.iterator(); while (iterator.hasNext()) { list.add(iterator.toString()); } return list; } private ListNBT fromListToNBT(List<String> list) { ListNBT nbt = new ListNBT(); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.toString(); StringNBT snbt = new StringNBT(s); nbt.add(snbt); } return nbt; } } When I use nbtCompound.getList, it expects an Integer. I thought, that the key string (so "elem_weak", correct?) would be enough to get all corresponding values. So what does this Integer do? My second problem is with StringNBT. I can't get the constructor to work properly. Even a simple new StringNBT() did not work. I also somehowc can't look at the source code (but I could import it...). Is my project setup incorrectly? Hope you can help me out one more time -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
I've been reading through the docs and used google a bit more. I do understand now, what I have to do, but I have trouble with actual writing the code. What I have so far: package Tavi007.ElementalCombat.capabilities; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; import net.minecraft.nbt.ListNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; public class ElementalDefenceDataStorage implements Capability.IStorage<IElementalDefenceData> { @Nullable @Override public INBT writeNBT(Capability<IElementalDefenceData> capability, IElementalDefenceData instance, Direction side) { List<String> weaknessList = instance.getWeaknessList(); //fill nbt with data CompoundNBT nbt = new CompoundNBT(); ListNBT weaknessNBTList = new ListNBT(); nbt.put("elem_weakness", weaknessNBTList); return nbt; } @Override public void readNBT(Capability<IElementalDefenceData> capability, IElementalDefenceData instance, Direction side, INBT nbt) { if (!(instance instanceof ElementalDefenceData)) throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation"); List<String> weaknessList = new ArrayList<String>(); //fill list with nbt data CompoundNBT cnbt = (CompoundNBT)nbt; instance.setWeaknessList(weaknessList); } } How do I get the Information from List<String> to ListNBT and vice versa? Also I'm not sure, if I even need cnbt. I do understand the difference of the NBT Formats, but I have trouble using them in Java... -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Thanks a lot. If I still have trouble, I'll come asking again. -
[Solved][1.15.2] Adding elemental properties to LivingEntities
Tavi007 replied to Tavi007's topic in Modder Support
Ah, yeah. That was me testing. Can you elaborate on how to handle NBT data or link me to some explanation, please? I would like to know, how to handle this properly. -
Hello, people who came here from google. You can find a summary at the end of this post. Basically what i wanted to do, was to add public variables to an entity using a capability and then give it default values through json files. These default values can also be changed through the use of a datapack. This method should in theory also work with itemstacks or other things. ----------------------------------------- Hello community, I recently started with my first minecraft mod. I usually programm in c++, but I wanted to try something new. The whole Idea of my mod is to give every LivingEntity elemental properties for defence and attack. While the player can equip the right gear for the job, most mobs will have set weaknesses/resistance and may have certain elemental attacks. For example a Blaze will naturally be prone to ice attacks, while his projectiles obviously have the element 'fire'. I want to give each mobs these properties through the 'Capabilities'-system. Every LivingEntity should have 4 lists, which should be filled by loading data from .json files. This will make adding mobs from other mods/newer minecraft versions much easier, I hope. So how can I do that? For example the zombie_elemetalproperties.json file looks like this right now: { "weakness": [ "fire" ], "resistance": [ "ice", "water" ], "absorb": [ ], "wall": [ "thunder" ] } So some of the list can be empty and some can have multiple values. My best guess is, that I use the 'compability'-system, which is why I have the ElementalCombatData class and the appropiate interface: package Tavi007.ElementalCombat.capabilities; import java.util.List; public class ElementalCombatData implements IElementalCombatData { private List<String> weaknessList = null; private List<String> resistanceList = null; private List<String> wallList = null; private List<String> absorbList = null; // Setter @Override public void setWeaknessList(List<String> elementList) { this.weaknessList = elementList; } @Override public void setResistanceList(List<String> elementList) { this.resistanceList = elementList; } @Override public void setWallList(List<String> elementList) { this.wallList = elementList; } @Override public void setAbsorbList(List<String> elementList) { this.absorbList = elementList; } //Getter @Override public List<String> getWeaknessList() { return this.weaknessList; } @Override public List<String> getResistanceList() { return this.resistanceList; } @Override public List<String> getWallList() { return this.wallList; } @Override public List<String> getAbsorbList() { return this.absorbList; } } Once I know how I get one of these list to work, I can adjust the rest. Now I also have the capability-class: package Tavi007.ElementalCombat.capabilities; import javax.annotation.Nonnull; import javax.annotation.Nullable; import net.minecraft.nbt.ListNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.util.LazyOptional; public class ElementalCombatDataCapability implements ICapabilitySerializable<ListNBT> { @CapabilityInject(IElementalCombatData.class) public static final Capability<IElementalCombatData> DATA_CAPABILITY = null; private LazyOptional<IElementalCombatData> instance = LazyOptional.of(DATA_CAPABILITY::getDefaultInstance); public static void register() { CapabilityManager.INSTANCE.register(IElementalCombatData.class, new ElementalCombatDataStorage(), ElementalCombatData::new); } @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return DATA_CAPABILITY.orEmpty(cap, instance); } @Override public ListNBT serializeNBT() { return (ListNBT) DATA_CAPABILITY.getStorage().writeNBT(DATA_CAPABILITY, instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional cannot be empty!")), null); } @Override public void deserializeNBT(ListNBT nbt) { DATA_CAPABILITY.getStorage().readNBT(DATA_CAPABILITY, instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional cannot be empty!")), null, nbt); } } Granted, I only copied it from another thread, that I found through google, which I modified a little bit. I'm not sure, if I did everything correct so far. So please correct me, if you found anything. My problem right now lies within the storage-class, where the readNBT and writeNBT function reside. Right now it looks like this: package Tavi007.ElementalCombat.capabilities; import javax.annotation.Nullable; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; import net.minecraft.nbt.JsonToNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; public class ElementalCombatDataStorage implements Capability.IStorage<IElementalCombatData> { @Nullable @Override public INBT writeNBT(Capability<IElementalCombatData> capability, IElementalCombatData instance, Direction side) { CompoundNBT tag = JsonToNBT.getTagFromJson(jsonString) return tag; } @Override public void readNBT(Capability<IElementalCombatData> capability, IElementalCombatData instance, Direction side, INBT nbt) { if (!(instance instanceof ElementalCombatData)) throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation"); } } What do I have to enter for jsonString and what do I have to do in the read-function? Also what is 'Direction' supposed to mean? Thanks in advance SOLUTION: First of, here is my repo. The whole problem can be divided into 2 main problems: the capability and the loading. First of the capability. I used 4 classes: an interface and its implementation of the data you want, a storage function, that implements Capability.IStorage<your interface> and the capability class. Note, that you can change the compoundNBT to whatever NBT type you need. I choose compound, because it is basically the same as the json format. I hope the comments in these files describes enought for you. Also don't forget to register the capability at the FMLCommonSetupEvent and attach them to the entity/itemstack/whatever. To use the capability in an event, you can use 2 different method. Check out some of my events. For the loading you need a class with the same structure as your json file. Even the variable names need to be same (I think). I assume you could use the same class as for the capability, but in my case that was not possible. Next you need a class, that extends the JsonReloadListener. This thing, once registered, will fire everytime data needs to be loaded (i.e. using the /reload command in minecraft). This class now holds a mapping of the resourceLocation to your data. This map can be used to access the loaded data. You also need a a class, which handles the overriding of data through datapacks (I think. A lot of guesses from my side, cause I'm also new to forge). Again don't forget to register your reloadListener at FMLServerAboutToStartEvent (see my main class) I hope I could help you :D