-
Posts
244 -
Joined
-
Last visited
-
Days Won
13
Everything posted by desht
-
But the OP wants to do this via the DecorateBiomeEvent.Post event, which is fired after the chunk has been generated. Gravel stays where it is during chunk generation because it's placed via a ChunkPrimer object, which is not affected by block physics in any way. Given that this is part of chunk generation, it sounds like some custom world gen might be a better option here? Making big terrain changes via the post event can't be good for chunk generation performance, and as the event name suggests, it's really intended for biome decoration, not terrain modification.
-
When you call World#setBlockState() - or Chunk#setBlockState() - Block#onBlockAdded() is called for the block you've set, if the block has actually changed. BlockFalling#onBlockAdded() calls World#scheduleUpdate(), which leads eventually to BlockFalling#updateTick(), and that method will turn the block into an EntityFallingBlock (via BlockFalling#checkFallable) if the block isn't supported from beneath. So... it doesn't seem directly possible to spawn gravel/sand/anvils in the air and not have them fall, even if you don't see the block update flag, i.e. bitmask 1 in the flags argument to setBlockState(). However, you should be able to do as @Draco18s said with the tall grass trick, or possibly even temporarily placing any solid block under your gravel before placing it, and removing the temporary block afterwards. As long as the block update flag (bitmask 1) isn't set, that shouldn't notify the gravel of a physics update, and leave it in place. E.g.: BlockPos below = pos.down(); // flags=0: no update notification, don't send to client world.setBlockState(below, Blocks.STONE.getDefaultState(), 0); // flags=2: no update notification, do send to client world.setBlockState(pos, Blocks.GRAVEL.getDefaultState(), 2); world.setBlockState(below, Blocks.AIR.getDefaultState(), 0); In reply to a couple of other comments in this thread: getGravityVelocity() is an entity method, and we don't want an EntityFallingBlock being created at all. BlockFalling.fallInstantly is false by default anyway. If true, it stops the smooth falling effect, and just "teleports" the falling block directly to its final location. So not relevant here.
-
[1.10.2] Question about syncing tile entity data
desht replied to Silly511's topic in Modder Support
If the only reason for marking an update is to sync tile entity data to the client for rendering purposes, then worldObj.notifyBlockUpdate(pos, oldState, newState, flags) looks to be a better option. markAndNotifyBlock() works - it calls notifyBlockUpdate() - but it also notifies the block's neighbours of a blockstate change, and may cause some comparator recalculation - extra unnecessary server load if you're just syncing TE data. -
[SOLVED] Dynamic blocks models and complex underlying block states
desht replied to desht's topic in Modder Support
Yep, that did the trick. Thanks everyone! I now appear to have a fully functional camouflaged block -
[SOLVED] Dynamic blocks models and complex underlying block states
desht replied to desht's topic in Modder Support
Well, I got this pretty much working today, going with option (2) - I ended up registering a custom model (RouterModel) for each variant of my block, passing the uncamouflaged model as a parameter to my custom baked model. Then I can return either the camo model or the underlying (real) model based on the presence or absence of an unlisted property. The code's all on GH now: see in particular: https://github.com/desht/ModularRouters/blob/master/src/main/java/me/desht/modularrouters/proxy/ClientProxy.java#L31 https://github.com/desht/ModularRouters/blob/master/src/main/java/me/desht/modularrouters/client/ModelBakeEventHandler.java https://github.com/desht/ModularRouters/blob/master/src/main/java/me/desht/modularrouters/client/RouterModel.java The only little problem I have now is that if I use a non-full block (say, a slab) as the camo block, it almost works, apart from the faces of any blocks beside it don't get drawn - presumably because the block renderer thinks it doesn't need to, the real block being a full cube. Image here: - the sandstone slab in front is actually a camouflaged item router, as The One Probe reveals, and the improperly rendered block behind is red sandstone. Any thoughts on how to get around that? -
I'm working through TheGreyGhost's dynamic models tutorial on GitHub right now: https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe04_block_dynamic_block_model1 and getting it close to working, but there's one problem I can't quite get my head round, and most likely due to me not fully understanding how variants and model loading works. The background: I have an existing block with several blockstate properties which affect the block rendering. That's all working fine, and you can see the blockstate & model JSON at: https://github.com/desht/ModularRouters/blob/master/src/main/resources/assets/modularrouters/blockstates/itemRouter.json and https://github.com/desht/ModularRouters/blob/master/src/main/resources/assets/modularrouters/models/block/itemRouter.json Now, I want to add some dynamic model functionality to this: when the tile entity holds a specific upgrade item, I want the block appearance to dynamically reflect the texture of the blockstate that has been saved in that upgrade item's NBT. That part's working fine - I can get the "camo" blockstate via an unlisted property in the IExtendedBlockState. Here's the code I have so far in my RouterModel (extends IBakedModel) class: @Override public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { return handleBlockState(state).getQuads(state, side, rand); } private IBakedModel handleBlockState(IBlockState state) { IBakedModel ret = existingModel; if (state instanceof IExtendedBlockState) { IExtendedBlockState ext = (IExtendedBlockState) state; IBlockState camoState = ext.getValue(BlockItemRouter.HELD_STATE); Minecraft mc = Minecraft.getMinecraft(); BlockRendererDispatcher blockRendererDispatcher = mc.getBlockRendererDispatcher(); BlockModelShapes blockModelShapes = blockRendererDispatcher.getBlockModelShapes(); if (camoState != null) { // works fine - block gets camouflaged ret = blockModelShapes.getModelForState(camoState); } else { // FAILS! attempt to get model for underlying state just gets the missing texture checkerboard ret = blockModelShapes.getModelForState(state); } } When the router has the camo upgrade, it works, and renders using the camo texture. But when it doesn't, its normal textures no longer work. I'm also setting up a custom state mapper in my client proxy preInit: StateMapperBase ignoreState = new StateMapperBase() { @Override protected ModelResourceLocation getModelResourceLocation(IBlockState iBlockState) { return RouterModel.variantTag; // new ModelResourceLocation("modularrouters:itemRouter", "normal") } }; ModelLoader.setCustomStateMapper(ModBlocks.itemRouter, ignoreState); ...which appears to be necessary, otherwise my custom RouterModel doesn't get used at all. But I have a feeling that's causing all the possible variants from my block to be ignored, and no model to be created for them (hence the missing textures). Am I on the right track here? I guess the real question is what do I need to do to get the regular models loaded for my block variants, but also be able to use a custom IBakedModel? As far as I can see, TheGreyGhost's tutorial doesn't account for the camouflaged block potentially having multiple variants and models... Update: thinking about this some more... my call to setCustomStateMapper() above returns a "modularrouters:itemRouter#normal" variant regardless of block state, and my ModelBakeEventHandler calls event.getModelRegistry().putObject(RouterModel.variantTag, customModel) - only the #normal variant is ever registered. But I need to register this custom model for every possible variant - do I need lots of calls to event.getModelRegistry().putObject(...) , one for each variant? Or is there a better way to do this?
-
Works nicely, thanks One very minor note: it's StateMap.Builder rather than StateMapBase.Builder .
-
The background: I have a tile entity which can sometimes (depending on how it's configured by the player) be a redstone power provider, and sometimes (probably more commonly) not. When it's a power provider, I obviously want Block#canProvidePower() to return true. But when it isn't a power provider, I want that method to return false (having it return true messes up things like propagating a strong redstone signal). Now, canProvidePower() only takes an IBlockState parameter, so I don't have access to the tile entity to see if it's currently able to provide power. Therefore I figured I'd probably need to store ability that in the blockstate, i.e. have the tile entity update a boolean property of the block when its ability to provide power is toggled. I don't want to use a regular listed block property, because a) this property has no bearing on the rendering of the block, and b) I already have several listed properties which do affect the rendering, and I don't want to double the number of models by adding another boolean property. So, my question: is IUnlistedProperty the right way to go here? My research so far suggests that it's really intended (along with Block#getExtendedState) only for block rendering, so would this be an appropriate usage? Or is there a better way to do this?
-
Botania has some code to generate lightning bolt effects using the particle system. I'd recommend perusing that code (it's in the vazkii.botania.client.fx package), and refer to http://botaniamod.net/license.php if you want to use the code (the license is reasonably liberal).
-
"is a chest"? You mean, you're directly extending TileEntityChest, or you're creating a tile entity with chest-like functionality? Have you looked at the code for TileEntityChest (note, it gets tricky because of double chests). You'll see that even vanilla chests implement getCapability() & hasCapability() for ITEM_HANDLER_CAPABILITY. But I think the short answer to your question is no: you don't need to implement any of those interfaces.
-
If you don't expose an IItemHandler capability on any side, there will be no automated interaction with your TE's inventory (or inventories), but players can of course still interact via any GUI you choose to attach to it via a Container. What do you mean by "implement IItemHandler..." ? Your TE shouldn't be doing that at all; your TE should contain an object implementing IItemHandler (commonly just an ItemStackHandler) for each inventory it has, and, if it wants to make those available to other mods (and vanilla!), return those from getCapability(), like I do here: https://github.com/desht/ModularRouters/blob/master/src/main/java/me/desht/modularrouters/block/tile/TileEntityItemRouter.java#L156 (Note that vanilla items like a hopper have been retrofitted with capability awareness and will interact with any inventory you expose via capabilities). You don't need to explicitly implement INBTSerializable; the TileEntity class implements that anyway, and the implementing methods just call readFromNBT() and writeToNBT(), which are the methods you should normally be overriding.
-
I actually came up with this idea a few years back when I wrote Bukkit plugins (and implemented it in the Sensible Toolbox plugin). But then I quit Bukkit and didn't do much of any development until a couple of months ago, when I decided to have a play with Forge modding. So here it is: Modular Routers. The idea: one block (the Item Router) and a collection of modules and upgrades which can be installed in said router to manipulate items which pass through the router. The router has only a single-slot inventory, and any installed modules (up to 9) do something with the buffer - e.g. drop an item into the world, send the item along to a nearby or distant inventory, pull items from an adjacent inventory into the buffer... Not intended as a replacement for more sophisticated item routing or piping systems but as a complement to them, for example when you want to move items across a room without laying a load of pipes under the floor. Here's an example use case, for supplying some Botania endoflames with coal: Dig a one-block hole and put an item router in it, so it's flush with the ground Set the router to run only when it has no redstone signal (router has a GUI button for this) Put a pressure plate on top of the router Add a Dropper Module to the router and configure it to drop items upwards Fill the router with coal (manually or perhaps from a hopper or other supply system, maybe even another router with a long-range Sender Mk2 module) Hey presto - a super-unobtrusive flower feeding system! Much more info at: CurseForge: https://minecraft.curseforge.com/projects/modular-routers Source: https://github.com/desht/ModularRouters Wiki: https://github.com/desht/ModularRouters/wiki
-
[Solved][1.10.2] EntityInteract event seems to fire twice on each side
desht replied to jabelar's topic in Modder Support
This had me confused for a while too, until I realised that in 1.9+, the player now has two usable hands... event.getHand() will be your friend here. -
[1.10.2] Ore dropping itself, not the item intended
desht replied to boredherobrine13's topic in Modder Support
Also remember that any IDE worth using will have a way of automatically adding an overridden method. For example, Ctrl-O in Intellij presents a list of overrideable methods, and will insert the correct method definition for you (along with an @Override annotation of course). I presume Eclipse has something similar. It's always worth using this when you're extending a base class. -
The scenario: I have a block (with a tile entity) which can output a redstone signal on each or any of its six sides; the redstone power level for each side depends in various ways on the contents of the tile entity's inventory: @Override public boolean canProvidePower(IBlockState state) { return true; } @Override public int getWeakPower(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { TileEntity te = blockAccess.getTileEntity(pos); if (te instanceof MyTileEntity) { return ((MyTileEntity) te).getRedstoneLevel(side); } else { return 0; } } (where getRedstoneLevel(EnumFacing side) is a method I added to return what the tile entity wants to emit on a given side in my MyTileEntity class). Now, if I open the tile entity's GUI and manually insert or remove items, everything updates fine - different sides of the block emit a redstone signal as appropriate. Some debug statements confirm that my getRedstoneLevel() method is always returning the right level for the given side, so I'm happy the logic is working here. The problem arises if the TE's inventory is modified programatically (via the CapabilityItemHandler & ItemStackHandler API, nothing unusual there) - in this case, the redstone signals do not update straight away, although I've confirmed again via debug statements that the TE's internal idea of the power levels is correctly updated. Some more debug statements show that getWeakPower() isn't getting called in this case. If I add (or break) some redstone around the block, that triggers the necessary redstone updates, and suddenly everything's OK again. So clearly it's a matter of having the tile entity notify its neighbours of a change somehow when its desired redstone output levels change. I had hoped calling worldObj.notifyNeighborsOfStateChange() would do the trick, but that doesn't seem to have any effect. So the question is: what's getting called to cause redstone levels to update when I modify the TE's inventory via GUI, that isn't getting called when the same inventory is manipulated programatically? Update: think I've figured it out. worldObj.notifyNeighborsOfStateChange() is the right way to do it, but I was calling it at the wrong point (before my tile entity was providing the appropriate power levels). A bit of code re-org and everything is now working nicely
-
I know Quark does this - when you press 'B' to toggle the 1.10 auto-jump, it displays a little icon which fades after a couple of seconds. Probably worth looking at how Vazkii handles that.
-
Hi, trying to figure out the correct & most efficient way to do this. If I have two arbitrary items (say one in a filter list, and one being checked against the filter), what's the correct way to check for oredict equivalence? From looking at the OreDictionary class, the only method which converts an ItemStack to anything is OreDictionary.getOreIDs() - can I use that on both stacks and check for an intersection of the ids in the two returned int[] arrays? I can't help feeling there's a better way, but I can't see it...