jaminv
Members-
Posts
25 -
Joined
-
Last visited
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
jaminv's Achievements
Tree Puncher (2/8)
4
Reputation
-
I have a multi-block machine that has connected textures. When the machine is active, the main machine block emits light. When it does so, it creates a hard light line between itself and connected blocks. Is there anything I can do about this? (Version 1.12)
-
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
I see what you mean now. While this did run properly on the dedicated server (due to layers on abstraction), when I'm doing everything properly it just isn't necessary. So much easier to just put the client code in a client proxy than having to worry about burying client code and/or accidentally referencing client objects in server code. --- Man I wish the tutorials I found had told me that I could test the dedicated server using the run configurations that are automatically setup in Eclipse (and that I should do so regularly). I had to go specifically looking for that information. I ended up having a fluid that I missed an IHadModel on and the registerModels() function referenced IStateMapped directly in the Block class. I also had some client message handlers that referenced Minecraft.getMinecraft().world and needed to be registered in a client proxy as a result. I also discovered that JsonUtils.isString() is (for some unknown reason) client only. I've got everything cleaned up now. I wonder if "test you code often on the dedicated server, here's how" should be in the common issues and recommendations thread? --- Thanks for all the help. Turns out that it's just another way of thinking about it, but it's still possible to consolidate code without using IHasModel interfaces. -
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
So optimally: In the RegistryEvent, call something like BlockInit.init(), which handle the instantiation, registration, and cache the model information? EDIT: I guess there's no real reason to break off into another class. -
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
I could just as easily instantiate them to an array and then registerAll() the array in the RegistryEvent. What's the best place to instantiate them? PreInit? Does that happen before the RegistryEvent? -
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
That's basically what I'm doing now, although I didn't realize I could getValidStates(). That might help with some abstraction. Ok, yes. That's almost exactly what I'm saying. --- https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/farming/FarmingBase.java#L103-L137 It appears that you're not using the RegistryEvents to register your blocks/items? Is that not required? I feel like a lot of the reason IHasModel ended up existing in the first place is to avoid disjointed code: where you've got instantiation in one place, registration in another, model registration in another, and then the block code somewhere else. So the tutorials I followed had a "instantiate the object, then have the instantiated object handle all its own registries" [anti]pattern. It appears you just handle instantiation, registry, and (deferred) model registry in one place. That seems like a pretty good pattern. I think that's the missing piece I was looking for. -
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
Well, the simple one is something like an `BlockOre` block where the ore type is stored in meta data. Instead of registering one model, I have historically iterated through the EnumOreType and called registerVariantRenderer() for each. Although thinking about it, I suppose I could just use a blockstate JSON file for this (as I do for the block itself). A more complex example is a series of blocks that use IBakedModel rendering and uses metadata for rendering. I actually need a different IBakedModel for each metadata state, otherwise the block's particle texture will be the same. Therefore, I need to create a CustomStateMapper that iterates through the EnumMetadata and provide a separate ResourceLocation for each. I'm not sure there's a way around this one, (perhaps I'm missing something?) and I'd really like to put this code with the objects themselves. This is specialized to the BakedModelProvider interface, so perhaps I could just add another method to the interface that returns an IStateMapper and defaults to a default implementation? Since I only currently need one VariantStateMapper to handle several similar block types, there wouldn't be any duplicate code. -
[SOLVED] IHasModel alternative for more complex situations
jaminv replied to jaminv's topic in Modder Support
1) Some models require additional consideration. I'm asking if IHasCustomModel is an acceptable pattern when a block requires extra code to handle its models. The data required to build the models is indeed public, but it may need special information like a Enum specific to that block. It makes more sense (to me) to localize that code in the same package as the block itself rather than push it into the registry packages. 2) BakedModelProvider is only referenced in my ModelRegistryEvent (and there only by instanceof), and in my BakedModelLoader, which is only registered in the ClientProxy. Additional, the only method of interface is specified as SideOnly (Side.CLIENT). I've actually modelled it after CodeChickenLib's IBakeryProvider (except my implementation is vastly simpler). Not saying that just because someone else did it makes it correct, but it seems like a lot of consideration has been applied here. (also the only method does nothing more than return an object, the `bakeModel` method has to be run on that object before any client-side code is referenced, and that is only done after BakedModelLoader provides a model to the client and bake() is run on that model). It appears that the ModelRegistryEvent is only ever run on the client side. Is that correct? -
[1.14.4] Blocks behind a custom model won't render [Solved]
jaminv replied to WezuLaweciarz's topic in Modder Support
Not sure if this still applies to 1.14, but it probably does. In your block class you need to override the isOpaqueCube method and return false: @Override public boolean isOpaqueCube(IBlockState state) { return false; } -
I followed a tutorial sometime ago, and of course I ended up with an IHasModel interface buried in my code. At the time, it kind of made sense because it wasn't really as simple as "of course everything has a model". Some blocks actually had custom item variants, so they would provide a different registerModels() implementation that handled the custom item variants. At the time, it felt like a pretty good use of abstraction. Except that in order to avoid a bunch of duplicate code, every Block derives from a `BlockBase` class that provides little more than a default registerModels() implementation... which is definitely *not* a good use of inheritance. Now, my situation has become a great deal more complex. I have some blocks that have custom state mappers for customer model baking. Currently, these utilize a `BakedModelProvider` interface because the block needs to provide data to the BakedModelLoader. I'm not sure if this is just a `IHasModel` by another name. There's no actual `registerModels()` method to the interface. Because they are all handled the same, I've put the following code in my ModelRegistryEvent: if (block instanceof BakedModelProvider) { ModelLoader.setCustomStateMapper(block, new CustomStateMapper(new ModelResourceLocation(block.getRegistryName(), "normal"))); BakedModelLoader.register(block.getRegistryName().getResourcePath()); } Naturally, things have gotten even more complex than this as my default `CustomStateMapper` implementation isn't going to work for every model, so I may actually need to add a `registeryModels() ` method to my `BakedModelProvider` interface. --- I'm not sure exactly what about the IHasModel makes it an anti-pattern. From my experience, it seems that the forced inheritance (or duplicate code) required to make the abstraction work is the main culprit. If that's the case, then an `IHasCustomModel` class would still be a proper pattern, whereas an `IHasModel` would not. Is that so? Or is there something else that makes it an anti-pattern?
-
I've done a few network messages already, but every example I've found entails sending the network message to a TileEntity (or player). But some of my tile entity classes are getting really big and I'm starting to work on composition over inheritance and breaking out some of the behaviors into encapsulating classes that manage those behaviors. The problem that I have is that some of them rely on network messages. As far as I can tell, I don't think there is a way to send a message to a composition object without passing it through the tile entity first. I was wondering if anyone had any thoughts on best practices for handling this? There are two ways that I can think of: 1) the tile entity manages the state, sends and receives the message, and implements an interface that allows the composition object to request the state from the tile entity, or 2) the composition object manages the state, sends the message and the tile entity receives the message and passes it directly to the composition object. The latter means less code in the tile entity, but doesn't feel very encapsulated. Since there's no requirement that the tile entity pass the message along, it's possible for that trust relationship to be broken. I'm leaning towards the former, but maybe there's something I'm missing? A few concrete examples: I'm moving the machine processing loop (like a furnace) out of my tile entity. There are two network messages involved in this. The first is the processing state. Since the processing loop doesn't occur on the client (its just skipped), the server machine has to tell the client that it's processing. This information is used to change model textures. The second network message is the redstone option (ignore redstone, active on signal, active without signal). This is selected by the dialog on the client and then has to be passed to the server, which actually uses the information. Thoughts?
-
Where it says "Looking at:" (third line of text from the bottom), those are the coordinates for your furnace. X=168, Y=69, Z=239. That is not within the range X=[-10,10], Y=[-10,10], Z=[-10,10]. You probably want to use the code I posted that deals in relative coordinates, but I can't hold your hand through explaining how the MC coordinate system works.
-
I think you might be thinking in relative coordinates, but world.getTileEntity() is in absolute coordinate. If you wanted relative coordinates, you'd need to feed in a reference BlockPos into the function: public static List<TileEntity> getTileEntityInAABB(World world, BlockPos relativeTo, int rangeX, int rangeY, int rangeZ) { List<TileEntity> telist = new ArrayList<TileEntity>(); for (double y = relativeTo.getY() - rangeY; y <= relativeTo.getY() + rangeY; ++y) { for (double x = relativeTo.getX() - rangeX; x <= relativeTo.getX() + rangeX; ++x) { for (double z = relativeTo.getZ() - rangeZ; z < relativeTo.getZ() + rangeZ; ++z) { TileEntity te = world.getTileEntity(new BlockPos(x, y, z)); if (te != null) { telist.add(te); } } } } return telist; }
-
Are you sure your Y value is between -10 and 10? Y=-10 doesn't actually make any sense. If you're still having trouble, open the F3 screen and point at your furnace and post a screenshot.
-
Change the for() loops to "y <= maxY", "x <= maxX", "z <= maxZ". I'm not sure why IF has it exclude the max values. If your furnace was at X=10, Y=10, or Z=10, it would have been excluded. Besides that, I don't see anything wrong there. Maybe narrow it down to the exact block coordinates of the furnace and trace through it?
-
Yes. Anything that has an inventory has to be a tile entity. Make sure you've got your range right. Make sure minX is less than maxX, minY is less than maxY, and minZ is less than maxZ, otherwise one of the loops will end without actually ever starting. That's the advantage of having a bounding box class. You can just feed it two BlockPos objects and have it sort out which of the X values is min or max, etc.