Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. I think that is an acceptable way to do it. What exactly are you worried about being wrong with that approach?
  2. You can do it almost anywhere you have the world instance as long as you check whether you've already replaced it and only replace it if the BiomeProvider instance isn't an instanceof your custom one. It shouldn't be that much of a performance hit even if you check it unnecessarily but I think you could just check whenever a chunk is generated like the biome event I already mentioned above. I think the only issue with this whole approach is that if another mod replaces the BiomeProvider then you're going to clobber theirs. But in modding there is nothing really preventing mods from clobbering other mods even when using event handling, so you just need to work with other mod authors if you come across an incompatibility. If you just wanted to add your biomes in addition to the vanilla ones then you can just use the registries. And if you're trying to simply tweak the vanilla ones then there are plenty of events for that. But for a holistic replacement you do want full control of the BiomeProvider instance.
  3. Basically this process is called "data fixing". So as Draco18s mentions you can intercept an event that makes sense -- like loading problem or possibly even earlier and "fix" the data by converting it. You'll notice that vanilla has to do that when they update save formats and such and you'll seed data fixer methods and classes occasionally in the code.
  4. I think you can use events to accomplish a similar effect -- not changing the actual biome but intercepting all the biome-related behavior to match your biome. For example, you can handle the ChunkGeneratorEvent.ReplaceBiomeBlocks to place your own blocks. However, all the various biome events are more about tweaking the vanilla biomes not replacing them. For example, they will still be called the same thing. I thought I saw a pull request one time where you could intercept the biome provider more fundamentally, but I can't seem to find that event. So I think the easiest way is to use reflection to change the protected biomeProvider field in the WorldProvider to point to an instance of your own custom BiomeProvider which could copy or extend the vanilla code and decide to place your own biomes instead of the vanilla where you want to. That should cause proper replacement and should cover all the places where the biome is checked (since biome is used for a lot of things including generation but also things like coloring the grass and such). Alternatively, maybe someone knows of a way that the new versions of the registries can simply replace the vanilla registered biomes.
  5. Regarding the "pull request" you can start by just filing an "issue" against the MinecraftForge project on GitHub. The "pull request" is where you actually offer a solution, but honestly it can be a bit tricky to set up properly to contribute to Forge (because Forge is actually a set of patches and because other people are modifying patches as well at the same time you're trying to contribute). However, it is really good if people are able to contribute because ultimately Forge is a community open source project. So I actually responded to someone who had posted this as an issue previously. See https://github.com/MinecraftForge/MinecraftForge/issues/4485 In that I looked at the code and here is I summarized the functionality then: Definitely I think the logic could be clearer, but I think the idea is that you can prevent despawning with the event easily because every 32 ticks you get a chance to reset the idleTimer to 0 whereas if you let it get to 600 then there is a chance that closer entities might be despawned. Interestingly though I think the logic is that entities that are very far cannot be prevented from despawning by the event. Now, although the event cannot prevent despawning, the EntityLiving#persistenceRequired field can. That can be set with the EntityLiving#setPersistence() method. So I think that if you want to take total control of despawning you could theoretically set the persistence of any entity you're interested in and then run your own despawning algorithm in the LivingUpdateEvent. Note I do think the despawn event would be better if it was either fired in both code paths or if it was just fired once at the beginning of the method to allow denial of any sort of despawn. I suppose that the original implementers felt that maybe allowing modders to prevent despawn generally would be "dangerous" as there is a real performance impact.
  6. You've got a lot of "Potentially Dangerous alternative prefix" warnings. That usually happens when you aren't registering things properly, although in rare cases it could be possible to ignore it (I think if you try to replace vanilla recipes it can happen). In any case you should probably fix that because it looks like your things are being registered to the minecraft "mod" and not to your mod so then that would also explain why your lang file would not be used.
  7. Also, the World class has a getTotalWorldTime() method. So basically you need to handle an appropriate event like when player joins world or similar, then post a GuiScreen using the information from getTotalWorlTime(). There are already tutorials for handling events and tutorials for creating GUIs, so try what you can and if you're still having trouble post your code.
  8. This problem is common on entity and tile entity creation where you might want to make sure the client-side is fully instantiated and initialized before doing something. As mentioned there are some ways to do that already (like entities have spawn data mechanism). But I admit sometimes I just send a delayed packet. It is really easy to do it, just create a boolean field in your tile entity called something like initPacketSent and init that to false. Then in your update method that runs every tick, just check if it is false and if so send the packet and set to true. This should delay the packet until the first time the update method is run which is usually the tick after creation and usually sufficient delay. If you want to delay more and really be sure then instead of a boolean just use a int value (like 5 for five ticks) and count down in your update method.
  9. I'm not sure that is quite correct. There are PotionEffect, PotionType and Potion classes. Both PotionType and Potion can be registered but not PotionEffect (as far as I know). Background It's a bit confusing because like a lot of things in the Minecraft code there is a duplication of some information across those classes. But looking at the fields and methods each class gives better idea of what each is for: Potion just has a bit of information in it but includes the attribute map, some registry stuff, and some booleans like "isBadEffect". The registry contains the instances from the MobEffects class. These instances represent things like "regengeration" but not a specific level of regeneration. But an important thing about Potion class is it has the methods performEffect(), affectEntity() and isReady() which I think need to be overridden. PotionEffect actually has a single Potion associated with it, but has some key things like the duration, amplifier, whether it is a splash type, whether to show particles, etc. PotionType contains a list of (possibly multiple) PotionEffects. The registry is for specific variants of the PotionEffects. So for example, there is both "regeneration" and "long_regeneration". Anyway, my point is that @Nikedemos says he doesn't want his effect to show up as an actual potion in the creative inventory. I'm not certain but I would guess that the PotionType registry will result in it showing up in the creative inventory. Summary Putting it all together I believe you want to create a custom Potion class that overrides the performEffect(), affectEntity() and isReady() methods. You want to register this. Then you want to create a PotionEffect class that is associated with that Potion. There is no registry for this as they are not singleton instances, instead you will create an instance each time you want to apply it. So basically, the Potion is a registered "singleton" instance and PotionEffect is the actual instance in effect (i.e. duration is tracked within this instance). To apply it you can call PotionEffect#getPotion().applyEffect(). I think you probably do not want to create a PotionType or register it, because I think that will cause a potion to show up in the creative tab. Caveat I didn't try the above, but just looked at the code and that are the things that looked like are happening.
  10. If you're updating between versions you'll often find that either the name of methods changes a bit, or the prototype for the method changes (i.e. maybe it has same name but different parameters need to be passed). Sometimes, the whole use of a method goes away replaced with another system. So what you need to do is figure this out yourself using the following steps: 1) Look in the class the method used to be in and look through all the available methods. It is often obvious which is the new method simply by the name. 2) Look at other places in the vanilla code that used to use the old method. To do this you need to load up the old version in Eclipse and look at the call hierarchy for the method. Remember some of the locations where the method was used. Then load up the new version and go to the same place in the vanilla code. You'll then see the new way of accomplishing the old thing.
  11. On your food item, in the onEaten() method just call the Entity#applyPotionEffect() method to the entity that ate it. Alternatively, you could create your own effect system by associating a custom Capability with the entity and then in the living update event check the capability and write code for whatever you want it to do.
  12. Yes. For modifying vanilla behavior you can first look for public fields and methods. For example entity AI is contained in a public list that you can modify directly. After that look at Forge events. Also some vanilla behaviour such as loot tables, achievements, recipes, models, etc., is now defined by JSON asset files.. If those aren't sufficient then look at java reflection to access otherwise private fields and methods.
  13. I usually send a packet explicitly to force the update to the client. This is because the order you do things to create the packet then add the NBT might miss the automatic update packets. For example, I think if you create an Item and add the NBT and then put it in a slot you will probably be automatically updated, but if you take an item already in a slot and add the NBT then probably not. You can use a vanilla packet, but the packet you use depends on where the item is currently residing. For example, if it is in a GUI then I think you would send an SPacketWindowItems packet. If it is is some of the player's equipment (worn armor or something in either hand) then you would send an SPacketEntityEquipment packet and if it is in the hotbar then use SPacketHeldItemChanged. Now, I think it is supposed to automatically update in most/many cases but personally I've found sending an explicit packet solves these sorts of things sometimes. Other than that, I would say just trace the execution including any packets sent, looking at the payload involved to see if the information you're expecting is there.
  14. It might be due to differences in path finding. Maybe the bounding box of your version is colliding or something. In any case, you should trace the execution to see where it's trying to get to when it is wandering or eating.
  15. This is a Java thing about modifying certain types of collections (like List) while iterating through it. You need to use a proper iterator and safe methods instead of a for loop. See discussion here: https://stackoverflow.com/questions/15384486/java-concurrent-modification-exception-error
  16. While the @Config system is quite convenient, I still prefer the previous system. It works fine. I've recently been playing around with making even more complex config editing GUIs, like for example I have a mod where you can change the color of enchantment glints and so I have it so you can enter the number in hex and it will display a preview even though the actual value being stored is an int type. Basically I like having the full control. I suppose it is possible to get to same level with @Config but since I already have it all working why fix what ain't broke?
  17. This is a classic issue that people making logs run into. Because logs have orientation it uses up some precious bits of meta data. People often try to be clever and combine all their variants them realize you need to break them up again. That is why vanilla has 2 log blocks, 2 leaves blocks, etc. Note also that 1.13.x is moving even farther away by making every variant a separate block. This is called "the flattening".
  18. Well, your blockstate file has to both (a) handle all the states (b) point to models that exist. Neither is true in your code. The vanilla blockstate JSON is: { "multipart": [ { "when": {"north": false, "east": false, "south": false, "west": false, "up": false}, "apply": [ { "model": "fire_floor0" }, { "model": "fire_floor1" } ] }, { "when": {"OR": [{"north": true}, {"north": false, "east": false, "south": false, "west": false, "up": false}]}, "apply": [ { "model": "fire_side0" }, { "model": "fire_side1" }, { "model": "fire_side_alt0" }, { "model": "fire_side_alt1" } ] }, { "when": {"OR": [{"east": true}, {"north": false, "east": false, "south": false, "west": false, "up": false}]}, "apply": [ { "model": "fire_side0", "y": 90 }, { "model": "fire_side1", "y": 90 }, { "model": "fire_side_alt0", "y": 90 }, { "model": "fire_side_alt1", "y": 90 } ] }, { "when": {"OR": [{"south": true}, {"north": false, "east": false, "south": false, "west": false, "up": false}]}, "apply": [ { "model": "fire_side0", "y": 180 }, { "model": "fire_side1", "y": 180 }, { "model": "fire_side_alt0", "y": 180 }, { "model": "fire_side_alt1", "y": 180 } ] }, { "when": {"OR": [{"west": true}, {"north": false, "east": false, "south": false, "west": false, "up": false}]}, "apply": [ { "model": "fire_side0", "y": 270 }, { "model": "fire_side1", "y": 270 }, { "model": "fire_side_alt0", "y": 270 }, { "model": "fire_side_alt1", "y": 270 } ] }, { "when": {"up": true}, "apply": [ { "model": "fire_up0" }, { "model": "fire_up1" }, { "model": "fire_up_alt0" }, { "model": "fire_up_alt1" } ] } ] } So you can firstly see that there is no model that is just called "fire". Furthermore, there are a number of states that need to be handled. By the way, your console should have warnings in it telling you what is missing (i.e. what states it needs handled).
  19. Okay, yeah it is a bit confusing but I looked through the call hierarchy and here is what is happening. The setCloudRenderer() method is a Forge hook. If no renderer is set by a mod (vanilla never calls this method) then it is null. Then later in FMLClientHandler the renderCloud() method checks for null and if it is null then it creates a new CloudRenderer class. If it is not null then it will use the IRenderHandler class you gave it in setCloudRenderer(). In both cases, it calls a render() method but technically as you noted these are different classes that don't share a type hierarchy. In other words, for mods it will call an IRenderHandler.render() and for vanilla it calls a CloudRenderer.render() function. This means that you cannot just instantiate, copy or extend CloudRenderer class for setCloudRenderer. Instead you need to make your own similar implementation but in a class that implements IRenderHandler. So I think (didn't try it myself) you should just go ahead and create a class that implements IRenderHandler but provides a render() function that copies the functionality of CloudRenderer.render(). Since the cloud rendering code is a bit complicated, I would probably do this by "wrapping" a CloudRenderer instance in an IRenderHandler implementation. So like this: 1) create a custom CloudRenderer class called something like CloudRendererCustom that extends CloudRenderer. You would override the render() method to make any changes you wanted to the way clouds look. 2) create an IRenderHandler implementation called something like CloudRenderHandler. The implementation would do two things: (a) create an instance of a CloudRendererCustom from Step #1, and (b) it would implement a render() function that simply calls the render() function of that CloudRendererCustom instance. 3) call the setCloudRenderer() method on the WorldProvider at the time the world is created, passing an instance of CloudRenderHandler from Step #2. Hope that makes sense. You're just making an IRender implementation that calls the render method of a custom CloudRenderer extended class.
  20. So it is possible to replace most vanilla behavior. To do so you can consider these possible approaches, in this order: 1) Use public scope fields and methods directly. For example, entities AI are contained in lists that have public access scope. So you can directly clear them, add to them, etc. Since Minecraft vanilla codes is not properly encapsulated, the scope is pretty random. Some classes are locked down tight with private access, but luckily it is very common to have public stuff. 2) Use JSON asset mechanisms. More and more logic in the game is now being represented in the JSON files. For example, recipes, achievements, and so forth. So you can pretty much just make a resource pack and change a lot of behavior. 3) Use Forge events. Most common modding problems already have a Forge event "hook" which allows you to intercept and even replace the vanilla behavior. These exist for all sorts of things from entity updates, rendering, world generation, and so forth. 4) Use Java reflection. For those things that are not public scope, Java still allows you to override the scope and access them. So for example you can do things like replace the MouseHelper field in the Minecraft class using reflection. The stuff you mentioned like clouds and weather can be done with combination of the above techniques.
  21. A null value can be valid but if you're getting an actual null error then you're usually doing something wrong in your code. For example, you've mentioned reading a config file and getting a null value. Well, first of all your file parsing should handle the case of non-exiting keys/value without really going null but if it does go null then just check for null value before trying to use it. In other words, a null pointer exception happens when you USE the null value, so you can always check for null before the possible use of it.
  22. To expand on Draco18s' answer, each resource location has a "domain" and a "path". The "domain" is basically the mod id, and in the case of Minecraft vanilla stuff the domain is "minecraft". So you can access resources in vanilla asset folders by using a resource location that points to "minecraft" domain.
  23. As diesieben07 is pointing out, performance is key for such an implementation. You need to understand the performance implications of the various collections and the iterations thereof. One thing that might help performance -- I think you probably only need to store information on blocks that have been interacted with. So potentially your map could be a lot smaller than containing all blockpos positions in the chunk, with the assumption that any block not in the map is full health.
  24. Just want to clarify the concept a bit. The vanilla source is "obfuscated" meaning that it is valid Java code but isn't really human-readable, mostly because all the fields and methods have names that don't mean anything (to humans). So as part of MCP there is a system of mapping human-friendly names to the actual names. This mapping is basically crowd-sourced -- up to the community to submit suggestions. Note that sometimes the suggestions aren't exactly right (I've seen cases of misnamed methods), and also sometimes the methods get adjusted over time based on trying to improve naming consistency Since the mapping is often getting updated, it is important for your build.gradle to point to a fairly recent version. I recommend updating every week, especially in the early days of a new version when it is probably changing frequently. In terms of whether it is "safe" to build a mod using an outdated mapping, it is because the friendly mappings are just to aid developers and the actual names are the correct ones for associating with vanilla. Note that if you use Java reflection, you need to use a class called ReflectionHelper because of the mapping. In ReflectionHelper methods you need to specify both the mapped and original names. The mappings are maintained by MCPBot which you can use to find mappings, download CSV spreadsheets with latest listings, and submit suggestions for new ones. For 1.12.2 I would say that the mapping process is essentially "finished". When 1.13.x comes around though you'll get to observe a period where there are lots of unmapped ones that get better. Each time you update the mappings there is a chance that your code will start throwing errors due to the change. You simply need to figure out what the new name is and correct your code -- a bit of a pain sometimes but unavoidable.
  25. Yeah, that is what I was going to respond and say -- logically the carried entity is "riding" the flying entity.
×
×
  • Create New...

Important Information

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