Jump to content

V0idWa1k3r

Members
  • Posts

    1773
  • Joined

  • Last visited

  • Days Won

    61

Everything posted by V0idWa1k3r

  1. Afaik all of the mods you've listed use multipart models for their pipes, not TESRs.
  2. First of all as the variable names suggest these are chunk positions, not block positions. You need to left-shift these by 4 to translate to block positions. Also what is up with this random.nextInt(16)? Why is it there? Why is it 16? Why is it Z only? You could just do a direct comparason of objects(world.getBiome(...) == YourBiomes.MINERAL_BIOME)
  3. The reason this is not going to work is much more simpler than the issue of not having the blockstate. When anything like a pipe for example tries to check for a fluid tank it checks the tile entity of that block. It won't(and it shouldn't) check the block itself. Capabilities are attached to the tile entity, not to a block state. So you must use a TileEntity.
  4. The name was likely changed to putColorRGB_F but you might not even need it. Have you tried without it?
  5. It is not quite as easy to reach that limit. In one of my mods I have items that can hold items that can be nested inside of other such items. Even a very big invenroty(100+) slots filled with those items each of which also holds items inside doesn't go near the packet limit. You can use CompressedStreamTools.write to write an NBTTagCompound to anything that implements a DataOutput, for example a DataOutputStream or a ByteBufOutputStream(this is the one that the game uses anyway), then get the length of that stream.
  6. You can't do this with JSON alone. You would need a custom IRecipe implementation that both accepts any item that extends ItemAxe and returns that item with it's damage increased by one in it's getRemainingItems list.
  7. I think you can use the RegistryEvent.MissingMappings event to deal with this. From that event you can get the list of mappings. Get the one that was changed and use Mapping#remap to point to the thing with the new name.
  8. This makes no sense. You've just accessed the NBTTagCompound that contains the serialized item data. Nothing about this says anything about a ByteStream. Yes, it is true. 32767 bytes. Don't have insanely large NBTTagCompounds. In pretty much all cases you won't have the tag bigger than the limit. If it is it is likely not your fault and you need to complain to whomever caused this issue.
  9. Minecraft is pretty much not thread safe. It wasn't written with thread safety in mind and as such can't be treated as if it was. This is but one of the issues you ran into. If something isn't thread safe and you are using it as if it was it is just a matter of time before you either start running into errors or some weird unintended behaviour emerges. Again: Minecraft isn't thread safe. You can't assume it is and thus you can't use it as if it was. Stop accessing not thread-safe things asynchronously, that WILL lead to issues because you can't do that. At best do what you must async and pass what you can't to the main thread to do using IThreadListener#addScheduledTask.
  10. In order to port the code given in the first example you need to understand how BufferBuilder works in the first place. Instead of Tessellator that gave a way to create vertices with predefined formats and alter their parts minecraft now has a BufferBuilder that allows you to build those vertices from scratch the way you need them. So a BufferBuilder is just a way to define vertices. Vertices are just a collection of data that is passed to the rendering pipeline. You start by specifying some property(usually position) and end with the .endVertex() call. It allows you to pack data into a vertex. You specify the vertex format when you start the drawing operation and you must use that format for all the vertices you are drawing in that pass. So for example to put position, texture and color into the vertex you would do BufferBuilder bb = ...; // Set to some value bb.begin(GL11.GL_QUADS /* Defines the amount of vertices per shape */ , DefaultVertexFormats.POSITION_TEX_COLOR); bb.pos(x, y, z).tex(u, v).color(r, g, b, a).endVertex(); ... // Define other vertices There are various formats too. The format name usually defines the way you define a vertex but if it is something obscure like BLOCK you can see it's components and their ordering in the DefaultVertexFormats class. Now as for adapting the old code. Let's look at the code at hand t.startDrawingQuads(); t.setNormal(0.0F, 0.0F, 1.0F); t.addVertexWithUV(0.0D, 0.0D, 0.0D, (double) u1, (double) v1); t.addVertexWithUV(1.0D, 0.0D, 0.0D, (double) u0, (double) v1); t.addVertexWithUV(1.0D, 1.0D, 0.0D, (double) u0, (double) v0); t.addVertexWithUV(0.0D, 1.0D, 0.0D, (double) u1, (double) v0); t.draw(); So what does this code do? It draws a quad, since it only defines 4 vertices which make a quad together. You can also easily see the data these vertices are composed of - they have a position(the first 3 variables in the addVertexWithUV method), texture coordinates(the last two variables in the addVertexWithUV method) and a normal(the setNormal method). Thus to adapt this code you need a similar format - POSITION_TEX_NORMAL is that format. Now when you know the format the rest is easy - just define the vertices using BufferBuilder with that format: BufferBuilder bb = ...; // Set to some value bb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_NORMAL); bb.pos(0, 0, 0).tex(u1, v1).normal(0, 0, 1).endVertex(); bb.pos(1, 0, 0).tex(u0, v1).normal(0, 0, 1).endVertex(); bb.pos(1, 1, 0).tex(u0, v0).normal(0, 0, 1).endVertex(); bb.pos(0, 1, 0).tex(u1, v0).normal(0, 0, 1).endVertex(); Tessellator.getInstance().draw(); And you are done. A big optimization can be made by not splitting each quad into each own pass but instead specifying all quads in one draw pass. As for the second method - I do not see an issue with it. It already uses BufferBuilder.
  11. Basically it all goes down to the initial init method class WrappersHolder { ICECProvider wrapperA; ICECProvider wrapperB; void init() { if (Loader.isModLoaded("ModA")) { wrapperA = Class.forName("AWrapperProvider").newInstance(); } if (Loader.isModLoaded("ModB")) { wrapperB = Class.forName("BWrapperProvider").newInstance(); } } } By default the fields contain a null value. The init method checks if the mod is loaded and if it is assigns a new wrapper object to that field. If the mod isn't loaded then no wrapper is assigned and the field stays null. So checking for null is then the same as checking for whether the mod is loaded or not - if it is then the field won't be null. As for the naming, well you can name the fields whatever you'd like. The instance in that line is there because these fields aren't static and thus need an instance to access them. The instance is just a field declared perhaps like this: public static WrappersHolder instance = new WrappersHolder(); It is not needed, you can instead make the fields that hold the wrappers static and then you don't need an instance to access them. Edit: as for the class loading I would imagine forge scans the packages to find either more packages to scan or .class files. It then would read those .class files as a binary stream and convert them to bytecode using the ASM library. Then it is trivial to analyze that bytecode to find an annotation. If an annotation is present then the class name/path is stored somewhere to load at a later date. The bytecode is then discarded. This way the classes are never loaded since they only exist for a short amount of time as bytecode in memory, not as actual loaded classes.
  12. I am able to launch your mod in a normal(non-dev) environment. There were a few compile errors I had to correct though and one of your classes was referencing the upper-case package. Use github integration instead of uploading files manually. Or at least the command line git client.
  13. And in the .jar file the upper-case turns into lower-case which leads to duplicate files which leads to the inability to load the duplicated class. In my local environment as soon as I dealt with the duplicated package/classes(and a few other compilation issues) I was able to boot the game just fine.
  14. Yeah, exactly my point. That's why I propose all this system in the first place and even use reflection to instantinate "dangerous" classes - to not allow loading unless I want it to happen. Those annotations are simply an indicator to the class transformer to strip the class of those methods as it is loaded via ASM. It doesn't cause class loading on it's own. As far as I am aware the only two annotations that cause class loading are @Mod and @EventBusSubscriber. My proposal relies on the init method being called at some point, preferrably at pre-init too. So what we are suggesting is essentially the same thing, I just choose to represent the mod not loaded scenario with a null instead of a dummy implementation.
  15. Why do you have 2 packages, one named airdrop, the other named Airdrop? Delete the older one if you are changing package names.
  16. That is pretty much what I am already suggesting. The wrapper factories will be null if the mod the factory provides a wrapper for isn't loaded. There is no reason to default to an empty method instead. You can simply check for null. Your approach is also valid though.
  17. Your issue is likely caused by something else somewhere else but since you are using static initializers everything gets messed up and you see this error report. One more reason to stop using static initializers. Also don't use IHasModel. It is stupid. Every item needs a model. Every single one. And nothing required for model registering is private. Also these Should be in your client proxy, not a common class. Stop using a deprecated method. Use the overload which takes a ResourceLocation. As for the actual issue - it's impossible to tell from the information you've provided. Please provide a link to your github repository so I can test it locally and trace the actual issue. Or simply stop using static initializers. In this case the acual issue will be the one you catch.
  18. By default it won't. Classes are loaded on demand. However I do not really trust this since I do not know if this is a required specification of the JVM behaviour or not. If it isn't a custom JVM provided by a third-pary may indeed load the class. If someone could link me to a specifications for this case it would be great. // In your TE for (EnumFacing side : EnumFacing.values()) { TileEntity tile = this.world.getTileEntity(this.pos.offset(side)); if (tile != null) { EnergyCapability energy = tile.getCapability(CapabilityEnergy.ENERGY, side.opposite()); // This if/else construct is very important because other mods may use a different energy API but still expose their energy capability as a forge energy one via a wrapper. In fact as far as I am aware all of them do. However in case they don't the else goes into play. if (energy != null) { energy.transferEnergyTo(...); } else { if (WrappersHolder.instance.teslaWrapper != null) { ICECProvider teslaProvider = WrappersHolder.instance.teslaWrapper; ICompatibleEnergyCapability cap = teslaProvider.createWrapper(tile, side); if (cap != null) { cap.transferEnergyTo(...); } else { ... } } } } } // The wrapper creation class TeslaWrapperProvider implements ICECProvider { // Since this class is loaded only if the mod is loaded it is completely safe to reference that mod in it. @CapabilityInject(Tesla.class) static final Capability<Tesla> TESLA_CAP = null; ICompatibleEnergyCapability createWrapper(TileEntity tile, EnumFacing side) { Tesla cap = tile.getCapability(TESLA_CAP, side); if (cap == null) { return null; } return new ICompatibleEnergyCapability(){ ... void transferEnergyTo(...) { cap.transferEnergyTo(...); } } } }
  19. In said class you can do whatever you want to do. The class would be dependent on the api provided by another mod. Don't invoke that method unless Loader.isModLoaded returns true. Then the class will not be loaded. If you really need to interact with the capability in an another class you can create a wrapper. Example scenario: // Depends on ModA class EnergyCapabilityA { int getEnergy(); void setEnergy(int i); } // Depends on ModB class EnergyCapabilityB { int getEnergy(); void addEnergy(int i); void removeEnergy(int i); } // Your generic wrapper interface, depends on nothing interface ICompatibleEnergyCapability { int getEnergy(); void addEnergy(int i); void remEnergy(int i); } // Your wrapper provider interface, depends on nothing interface ICECProvider { ICompatibleEnergyCapability createWrapper(TileEntity tile, EnumFacing side); } // A custom caster class, depends on ModA class AWrapperProvider implements ICECProvider { ICompatibleEnergyCapability createWrapper(TileEntity tile, EnumFacing side) { EnergyCapabilityA capA = tile.getCapability(A_ENERGY_CAP, side) return new ICompatibleEnergyCapability(){ int getEnergy(){ return capA.getEnergy(); } void addEnergy(int i){ capA.setEnergy(capA.getEnergy() + i); } void remEnergy(int i){ capA.setEnergy(capA.getEnergy() - i); } } } } // A custom caster class, depends on ModB class BWrapperProvider implements ICECProvider { ICompatibleEnergyCapability createWrapper(TileEntity tile, EnumFacing side) { EnergyCapabilityB capB = tile.getCapability(B_ENERGY_CAP, side) return new ICompatibleEnergyCapability(){ int getEnergy(){ return capB.getEnergy(); } void addEnergy(int i){ capB.addEnergy(i); } void remEnergy(int i){ capB.removeEnergy(i); } } } } // A class containing the wrappers, depends on nothing class WrappersHolder { ICECProvider wrapperA; ICECProvider wrapperB; void init() { if (Loader.isModLoaded("ModA")) { wrapperA = Class.forName("AWrapperProvider").newInstance(); } if (Loader.isModLoaded("ModB")) { wrapperB = Class.forName("BWrapperProvider").newInstance(); } } } // Whenever you need to work with your capabilities class Worker { void work() { if (WrappersHolder.instance.wrapperA != null) { ICECProvider aProvider = WrappersHolder.instance.wrapperA; ICompatibleEnergyCapability cap = aProvider.createWrapper(tile, side); // Do whatever you want with the cap } } } This way everything is safe to use since you are not loading any classes that may or may not be present and everything is nicely in a wrapper and bound to a common interface. If you want your has/getCapability to return a capability of an another mod it is a bit more tricky but also possible by creating wrappers for those capabilities in a similar way that depend on your main capability, only constructing them if the mod is present and returning them. You would need to be careful with your Capability<> instances though.
  20. As far as I am aware the Optional is going away in 1.13. CapabilityInject will not insert a capability that isn't provided thus it will stay null. But that kinda requires a hard dependency anyway since you need to pass a class to the annotation. My solution would be to put all interaction with potentially present capabilities in a separate class and don't load or ever touch it if the mod providing the capability isn't present.
  21. After you've changed the data of the capability on the server you need to send the changes to the client so the client is aware of the change. GUIs are client side only.
  22. You actually don't have to create a block to make your fluids have textures. The reason you don't see a texture without a fluid block is because it's not stitched to the texture atlas. Creating a block automatically stiches the texture and so you now have the ability to see it. However that is not the only way to do this and in fact is not the preffered way. Just stitch your fluid texture in the TextureStitchEvent.
  23. I am pretty sure these don't get synced to the client. You shouldn't be using this anyway, use capabilities. There are no reasons whatsoever to push/pop matrix here. You are not changing the matrix in any way. If you change the GL state to something change it back when you are done. If you are enabling blend then specify the blend profile too. Why are you modding for 1.10.2 anyway? It's outdated, use 1.12.2.
  24. What exactly are you trying to do? If you want to obtain a color of an item you can use ItemColors#colorMultiplier. Mind you this will return a white color if the item has no IItemColor associated with it. If you want to get the color from the texture you would need to somehow get the file that is responsible for the sprite, read it(to a BufferedImage perhaps) and then get the color of the pixel you want(or all pixels and average the color)(for a BufferedImage it would be BufferedImage#getRGB). Mind you that this approach is rather expensive. Alternatively you could read the pixels at specific coordinates on a texture using GL11.glReadPixels. The texture could be grayscaled to later be colored by an IItemColor. For this approach you would need to know the coordinates of the pixel on the sprite map though so you would need a sprite in the first place. Also the mod you've linked is open source. You could see how they did it. And keeping a list of each color value for each ingot is not that bad. It is actually the most sensical approach. It's just an integer per ingot you wish to register after all. And I have no idea why you are implying that you are modding for 1.13. Forge for 1.13 isn't out yet.
  25. I think it is done this way to make as little patches as possible and have the patches be as small as possible. 1 patch to the Item class < 1 patch to the Item class and 1 patch to the ItemShield class.
×
×
  • Create New...

Important Information

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