Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. Minecraft is Java so you can use standard Java methods for manipulating (reading/writing/changing) files. If you want to use the built-in configuration system see: https://mcforge.readthedocs.io/en/latest/config/annotations/
  2. In Minecraft modding, metadata is specifically a very condensed (using only 4-bits of information) way of coding information about a block at a position in the world. The reason why it is so condensed is because the number of block positions in a Minecraft world is very large -- there are 65 thousand positions in a single chunk! So to save memory, disk space and networking bandwidth they restrict the information for most blocks to 4-bits. 4-bits allows for 16 states (0 to 15). That is enough to provide some functional variation. For example, you can have 16 different colors of a block that is otherwise mostly the same. Or you can code the orientation of a log block. And so forth. However, sometimes you need more information associated with a block. For the example in the thread above, if you want to store an energy level that can go to 100 then you probably need to use a "tile entity". A tile entity can both store more information (using NBT format to and from disk) and can also process more complex logic. They need to be used sparingly though because they can tax performance -- for example you probably wouldn't be able to fill a chunk with furnaces that were all cooking at the same time without causing lag. In early days of modding, modders would "think" directly in terms of metadata codes and NBT data. However, in modern times those are mostly hidden implementations and instead you work with Properties and IBlockStates, and for more complex blocks with tile entities you can use Capabilities. So really your question should not be "how and when do I use metadata" but rather "what is best way to store this sort of information about a block"? If it is very simple information that can be stored within 16 values you can use properties and block states, otherwise you need to use tile entities (and likely capabilities attached to them).
  3. The API approach mentioned above is logically sound, but practically it is more work than just doing the porting directly. Firstly, this all assumes that you will make a fair number of mods to be worth considering such generalizing. But if you do make lots of mods it is likely that each of your mods touches fairly different aspects of the game. Like one might add dimensions, another entities, another items and so forth. Sure there might be some cross-useful stuff, but generally modders end up making either a bunch of targeted mods or one comprehensive mod. So then making an abstraction layer beyond Forge itself doesn't make sense -- you'll be trying to generalize something that you only use a couple times and going through a number of hoops to accomplish even that. I also struggled for a while trying to figure out the best way to support porting multiple mods, because frankly it is a lot of work. At one point I thought that even branching my code would be useful -- like start a mod in 1.7.10 then branch for each additional version up to 1.12.2 or whatever. However, I found that the code changes so much between versions that even that was a waste of time! Honestly, with modding you have both the underlying Minecraft vanilla code as well as the Forge code both undergoing significant overhauls for each version. Heck even the upcoming 1.13 is going to be a huge rewrite! The best thing in the end is just to organize your code in a useful and familiar way and then just put in the work for the porting. One last tip: you need to pick your battles. For example, some things like Entities haven't really changed much through the various versions. But things like blocks have changed a lot with properties, blockstates, JSON models, and registry events all changing and now they are going to be "flattened"! So if you have a mod that focuses on Entities I would highly recommend trying to port it to as many versions as possible. But if you have a mod that focuses on Blocks I would recommend just concentrating on one or two suitable versions to support.
  4. You can intercept any Gui opening by handling the GuiOpenEvent. You can check if the one that is opening in the event is the inventory and you can prevent it from opening, or replace it with your own. Even it isn't your original idea, it is great when modders adapt their ideas to make them easier to implement.
  5. So firstly there are two types of GUI in Minecraft. There are those that directly extend the Gui class and then there are those that extend the GuiScreen class. As far as I know all the ones that allow movement (such as the main HUD, or the debug info gui) extend the Gui class not the GuiScreen class. Things like the GuiContainer used by inventories extend GuiScreen. The main idea with the GuiScreen class is that it intercepts the mouse and keyboard input and does Gui actions (like running code when a button is clicked). I think it might be very hard to do what you're wanting to do. In particular there is the following code in the Minecraft#runTick() method which would be a problem: if (this.currentScreen == null || this.currentScreen.allowUserInput) { this.profiler.endStartSection("mouse"); this.runTickMouse(); if (this.leftClickCounter > 0) { --this.leftClickCounter; } this.profiler.endStartSection("keyboard"); this.runTickKeyboard(); } Now, a regular Gui (like main HUD) is not a screen so it would return currentScreen as null (and therefore update the input). But a GuiScreen like an inventory is going to intercept the input. It might still be possible though. I think there are two approaches: 1) Create a Gui that tries to recreate what an inventory should look like. So for example, if you just want to show something that looks like an inventory while still moving you would just need to draw the inventory stuff but do it in a Gui, not the regular GuiScreen. 2) Create a Gui screen that tries to send the mouse and keyboard info it is getting back to the main game. There is a handleInput() method that calls handleMouse() and handleKeyboard(). You'd have to look at those methods to see if you can push the information back to the main game. Anyway, the point is that the inventory type GUIs are intended to intercept the user input and it might be tricky to work around that. What exactly are you trying to do?
  6. Well I'm not sure how well it would perform, but I think you can scan for them. It is even easier if you don't have to find absolutely all of them, but just want to find ones that for example are mostly round. What you could do is have a loop through x, z that jumps in amounts that are half of the size of smallest island you want to detect. At that location you would loop down from the sky (or some decent height) until you find a block (if you find nothing then jump to the next location) and if you find one you'd run a method that checks the area around it to find the min and max x and z that are connected (again if you're not concerned with finding every weird shape you can simplify the concept of "connected"). If the span (difference of max and min) in both the x and y are less than some value then you would declare that you've found a "small" floating island. It is admittedly slightly complicated and requires some nested loops. But I think it is generally possible to find islands that are somewhat regular in shape.
  7. I don't think it has changed much for several versions. Most tutorials should work or be close enough to work for 1.10.2. There are pretty much two types of GUI, ones with a container attached (i.e. have slots like an inventory or crafting table) and basic GUI which just display some information and interact with buttons. In either case, you basically just make your own class that extends GuiScreen (or a relevant subclass that is similar to what you want) and just open it for the player when it makes sense (interacting with a block, or pressing a key bind or whatever). But it really depends on what you're trying to do.
  8. Okay, that looks like it might work (I didn't check the exact code, but the general idea looks like it should work.) So your "armor class" is your own class that extends ItemArmor? And you've registered that item (using the RegistryEvent<Item>)?
  9. For something like checking whether player is standing on a block, you can handle the PlayerTickEvent and just check the block under the Player at that time. Basically there are a number of "tick" events which are useful for applying behavior that may not have an event. These give you a chance every tick (1/20 second) to run whatever code you want (like scanning inventory for specific items, scanning surrounding for certain terrain elements, and similar).
  10. Yes, it is a lot easier if you already know how to program because then the code "explains itself". Anyway, what you're asking probably has many tutorials. Custom armor is a common thing to do so I think there should be good tutorials already available. Possibly even in your own language. Did you Google search for tutorials on "custom armor".
  11. Just to emphasize that the object holder instantiation works (i.e. the blocks are not null at time I try to register item block models), I put a debug print in my registerItemBlocks() method. The method is now: @SideOnly(Side.CLIENT) public static void registerItemBlockModel(ItemBlock parBlock, int parMetaData) { // // DEBUG System.out.println("Registering item block model for" + ": " + parBlock.getRegistryName()); ModelLoader.setCustomModelResourceLocation(parBlock, parMetaData, new ModelResourceLocation(parBlock.getRegistryName(), "inventory")); } And the output is: [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_15 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_14 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_13 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_12 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_11 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_9 [11:49:06] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.movinglightsource.registries.BlockRegistry:registerItemBlockModel:191]: Registering item block model for: movinglightsource:movinglightsource_7 In other words, when it goes to register the item block model, the actual block must exist (non null) since it returns a registry name (which is also correct). It doesn't try to register any custom model for a "null:inventory" resource location...
  12. They don't need to be -- the whole class is. You only need annotation on the field if the Java name doesn't match the registry name. For item blocks I'm appending "itemblock_" to the Java field names so do need the @ObjectHolder annotation directly on each field.
  13. I don't see how this is possible seeing as how none of your Block fields are instantiated . You need to study the concept of @ObjectHolder annotation. All those null fields are populated in several passes between the registry events. If you watch the console in your mods you'll see a bunch of FML messages saying "Applying holder lookups" then "Holder lookups applied". Basically what happens is that after the block registry event, your code is scanned for @ObjectHolder annotations. Wherever the type and name (i.e. the actual field name in Java, no string needed) match, the null field will get populated FROM the registry. Then the process is repeated for items after they are registered.
  14. Maybe it is *additionally* registering something with a null registry name, but it is weird that the error seems to know the registry names. Like why would it basically say "I'm seeing this null registry name for all these items with this list of registry names"?
  15. All the item blocks seem to be registered. If, in the init stage, I dump all the registered items with: System.out.println("All registered items = "+ForgeRegistries.ITEMS.getEntries()); The console output lists all my items: movinglightsource:movinglightsource=net.minecraft.item.ItemBlock@12919b7b, movinglightsource:movinglightsource_15=net.minecraft.item.ItemBlock@4901ff51, movinglightsource:movinglightsource_14=net.minecraft.item.ItemBlock@3033e54c, movinglightsource:movinglightsource_13=net.minecraft.item.ItemBlock@e31d9c2, movinglightsource:movinglightsource_12=net.minecraft.item.ItemBlock@10e5c13c, movinglightsource:movinglightsource_11=net.minecraft.item.ItemBlock@56584f06, movinglightsource:movinglightsource_9=net.minecraft.item.ItemBlock@796ed904, movinglightsource:movinglightsource_7=net.minecraft.item.ItemBlock@7991e022 So there does appear to be registered item with corresponding expected registry name for all my blocks.
  16. You need to follow the code from there. There is obviously a method there that gets the model and is even called getArmorModelHook(). That method returns a ModelBiped so you could just override to return your own custom model right there, but more correct to continue as VoidWalker mentions -- this method ends up calling the Item#getArmorModel() method. It is all related. There is a layer in the player model for armor. Assuming you want to replace the normal armor (instead of adding to it) you need the armor layer to find your model. The class code you are already looking at shows you where it gets that model from. So follow it from there.
  17. But if you look at that line of the error message it says the error is for a list of items that it properly lists out their registry names. So it is saying the problem variant is #null/inventory for a number of items which it then lists out. I'll work on figuring this out, but just trying to see if anyone knows where best to look since JSON can fail in so many ways. I THINK the proper way is to register an ItemBlock for a Block and I think that then the item will try to match models for each blockstate of the associated block. In my case though I don't have any custom blockstates, so it is just about the default model types (I think), which includes "inventory". I am registering the block and the item block with same registry name and I think I have the @ObjectHolder reference names matching. But of course all it takes is one typo for any of these strings to not match....
  18. If only I had thought of that! ?, but the weird thing is that it seems to know what the item is -- the item itself isn't null at least according to the error message: [09:07:05] [main/ERROR] [FML]: Exception loading model for variant movinglightsource:null#inventory for items ["movinglightsource:movinglightsource_11", "movinglightsource:movinglightsource_12", "movinglightsource:movinglightsource_13", "movinglightsource:movinglightsource_14", "movinglightsource:movinglightsource_15", "movinglightsource:movinglightsource", "movinglightsource:movinglightsource_7", "movinglightsource:movinglightsource_9"], normal location exception: So it is the item variant that seems to be null. But the weird thing is that the block (and related item block) don't have any intended variants. Obviously I have done something to make it think there are variants somehow, but my block has no Property that would create non-default variants. I know with JSON it is usually just a simple typographical error, but just looking at where to look for this error. Why would it think there is a variant "#null/inventory" based on my JSONs? I will try to trace my registry code execution to see if a null occurs there, but just seems weird as I use the same code setup a lot without this error.
  19. Note, I can get rid of the problem if I add a "null.json" file in my item models. But that obviously doesn't seem like a "healthy" way to fix the problem. Why is it looking for a null item json model?
  20. The game still works, but when I load the game I see this in the console: [09:07:01] [Sound Library Loader/INFO] [minecraft/SoundManager]: Starting up SoundSystem... [09:07:01] [Thread-5/INFO] [minecraft/SoundManager]: Initializing LWJGL OpenAL [09:07:01] [Thread-5/INFO] [minecraft/SoundManager]: (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) AL lib: (EE) DoReset: Failed to check format support: 0x88890008 AL lib: (EE) DoReset: Failed to initialize audio client: 0x88890008 Exception in thread "Thread-5" [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: org.lwjgl.openal.OpenALException: Invalid Device [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.Util.checkALCError(Util.java:55) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.ALC10.alcCreateContext(ALC10.java:251) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.AL.init(AL.java:173) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.AL.create(AL.java:143) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.AL.create(AL.java:102) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at org.lwjgl.openal.AL.create(AL.java:206) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at paulscode.sound.libraries.LibraryLWJGLOpenAL.init(LibraryLWJGLOpenAL.java:164) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at paulscode.sound.SoundSystem.CommandNewLibrary(SoundSystem.java:1576) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at paulscode.sound.SoundSystem.CommandQueue(SoundSystem.java:2572) [09:07:01] [Thread-5/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:-1]: at paulscode.sound.CommandThread.run(CommandThread.java:121) Is that a problem, or a known issue? I doubt it is anything related to my mod code as I don't muck with sound at all, and this is early in the loading process.
  21. Okay, so I have a mod that creates "invisible" tile entities that do not go onto any creative tab. I think I initially didn't make any block state variant for "inventory" but I think that gave me some errors. So I added the "inventory" to my block state and registered accordingly. However, I must have screwed something up because (although the game works) I'm getting error in the console: [09:07:05] [main/ERROR] [FML]: Exception loading model for variant movinglightsource:null#inventory for items ["movinglightsource:movinglightsource_11", "movinglightsource:movinglightsource_12", "movinglightsource:movinglightsource_13", "movinglightsource:movinglightsource_14", "movinglightsource:movinglightsource_15", "movinglightsource:movinglightsource", "movinglightsource:movinglightsource_7", "movinglightsource:movinglightsource_9"], normal location exception: net.minecraftforge.client.model.ModelLoaderRegistry$LoaderException: Exception loading model movinglightsource:item/null with loader VanillaLoader.INSTANCE, skipping The whole console log is: So the blockstate JSON is simple: { "forge_marker": 1, "variants": { "normal": { "model": "movinglightsource:movinglightsource" }, "inventory": { "model": "movinglightsource:movinglightsource" } } } And block model JSON is simple: { "textures": { "pole": "blocks/log_big_oak" }, "elements":[ { "__comment":"basically make it have no surface area so it is invisible", "from":[ 0.5, 0.5, 0.5 ], "to":[ 0.5, 0.5, 0.5 ], "faces":{ "down":{ "uv": [ 0, 0, 15, 15 ], "texture":"#pole" }, "up":{ "uv": [ 0, 0, 15, 15 ], "texture": "#pole" }, "north":{ "uv": [ 0, 0, 15, 15 ], "texture":"#pole" }, "south":{ "uv": [ 0, 0, 15, 15 ], "texture":"#pole" }, "west":{ "uv": [ 0, 0, 15, 15 ], "texture":"#pole" }, "east":{ "uv": [ 0, 0, 15, 15 ], "texture":"#pole" } } } ] } and the item model JSON is simple: { "parent": "movinglightsource:block/movinglightsource", "display": { "thirdperson": { "rotation": [ 10, -45, 170 ], "translation": [ 0, 1.5, -2.75 ], "scale": [ 0.375, 0.375, 0.375 ] } } } And here is my class that does all the registration: Summary -- what does the "null" in the "variant movinglightsource:null#inventory for items" error mean? -- what is that looking for?
  22. I'm confused. Why can't you use the already available LivingDeathEvent? I think it is fired on both sides, but if not just send a packet to the client. In any case, as mentioned you can then start a timer for how long you want it displayed on the client. I personally would just do it as a static int field in a ClientTickEvent handler. However, you can also consider making the message use an existing temporary GUI like a toast message. Furthermore, your GUI doesn't have to pause the game -- that is just a setting in the GUI. Most GUIs do not actually pause the game.
  23. Wait, what are you trying to do exactly? You already can customize vanilla mobs completely. You can change all their AI, change all their attributes, change their models and textures, and fully intercept their update methods. If you want to change anything vanilla you should look for ways in this order: 1) Look for natively public methods and fields. There are really quite a lot of these. For example, all entity AI is kept in public task List fields that you can directly manipulate completely. 2) Events. There are already events for most things you would want to mod. 3) Substitutions. You can do things like handle the event when an entity joins the world and replace with your own version. You can do similar thing with blocks during chunk populate event. Some of the modern registries can be manipulated to do substitutions as well. 4) Reflection. You can literally replace comprehensive things by accessing the various singleton fields in classes like the Minecraft class. For example you can replace the mouse helper class, or replace the item renderer or the global renderer or the texture manager or the model manager or whatever. Those are "intrusive" and can cause incompatibility with other mobs, but they are possible. Anyway, mobs are particularly well covered by Forge. What are you trying to do that you think you can't?
  24. Yes, anything that general block rendering usually involves a somewhat "heavy" mod. I'm not entirely sure why Forge doesn't provide more hooks but I suspect that it is due to performance concerns. If every mod started mucking around with block rendering it would probably be a disaster.
  25. Okay, I have a bunch of ideas. Firstly, if you only want this effect when the block is being highlighted (i.e. the selection block), you can add all the rendering you want in the getSelectedBoundingBox() method of your block. This method is called while already in the middle of rendering so you can just get the Tesselator.instance() and draw anything additional. Otherwise, assuming you want this highlighted all the time, here's some more. Okay, if this is mostly a cosmetic thing I don't think you strictly need it to have states associated with it. You could potentially check for neighbors at time of rendering, but depends on what you're trying to achieve. Even on server side I would suggest it might be easier to check for neighbors when you need to rather than trying to maintain it a state. Next, regarding the "43 different states" if you just check at rendering time you can create all the overlays (i.e. one for each side) separately and on top of each other. You just have to design the graphical highlighting such that it works when drawn on top of one another. In other words, imagine having a texture that was transparent except for a yellow strip along an edge. You would use that single texture and just rotate it and render it for each neighbor. There are actually a couple different approaches that might work better than using block states with standard block models: a) Make your block a tile entity with a special renderer. In your special renderer, just check the neighbors at the time of rendering, no need to maintain a block state. b) Use Reflection to replace the BlockModelRenderer in the BlockRendererDispatcher class. It should be pretty obvious how to do (a), but for (b) here is some more details about what I'm thinking: You can get the BlockRendererDispatcher class with Minecraft.getMinecraft.getBlockRendererDispatcher() getter method and then change the private field to a custom BlockModelRenderer. The custom BlockModelRenderer would extend the vanilla one and copy most of code but in the place where it renders the layers it would then include your code for your additional stuff.
×
×
  • Create New...

Important Information

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