Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. So I'm trying to port my wild animals mod from 1.7.10 all the way to 1.12.1. I'm pretty good at porting upwards and of course when new features are added sometimes I consider whether I should convert to the new system. I have complex animations on my client based on state fields in my custom entity class so I need to sync from server to client. In the past I used a custom packet with an NBT compound and frankly it worked well. But I wanted to see if the data manager would be a good alternative. So first of all I simply continued to use my NBT compound and created a DataParameter of type NBT compound. And for my EntityElephant class it worked great. When the elephant gets attacked the animation on the client has it rear up and furthermore nothing crashes. EDIT: Actually, it only appears to work because the code is running on both sides -- it doesn't seem that the information is being sent across to the client. So then I tried to do the same thing for my birds of prey entities. However, no matter which way I try it, I get various full on crashes of the game. I thought maybe it was due to using an NBT compound and so broke it up into individual DataParameter keys instead. And still I get crazy crashes. So I need help. Let me describe the latest crash... So when I try to spawn my EntityHawk using spawn egg the crash says: https://gist.github.com/jabelar/e5b220314afe05a26d62b30f7f18b94d This is the wierd part: Now if you follow the error message, it is happening during the super constructor for my entity (see my code here), specifically when the EntityLivingBase class constructor tries to set the health. This is really weird because this fires before any code runs in my entity class and so cannot be due to my registration of my DataParameter key pairs. Now of course there is something in the class that runs before the constructor -- the static fields are created. And I'm following the vanilla code's example to instantiate all my DataParameter keys by using the createKey() method. So it MUST be a problem with that. But I cannot see what the problem is. Currently I have all the keys created against the Entity.class but have also tried EntityBirdsOfPrey.class, and the vanilla classes all create their keys against Entity.class. The only thing I could think of was that maybe I have created a duplicate field name, but I traced all the way back the type hierarchy and can't see any that are the same. One other point is that I'm creating my keys against the dataManager instance inherited from the Entity class. I think that is correct, or am I supposed to instantiate my own EntityDataManager? So I need help. Thanks! I guess one question is whether the EntityDataManager is a valid, modern way for syncing a bit of data from the server to the client. Should i be doing something else? Also, if I have code that runs on both sides does the EntityDataManager handle that -- like can I call the set command from the client? Is that ignored? Or should I be checking side before using the set command?
  2. Actually, do you want all blocks of certain type to go invisible, or just certain ones within view or something based on specific positions? Any scheme to mess with the block models would affect all the blocks of that type. If you want different behavior for a block based on its specific position you only have two options: metadata or tile entity. Both of those imply that you would need a custom block since vanilla blocks don't have metadata for that and adding tile entities to all the vanilla blocks of a certain type would cause performance and storage problems. So you probably gotta find a way to intercept the render.
  3. I'm not sure about another way to intercept the render, but hopefully someone else knows. There are other ways that would be a lot of work, but I think possible. For example, perhaps you could replace the vanilla models with ones that are conditional based on a player capability. EDIT: Actually probably wouldn't work assuming you want to only make specific locations invisible. See more below.
  4. Hmm. I hadn't looked at that event for a while but you're right, it is not in 1.12.1 and looking at the events in minecraft forge client events referenced library doesn't show anything that looks like a replacement to me.
  5. there is an event, I think check spawn event that you can cancel to prevent a spawn after you've checked the conditions you care about.
  6. For example: if (!event.getWorld().isRemote && event.getHand() == EnumHand.MAIN_HAND) Will only execute once -- on the server with the main hand.
  7. You don't. If you subscribe to it it will fire four times,but what you do is use the parameters passed with the event to test which side it is and which hand it is.
  8. Well I think you should still look at biped model and render classes to understand how the information about the item is generally used. Then you simply have to calculate the equivalent positions in your mob's render class. In other words, in a biped model they know where the arm is (note that it can be swinging a sword and such too, so need to track anything that might make your mob's "hand" move). The rest is just math and depends a lot on how complicated the movement of your model is.
  9. Okay, I figured it out. I was essentially registering twice because my inherited class EntityElephant was also calling the initSyncCompound() method in the constructor in addition to the EntityHerdElephant parent class. All is good in the world now and I can finally get to sleep...
  10. So looking at theEntityDataManager#register method that throws the error, it very simply gets an integer "id" from the DataParameter that is passed in. That DataParameter is considered the "key" for the entries map. I created the DataParameter using the EntityDataManager#createKey method, so it is very confusing that it is saying that it already exists. I'm actually a bit suspicious though of the createKey code. It uses a "next ID map" that looks wierd to me. First of all it checks to see if the class you're trying to register (which should be <T extends Entity> type) is already in the NEXT_ID_MAP. In my case it should not be, so it uses a while loop to weird crawl through the NEXT_ID_MAP. It checks the superclass of the <T extends Entity> class that was passed in and if that is not in the NEXT_ID_MAP then it checks the next superclass and keeps going until it hits the Entity class itself. At that point it finds the largest ID for that class and adds 1 to that. I think that might be a bug though, since there will be other things in the map that have different parent hierarchies. Imagine you have two different classes that both have Entity as the direct parent, and imagine that 4 parameters are already registered for Entity as ID 0 to 3. Then both of these will want to get an ID of 4. Maybe I'm looking at it wrong, but that's what it seems like the code does. On the other hand, the vanilla entities seem to work okay so I guess I'm just misinterpreting the code path. But my main point is: the ID that is throwing the error is the one created by the DataManager's own createKey method so I don't understand how it could create one that would be a duplicate.
  11. So I'm porting all my mods to 1.12. In the past, due to limitations of the DataWatcher I had come up with my own custom packets and for every entity had an NBTTagCompound with custom data that I would sync between server and client. The system worked well. Now that there is a EntityDataWatcher I noticed there is a DataSerializer for NBTTagCompounds. So I figured great! now I can just use that instead of custom packets. I know I can also break my tag compound back up into individual elements and serialize those into the EntityDataWatcher but figured since I already had a tag compound I'd see what happens. Well, I get a very strange error when I try to use a spawn egg to spawn my EntityElephant (which extends EntityHerdAnimal). The error is: . Caused by: java.lang.IllegalArgumentException: Duplicate id value for 13! at net.minecraft.network.datasync.EntityDataManager.register(EntityDataManager.java:105) ~[EntityDataManager.class:?] at com.blogspot.jabelarminecraft.wildanimals.entities.herdanimals.EntityHerdAnimal.initSyncDataCompound(EntityHerdAnimal.java:86) ~[EntityHerdAnimal.class:?] The whole console output including the error is here: error gist Now the DataWatcher doesn't seem to be documented, so I'm looking at vanilla entities and did the following: In my custom entity class I created a DataParameter field for my tag compound like so: protected static final DataParameter<NBTTagCompound> SYNC_COMPOUND = EntityDataManager.<NBTTagCompound>createKey(EntityHerdAnimal.class, DataSerializers.COMPOUND_TAG); In my custom entity constructor I register the parameter with it's initial value (a tag compound which I have already set fields in) like so: dataManager.register(SYNC_COMPOUND, syncDataCompound); Anywhere I change a value in the tag compound I also set the data manager like so: dataManager.set(SYNC_COMPOUND, syncDataCompound); Anywhere I need a value I get the tag compound from the data manager and then the value from the compound, like so: dataManager.get(SYNC_COMPOUND).getFloat("scaleFactor") The whole class is here (feel free to try the download and try the mod as well): The code on GitHub So basically I think the error is very weird. It is obviously related to the register method in my constructor. One thing I noticed is that if I change the class to a parent class (like Entity) the error will change the id it complains about. So it seems to be a problem with the class I'm passing. Now the EntityHerdAnimal class itself is never instantiated (rather I extend it to EntityElephant) but that is consistent with other EntityDataManager entries -- such as for Entity. I'm wondering if it is an issue with the way I'm registering the EntityElephant itself? However, all the other entities in the game (EntityTiger, EntityEagle, etc.) all work although they use my old packet system -- EntityElephant was my first attempt at converting to EntityDataManager. Sorry for the long post, but really I just need someone to see if they see anything wrong in my EntityHerdAnimal class regarding the way I'm using the data manager. Thanks.
  12. Thanks for the additional info Draco. I think the main point I was missing about generics was what diesieben07 mentioned -- that the type wasn't available as a runtime field, rather it was more like a flexible casting system. I probably need to challenge myself to look at my code and figure out where generics would have been more useful and try it out. I think registries are an obvious place for it of course.
  13. Thanks that was the root of my problem. I also appreciate the detailed explanations about generics generally.
  14. Okay, so then effectively it is creating a new IRenderFactory for each type. I thought a "factory" was meant to be a singleton which handled all the types. I think that is where I went wrong.
  15. Maybe a simpler way to help me is starting with the factory class declaration: If I put: public class RenderFactory implements IRenderFactory it will complain about generic types. If I put public class RenderFactory<T> implements IRenderFactory<T> it complains that IRenderFactory<T> isn't correct since the interface is bounded by <T extends Entity> If I put public class RenderFactory<T> implements IRenderFactory<T> If I put public class RenderFactory implements IRenderFactory<EntityTiger> it is happy, but then that means I just created a factory only for EntityTiger which is what I was trying to avoid.
  16. Thanks for that explanation. That makes a lot of sense and explains better why I can't use the type at runtime. In this example, is the MyRenderer the factory class or the Render class? I'm assuming factory class since that is what the register method wants passed, but my factory class currently doesn't have any constructor, just the createRenderFor method. So I think you're saying I should create multiple constructors in the factory class and have each of them return a different Render<T> such as RenderTiger, RenderLion and such? And then that constructor would set a field to be RenderTiger and in the createRenderFor method I'd return that? You can see why I am still getting a bit confused ... Edit: I just started to implement what I just said above and immediately realized the I can't return a Render<T> because I actually have one Render for all big cats (RenderBigCat) that is just constructed with different textures depending on tiger, lion, etc. Also, I don't see how the register method would know to expect a RenderBigCat. I think the main point I'm missing, is how does the factory know which entity is being registered? And how does that translate to expecting a different Render class back. I'm looking through github and all the examples I find seem to create a different factory per render class, but I'm still thinking I should be able to create a single factory ...
  17. what does the error say?
  18. As mentioned, the 64 limit is coded into a lot of places so you can't just raise the limit by overriding the max stack size in a class. I have wondered though about creating a "ghost" inventory container to add further multiples of 64. Theoretically you could create a GUI that displays the combined count of several itemstacks stored in several containers. Then you'd also need to handle where the player is using an item stack which would actually be several item stacks and you'd display the total count. So I kinda feel it is possible to do, but certainly it would require crawling through all sorts of code and handling lists of ItemStacks wherever there is currently just a single ItemStack and changing the GUIs to provide the combined amount. Lots of work.
  19. .In a game like Minecraft, the mismatch between the visuals and the actual bounding boxes is part of the charm of the game. There are no exact hit boxes, and parts of models can overlap the nearby blocks or other entities. It is not meant to be super realistic. If you really have a need for this, then for the vanilla entities you'd have to figure out the mismatch yourself and perhaps handle cases like Draco mentions where you know the model might be changing size. For example, a child entity is scaled down. Basically I think for known entities it is possible to get pretty close, but just takes a bit of work and trial and error to get it the way you like it. But I don't think there is a generic way (like if you want it to work for other mod's entities). Or to be more precise, it would be a very advanced thing to do to inspect the models and figure it out generically.
  20. Okay, I'm admittedly fairly weak in using generics and it is causing me some trouble with my render factory. for my custom entities. IRenderFactory only takes a RenderManager as a parameter. But it also is <T extends Entity>. I assume that it gets the T from the registration method where you associate the entity class with the factory. However, I'm having trouble using the T to figure out which render class to return. Previously I worked around the limitation by creating a separate factory for each entity. So I'd have RenderFactoryTiger that returns the RenderTiger and RenderFactoryLion that returns the RenderLion. That works, but I feel certain that I'm not using the factory idea properly -- ideally you have one factory that returns the different renders based on the type T, right? I was hoping I could just check if T was instanceof and return the render based on that. In other words if T instanceof EntityTiger then return RenderTiger. But it doesn't seem that generics like that type of thing, or maybe I'm not properly associating the T from the interface to the T in my code? Anyway, I'd like to learn how to do this. Does someone have an example of a single factory returning different render classes based on the T registered with the factory?
  21. Were you messing around with the BreakEvent or block harvest event and somehow canceling the damage?
  22. He already explained what he's trying to do, he just want to randomly pick from all registered potions and apply it when a certain food item is eaten. So I think he should use the getValues() then pick random number based on the list size and get the element based on that index.
  23. The ItemHoe setBlock() method also calls stack.damageItem(1, player) so you're doing same as vanilla use should do. I'm sure you know how to trace the code as well or better than me, but seems like standard stuff would prevent the damage: if the max damage is less than zero, if the NBT tag has unbreakable boolean set true, if the unbreakable enchantment is in effect, if player is in creative mode. One thing though -- what material is your hoe? The ToolMaterial affects much of these fields.
  24. What do you mean by not taking skpped ticks into account? Are you talking about when there is lag? People argue about it but most end up agreeing that if the whole game is slowed down then you should scale accordingly -- if the ticks are only 10 per second then the player speed should be half as much. If you really wanted to calibrate to real time that is fairly easy to do though. Minecraft is just a Java program and Java has various methods for checking real-time. So you can create a timer that checks for difference in system time on each server tick and if it varies from the expected 1/20th of a second you can set a scale factor you can use for calculations during that tick.
  25. Actually diesieben07 a while back gave an idea on how to do this (intercept vanilla packets). I copied the info into a tutorial tip here: http://jabelarminecraft.blogspot.com/p/minecraft-forge-modding.html It might be out of date and looks like a bit of work, but worth looking at as a possible approach. By the way, I'm not sure an event would be a good idea because I think there are many packets per tick and so would be firing continuously and cause performance problems.
×
×
  • Create New...

Important Information

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