Posted February 15, 20169 yr My block extends a vanilla block (pressure plate), adding a property. When the server (!remote) updates the state, setting both properties, only my own property changes client-side. The vanilla property is always stuck at its default/base value on the client. I have server side print statements telling me that the state being set for the update method is what I want. Where do I look next to see where the vanilla property is being clobbered on its way to the client? My Block class: public abstract class classSmartPPlate extends BlockPressurePlate { public static final PropertyInteger SIGNAL = PropertyInteger.create ("signal", 0, 15); private Block keyIngredient = null; // Each child class must set keyIngredient protected classSelector selector = null; // Child class should allocate implementation of this interface public classSmartPPlate(String plateName) { super (Material.circuits, Sensitivity.MOBS); this.setUnlocalizedName (plateName); // Used in regBlock this.setStepSound (soundTypeMetal); classSensorMod.regBlock (this); children.add (Block.getIdFromBlock (this)); // Same function used to make automatic ItemBlock in item registry keyIngredient = this.defineKeyIngredient (); } /** * SIGNAL is the metadata value that becomes redstone strength via * abstract methods that insist on using block states instead of raw metadata. * * POWERED is the derived boolean that controls rendering. */ protected BlockState createBlockState() { return new BlockState (this, new IProperty[] { POWERED, SIGNAL }); } /** * Convert the given metadata into a BlockState for this Block. * The super's simple boolean and our own finer signal are each derived independently from the same meta. */ @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState () // We can't use super because of its "== 1" .withProperty (POWERED, Boolean.valueOf (meta > 0)) // So we write the inequality. .withProperty (SIGNAL, Integer.valueOf (meta)); } /** * Convert the BlockState into the correct metadata value. * We ignore super.POWER and simply return our own SIGNAL from which it is derived. */ @Override public int getMetaFromState(IBlockState state) { return ((Integer) state.getValue (SIGNAL)).intValue (); } /** * Convert internal detection signal to external redstone signal. Our parent tries to rectify all * detections into +15 redstone. We don' want that, so we must override both func_150060_c & * func_150066_d to pass signal unchanged. */ @Override protected int getRedstoneStrength(IBlockState state) { return ((Integer) state.getValue (SIGNAL)).intValue (); } /** * This should be named setBlockState. * In this method, super is smart enough to use "> 0", so * Let super do its POWERED before we append our SIGNAL. */ @Override protected IBlockState setRedstoneStrength(IBlockState state, int signal) { IBlockState intermediate = super.setRedstoneStrength (state, signal); System.out.println (String.format ("Input signal is %d", signal)); // TODO: Remove debug print System.out.println (String.format (" Intermediate POWERED = %s", intermediate.getValue (POWERED).toString ())); IBlockState result = intermediate.withProperty (SIGNAL, Integer.valueOf (signal)); System.out.println (String.format (" Result POWERED = %s\n", result.getValue (POWERED).toString ())); return result; } protected abstract Block defineKeyIngredient(); // Each child class must define its keyIngredient @Override public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) { if (!worldIn.isRemote) { int old = this.getRedstoneStrength (state); this.updateState (worldIn, pos, state, old); // Always update, because diff entities have diff strengths } } protected abstract ArrayList<Entity> getEntityList(World w, AxisAlignedBB aabb) ; /** * Returns the signal level of one entity. If multiple applicable entities share a plate, * the strongest signal among them will supersede the rest, so sort values accordingly. */ protected abstract int getSignal(Entity e); @Override protected int computeRedstoneStrength(World w, BlockPos pos) { int signal = 0; ArrayList<Entity> list = this.getEntityList (w, this.getSensitiveAABB (pos)); // Detect our entities for (Entity e : list) { if (!e.doesEntityNotTriggerPressurePlate ()) { // Look at each mob we can detect (we're not counting) signal = Math.max (signal, this.getSignal (e)); // Set signal to strongest one mob on our plate } } return signal; } } The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 15, 20169 yr Without overthinking - you have too many states. I mean. 0-15 for your signal, and where goes the boolean POWERED? Lookup BlockPressurePlateWeighted which uses POWER to measure power strengh from 0-15. It uses 0 value as replacement for POWERED=false. This is probably why client can't decode it. Idk why server says otherwise. 1.7.10 is no longer supported by forge, you are on your own.
February 15, 20169 yr I mean. 0-15 for your signal, and where goes the boolean POWERED? @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState () // We can't use super because of its "== 1" .withProperty (POWERED, Boolean.valueOf (meta > 0)) // So we write the inequality. .withProperty (SIGNAL, Integer.valueOf (meta)); } He's already doing what you said. Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
February 15, 20169 yr Author Right: Signal is meta, and meta is signal. "Powered" is purely derivitive from signal. If the metadata value made it to the client side, then my own meta-to-blockstate method should assign both properties. However, there must be something else going on... The client thread never even hits my breakpoint in that method. I don't know much about client-server comm, but I suspect that the properties are moving via something other than metadata. Might I need NBT coding and decoding? Argh, what I think I know about blocks, tile entities, items etc is getting all mixed up. The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 18, 20169 yr Author To clarify: On the client, the POWERED property remains false while it is true server-side. Is my mod responsible for some message call to sync the sides? The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 18, 20169 yr To clarify: On the client, the POWERED property remains false while it is true server-side. Is my mod responsible for some message call to sync the sides? When the server sends a block change to the client, the IBlockState is serialised to its ID in the packet. The ID of a state is derived from the Block 's ID and the metadata for that state. If a property doesn't affect metadata, its value won't be synced to clients. If your block requires a property that's not stored in the metadata (e.g. the property is stored in a TileEntity , derived from the other properties or derived from surrounding blocks) to render properly, override Block#getActualState to return an IBlockState with that property set. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
February 19, 20169 yr Author Interesting... So if one property is all that matters on the server, and another is derived to control rendering, then I need this "actual" method in order to force the render-control property to transmit? I'll give it go as soon as I get a break from tax season... The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 21, 20169 yr Author Well I'll be hog-tied! Here I thought the meta value would be passed from server to client where getStateFromMeta would be called. I programmed that method to handle this exact situation. Adding an override of getActualState does the trick. My p-plate was already able to produce its redstone power on the server. Now it visually sinks 1/16 of a block when activated. Here's my seemingly paradoxical code for getActualState: @Override public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { return getStateFromMeta (getMetaFromState (state)); // Believe it or not, this is NOT a no-op! } The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 21, 20169 yr That is horrible... that should not be the case. Show the rest of your class. I do Forge for free, however the servers to run it arn't free, so anything is appreciated. Consider supporting the team on Patreon
February 21, 20169 yr Author What's horrible is that getActualState is somehow being called with a state that's NOT the product of my own class's getStateFromMeta. State arrives having only one of its properties set (Choonster mentioned "serialization", which I did not fully understand). My getActual method converts back to meta so it can use my own meta-to-state method to make the complete state that I had expected in the first place. Here's my state def and the conversion methods: public static final PropertyInteger SIGNAL = PropertyInteger.create ("signal", 0, 15); /** * SIGNAL is the metadata value that becomes redstone strength via * abstract methods that insist on using block states instead of raw metadata. * * POWERED is super-class's derived boolean that controls rendering. */ @Override protected BlockState createBlockState() { return new BlockState (this, new IProperty[] { POWERED, SIGNAL }); } /** * Convert the given metadata into a BlockState for this Block. * The super's simple boolean and our own finer signal are each derived independently from the same meta. */ @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState () // We can't use super because of its "== 1" .withProperty (POWERED, Boolean.valueOf (meta > 0)) // So we write the more intelligent inequality. .withProperty (SIGNAL, Integer.valueOf (meta)); } /** * Convert the BlockState into the correct metadata value. * We don't use super.POWERED, simply storing SIGNAL from which POWERED can be derived. */ @Override public int getMetaFromState(IBlockState state) { return ((Integer) state.getValue (SIGNAL)).intValue (); } As you can see, the extended class's SIGNAL property is an integer expansion of the super-class's boolean POWERED property. SIGNAL equates to metadata, and POWERED has become a derived property (is the SIGNAL non-zero?). As described by the comments, the SIGNAL becomes the redstone power on the server, while POWERED controls rendering (p-plate up versus depressed) on the client. The one other factor one might care about is that (in client proxy) SIGNAL is ignored for rendering: ...StateMap.Builder ().addPropertiesToIgnore (classSmartPPlate.SIGNAL... The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 21, 20169 yr (Choonster mentioned "serialization", which I did not fully understand) Minecraft uses Netty to send data between the client and server. Netty doesn't know how to send complex objects like IBlockState s over the network and recreate them on the other side, so they need to be broken down into simpler types that Netty does know about (this is a similar concept to storing data in NBT, both are forms of serialisation). In this case Minecraft sends the ID of the IBlockState , which is just an int derived from the Block 's ID and the state's metadata. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
February 21, 20169 yr Author The part I don't understand is what happens when Netty's serial arrives on the client. If Netty has a block ID and meta value, then what is it doing instead of calling the block's getStateFromMeta? @D7: My conversions are symmetrical for all valid block states. Because one property depends on the other, POWERED should never be zero when SIGNAL is non-zero (and vice-versa). Maybe I was supposed to take a different approach when I wanted to expand a vanilla boolean into an integer? Should I have junked the vanilla boolean entirely and then written all 16 states in my blockstates.json file, choosing one model for zero and another model for each of the 15 levels of positive signal? The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 22, 20169 yr You should not be using POWERED then, as in memory you're taking up twice as much room as you need to because you have 'invalid' states in the IBlockState table. In your renderer you should just have a >0 check. Or, as others have suggested use IUnlistedProperty and fill it in in getActualState. Beyond that, depending on how you register your class things could get odd with the metadata. What state does that pass in that is 'invalid'? I do Forge for free, however the servers to run it arn't free, so anything is appreciated. Consider supporting the team on Patreon
February 22, 20169 yr The part I don't understand is what happens when Netty's serial arrives on the client. If Netty has a block ID and meta value, then what is it doing instead of calling the block's getStateFromMeta? IBlockState s are converted to and from their IDs using Block.BLOCK_STATE_IDS . This is populated each time a Block is registered: The registry iterates through all of the possible states and adds each one to the map using blockId << 4 | block.getMetaFromState(state) as the ID. If multiple states share an ID, whichever one was added last will be returned from ObjectIntIdentityMap#getByValue . Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
February 22, 20169 yr Author You should not be using POWERED then, as in memory you're taking up twice as much room as you need to because you have 'invalid' states in the IBlockState table. Maybe... If my 32 permutations map to only 16 metadata values, would they occupy 16 slots or 32? I'll try to create my blockstate with only SIGNAL, but some of the vanilla code might then break (POWERED runs like a rash through the vanilla p-plate class). Maybe I'll end up extending the p-plate's base class instead. I'll also look at weighted p-plates to see how they manage both redstone strength and on/off rendering. Come to think of it, perhaps that's where I should have started. Beyond that, depending on how you register your class things could get odd with the metadata. So far it's working like a charm, even after closing and reopening the world. There are only 16 possible meta values, so what's the worst that could happen? What state does that pass in that is 'invalid'? On the client side, the getActualState method was being called with a state that had non-zero SIGNAL but false POWERED. Based on Choonster's explanation, the POWERED=false permutation of that signal strength must have been added to the map after its true permutation, clobbering it. I'd ask why Netty uses the mapping instead of calling the state-to-meta and meta-to-state methods, but I hope I never need to know. I vaguely recall something about Netty being a separate thread, so I'll guess that it has something to do with thread-safe programming. In any case, it is what it is, and now I can see how it tripped up the rendering on the client. The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
February 22, 20169 yr Maybe... If my 32 permutations map to only 16 metadata values, would they occupy 16 slots or 32? You are creating 32 block states, half of wich are invalid for your game logic (powered=true,signal=0 / powered=false,signal!=0) So far it's working like a charm, even after closing and reopening the world. There are only 16 possible meta values, so what's the worst that could happen? Desync I'd ask why Netty uses the mapping instead of calling the state-to-meta and meta-to-state methods, but I hope I never need to know. I vaguely recall something about Netty being a separate thread, so I'll guess that it has something to do with thread-safe programming. In any case, it is what it is, and now I can see how it tripped up the rendering on the client. Becasuse what is hitting the wire is the raw chunk data (a block id / metadata hash for each block in the chunk) not the single block IBlockState
February 22, 20169 yr Yes, every permutation of every property gets a blockstate created for it thus all your 'invalid' states STILL exist and take up memory. Even if they are not put into the ID mapping. Admittedly as BlockState implementation is a small class, that's not much memory for you, wasting maybe ~500 bytes. But waste is waste. As for why they don't use mTs/sTm in networking. state = MAP[(ID<<16) | meta] is thousands of times faster then state = MAP[iD].mTs(meta) I do Forge for free, however the servers to run it arn't free, so anything is appreciated. Consider supporting the team on Patreon
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.