Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. This is modding so we are trying to extend an enum after it is already defined in code we may not have scope over. This means that EnumHelper is using Reflection tricks to get the effect, but it also means that the "name" of the enum is actually not really the actual underlying type of the enum. It is better than nothing, but I suppose it probably does allow apparent duplicates. However, that would certainly be an error. I think they would have to be treated as the same thing. Think about it, if someone extends a CreatureType enum with a duplicate name and then assigns that CreatureType to an entity it would of course assign it to the first one -- in other words, even if you can create duplicate entry I don't think it would ever be actually assigned to anything. That could cause a bug for any mod that did that, but shouldn't be a concern for you.
  2. There is actually a LootTableLoadEvent you should use instead. Basically you can check for whether it is the dragon loot table loading and then replace it. See a tutorial here: https://tutorials.darkhax.net/tutorials/loot_tables/ Note that recently the event has added the ability to get the LootTableManager instance as well which gives you ability to access more powerful methods.
  3. I don't think you're really thinking this through. You're trying to avoid a dependency but then want to do things that depend on the other mod. But if you insiste, what you need to do is to encapsulate the proxy interface such that the method prototypes work even when the other mod isn't loaded. That means the methods cannot return a value that is specifically of the other mod's type, and cannot take parameters that are specifically of the other mod's type. However, the other mod's classes should have parents that may be common. Like if they have an EntityVampire that extends EntityMob, then you can just type the return value as EntityMob. But note that if you want to further act on it as an EntityVampire then you'll need proxied methods for that too like have a method called setVampireCoffin(EntityMob mobIn, BlockPos posIn) and then in your proxy you'd check if it is an instanceof EntityVampire and act accordingly. In other words, you'll need to encapsulate everything you want to do with the other mods stuff with generic method prototypes that re-cast back to specific types according to whether the other mod is loaded.
  4. Most people try to get to "cute" with their registration code but you really don't need all of that. The problem is that the order of registration needs to be controlled but you also usually want static fields for the instances and it is difficult to control their initialization. So a lot of people then end up with null problems just like this poster is having. So the most accepted practice is to construct the instance when registering and then inject the reference to the instance back to your field with the @ObjectHolder annotation system. If you do that, you will mostly be okay because the events are fired in a useful order and you'll always have a non-null instance registered but still get the benefit of having a field to reference the singleton directly later. As in all coding, there are many ways to do things, but some are more prone to mistakes. In my experience the "self-registering" approach loses some of the control over the order of how things happen and in general simplicity is less error-prone.
  5. you made a typo in your loop. when you cut and pasted you left the second limit as "i" in all the loops, when it should be "j" and "k".
  6. It is pretty hard to debug this by staring at code, especially since you're not showing all of it. For example, your BlockBase constructor does set the registry name but you don't show the Sapphire_Block code so it is not clear that you actually extended that class, or properly passed the string along to the super constructor. NOTE: It is not considered good programming style to name classes with underscores. It should be SapphireBlock, not Sapphire_Block. Additionally, you construct the instance in your init() method, but it isn't clear where you call that so as far as we know that instance could still be null. Basically, you're not giving us all your code and it is the EXACT order of things that matters for this bug. Anyway, my point is still that it isn't fair to have a bunch of people just reading your code when you can debug this easily yourself. Just keep adding print statements until you understand everything that is happening. For example, in your second print statement why don't you print out some useful data like the contents of the registry name. Assuming it is null, then work backwards to figure out why it is null. For example, put a print statement in your BlockBase constructor that prints out the registry name, then check if that is getting called before you try to register it. And so forth.
  7. What have you done to debug it? It should be easy to quickly see what is wrong if you just observe the execution. I personally like to add print statements throughout the code so I can watch (and learn) about the execution in real time. For example, if you put print statements at the beginning of each of your methods then you can confirm they are being called in the correct order. And if you put a print statement right before your error line you can print out the values of what you're trying to pass to the method and you should see that they are in fact null. Then you simply trace backwards until you find the first place it isn't doing what you expect. This is how professionals debug -- by "tracing" the execution. Not just staring at the code or trying random changes. Since computers are logical, just watching the execution you can always find where it starts to go wrong. Basically for this problem, it is obvious what the error actually is -- so something is either wrong with your order of operations, or else you may have created multiple instances and getting them confused with each other (i.e. one has registry name set and one doesn't). To be honest I think your instances are mixed up as you're not using the object holder annotation so you need to be careful about how you order and reference your instances.
  8. EDIT: Nevermind, I corrected it directly in post above.
  9. There is supposed to be a mechanism called a substitution alias that does this for you, but I've never got that to work. For a while after 1.10.2 substitution was supposedly working but I haven't tried it yet and probably not working again. You can as you mentioned, change generation in your own custom dimension, then you can simply tell your ChunkProvider to generate your own Block instead of stone. But what if you want to change generated blocks in other/vanilla dimensions? Well, here's a way. However, if you look at ChunkEvent.Load event you'll find that it is called not just upon loading but also immediately after chunk generation. So it is the best place to hook into. Note that this method should be put into a handler class that is registered to the regular EVENT_BUS. (See my tutorial on events for more information on event handling.) So here is an example: public static Block fromBlock = Blocks.GRASS; // change this to suit your need public static Block toBlock = Blocks.SLIME_BLOCK; // change this to suit your need @SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true) public static void onEvent(ChunkEvent.Load event) { Chunk theChunk = event.getChunk(); // replace all blocks of a type with another block type for (int x = 0; x < 16; ++x) { for (int z = 0; z < 16; ++z) { for (int y = 0; y < theChunk.getHeightValue(x, z)+1; ++y) { if (theChunk.getBlockState(x, y, z).getBlock() == fromBlock) { theChunk.setBlockState(new BlockPos(x, y, z), toBlock.getDefaultState()); } } } } theChunk.markDirty(); } Note: It is possible to further check for the metadata of the block being replaced, and also to set the metadata of the block being replaced. Note: This will only replace generated blocks. If you really want to replace a block completely in the game you need to also substitute it in the creative menus, possibly intercept any block placement, and if there are recipes that output the block you'll need to replace those. Tip: Depending on what you want to replace you may want to check different Y-values. Since I was replacing a block normally found on the surface I only looked 20 blocks below the top block. I didn't just look at the top block because in cases of floating islands and overhanging cliffs there were cases where the grass block was not technically the top block. Warning: If you don't call the markDirty() method, then each time you reload the chunk it will have to replace all the blocks again. It will still work, but is a waste of performance.
  10. Firstly your model for the block must use the tintindex and set it to non-negative value. You'll see in the grass.json that the tintindex is set to 0. Next you need to create a class the implements IBlockColor. In that class you'll implement a method for the color multiplier (you can base this on biome, but can also use other things). Lastly you'll need to register blocks to your IBlockColor class in your ClientProxy's init loading handling method using Minecraft.getMinecraft().getBlockColors().registerBlockColorHandler() method. I have an example of my IBlockColor implementation: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/init/ModBlockColors.java
  11. Sorry but you just have to work it out. Based on how your model is built up and animates you'll have to do all the trigonometry involved. It might be easiest to actually draw it out on paper and figure it out. But basically you need to start from the body position and depending on the rotation figure out where the neck attaches, and then based on the neck rotation figure out where the head attaches, and then based on the head rotation figure out where the mouth would be.
  12. I guess it is a bit complicated. I have a tutorial here that might help. http://jabelarminecraft.blogspot.com/p/minecraft-modding-custom-fluids.html?m=1
  13. There is a very good reason they did not allow rotation or irregular bounding boxes. If you allow rotation then every pathfinding and collision detection method would require many, many times more processing there would be lots of trigonometry and you'd have to know the relative position to understand the perspective when trying to interact with it and so on) and it would be a performance problem. Basically this is Minecraft and that means "blocky". So just like Minecraft's own large multipart entities using multiple hitboxes is the best way, even though I understand it will be annoying to program and also won't give a perfect effect. I'm not saying it is impossible to change but it would require re-writing lots of somewhat advanced code. You would need to re-write the ray-tracing code to look for your bus entity, you would need custom collision checking for your bus entity, and you would need custom path-finding. Each of these mainly involves just a lot of trigonometry.
  14. It depends on what you want. If there are a lot of dogs in world you probably shouldn't make them all persistent. Rather only tamed one. So If you have a method for taming then I would set the persistence there. The persistenceRequired field is private and the enablePersistence() only sets it to true -- there is no way without Reflection to clear it again. But it is probably okay to leave dogs persistent if they've ever been tamed as that shouldn't be that many and certainly would be less than all the dogs in the world. But if you really wanted to clear it again you can use reflection or alternatively you can create your own field and override the despawn method to use that instead. But I would start by just using enablePersistence() whenever you do the taming.
  15. Did you try making the entities persistent with the setPersistent() method when they are tamed? If you look at EntityLiving there are some related fields/methods: - canDespawn() which defaults to true - despawnEntity() which looks at a couple things including distance, the canDespawn() and also - isPersistenceRequired which can be set with the enablePersistence() method, and this also is returned for the isNoDespawnRequired() method. If you look at the despawnEntity() method and trace the logic, you'll see that simply setting the persistence with enablePersistence() method will prevent despawning. That should help a fair bit because entities despawn even when chunks are loaded without persistence. Now I don't think persistence really helps if the chunk is actually unloaded. But it might so maybe Draco18s or diesieben07 know more details about that. You could force the entities to stay loaded by handling the chunk unload event and directly manipulating the world unloadedEntitiesList, but I think that would be a problem to have entities loaded without the chunk. But again others might know better. I would start by ensuring your entities are persistent. If there is still an issue, then what I would do is create a capability for the player that contains a List of the EntityDogs that have been tamed. I think you would actually just keep some information about the dogs and when you want to whistle them you would find the ones in the world and bring them, and then all the ones that are missing you'd have to re-construct. But I'm guessing at this point.
  16. Are the dogs in the list, or they are not even in the list? You should use print statements to print out the list to see what is in it.
  17. You can't, depth and width have to be the same. This is because, for performance reasons things like path finding and collision checking need to be simplified. For the same reason the hitbox doesn't rotate even if the entity model does. The only way to make an irregular hitbox is to actually make multiple hit boxes. There are many ways to do that, but one way is to make invisible entities that track along with your entity and have hitboxes, like multipart entities like dragon do.
  18. What do you mean it "would stop working"? Is there an error? If you mean that some of the dogs have disappeared due to being unloaded, that is a separate problem. As I already mentioned you need to set persistence on your tamed dogs if you want them to not be unloaded.
  19. Here's how I suggest going about it. This is how I figure things out. So your original question was how to "scan" the entities in the world. So I would go to the World class and look at what fields and methods are available, literally scroll through them to see if anything looks interesting. In Eclipse you can use the Type Hierarchy for the World class (and generally a good idea to enable all inherited stuff with little button at top of the list of methods). If you scroll through that you will see there is a field called loadedEntityList. If you right click and pick "Declaration" you can go to where it is declared in the code. There you will see that it is public scope meaning that it is available for you to use in your classes -- cool. Sometimes in modding the names of the fields and methods don't match what you expect, so it is a good idea to confirm this is what you want by looking at the Call Hierarchy for that field. If you do you'll see how it is used by Minecraft and in this case it looks like a useful thing. Now the type of field is a simple Java List<Entity>. So basically you can do everything you would want to do with a List. If you don't know Java well you should look it up, but Lists can be iterated in a loop so you can just loop through and find all the entries that are instanceof EntityDog (or whatever you're looking for) and so on. That is how you "scan the entire world for a specific entity"...
  20. This brings up another issue of entity persistence as well. In regular Minecraft, entities can literally "despawn" if they are far away for long enough and I think that is probably forced during chunk unloads. This works okay for general animals (who really cares if a sheep is still there later) but for some things like structure-generated mobs (like in mansions) and maybe things like tamed animals you might want to make sure they are persistent. I prefer the idea of using a list to keep track of your tamed animals, rather than scanning all entities in the world to see if they are the right type and then further checking to see if they are tamed, because that is very inefficient -- less than 0.1% of entities in the world are likely to be tamed at any given time. However, you can do it by scanning if you want as the world has a list of loaded entities which you can loop through (or use contains() type methods if the data structure is amenable).
  21. It is easy. Just have a field for the dog that keeps track of which attack type should be the current option and then in each AI in the shouldExecute() method just test to see if the attack type matches.
  22. Why would you have to scan for this? Why not have player simply have extended data that keeps track of all dogs that the player has trained?
  23. Yes, send the packet for the key binding associated to the right click.
  24. I was going to mention a similar thing -- I think AppData folder might have permissions issues in some cases. The first two cases are still possible -- the smallest typo can cause a file to not be found. For example, I'm assuming your mod id is actually "wire" all lower cases and stuff. I usually try to avoid typos by only entering the text once -- for example, in your model registration instead of "wire:newingot.json" I would usually code it as ingotInstance.getRegistryName(). In my example of course you would replace ingotInstance with the injected instance from your item registration.
  25. Your modding workspace is set up in your roaming AppData folder? So that's where your project file is? It seems like you're putting your JSON in your regular minecraft location not your project asset location... Can you show screenshot of Eclipse's package explorer tree showing the resource package location?
×
×
  • Create New...

Important Information

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