For now at least I just want to keep track of them, but as previously described an array of co-ordinates is ineffective when gravity-enabled blocks are included.
For now at least I just want to keep track of them, but as previously described an array of co-ordinates is ineffective when gravity-enabled blocks are included.
changing all the blocks out for tileentitys will kill and computer trying to run it.
changing all the blocks out for tileentitys will kill and computer trying to run it.
Not changing them out, adding tile entities to a specific group of blocks. If they weren't placed by the player, then they wouldn't have a PlayerBlock tile entity.
And then, when the game selects 20 random blocks to update, the code would just check if the block had that PlayerBlock tile entity before doing anything to it. Having an array would certainly make it easier to affect player-placed blocks specifically, which would be very useful indeed, but lag-reduction is a big issue here.
Not changing them out, adding tile entities to a specific group of blocks. If they weren't placed by the player, then they wouldn't have a PlayerBlock tile entity.
And then, when the game selects 20 random blocks to update, the code would just check if the block had that PlayerBlock tile entity before doing anything to it. Having an array would certainly make it easier to affect player-placed blocks specifically, which would be very useful indeed, but lag-reduction is a big issue here.
you will have to be careful as it creates a tileentity for all blocks that u put the code in no matter what unless you manuly add the tileentitys in
Hey, I'm just giving the man the information he asked for, haha. I don't know what he's trying to do with it.
Yes, you do need to extend BlockContainer, now that I think about it. Hopefully I didn't forget anything else :/ This is due to a bad design decision on Mojang's part (unnecessary use of the instanceof operator), which must be overcome by the block being derived from... a BlockContainer. Who knows, maybe it's more efficient than the alternative (that I'm about to recommend trying.)
Not sure, you can probably figure something out that isn't invasive. Are you comfortable changing the code a bit in the Block class a tad? What would happen if you shifted the base getTileEntity() method (just returns null initially) to Block instead of BlockContainer, and no longer required that the block be an instance of BlockContainer? Instead, just check if the result of the method returned is null (or I guess your custom subclass! Depending). All the other Blocks will inherit this method, and you won't have to go in and change any of them. I believe this would also include any other mods that have custom blocks, which would be neat. This is just my thinking, I don't quite have the time to look at all the code atm, haha.
Note that no block that already has a TileEntity would work under the TileEntity method you're trying (though maybe it doesn't matter? Not sure what specifically you're trying to do).In the root getTileEntity(), you can even check the current class (with instanceof) and only apply your method to whatever blocks you want : P
To clarify, I'm trying to find a reliable and relatively low-lag method to discern if a given block was placed by a player in order to isolate aspects of my work-in-progress mod to only those blocks rather than applying them to every block in existence (which is tremendously lag intensive by comparison). Specifically my mod causes blocks to randomly turn into lower-level blocks as part of a progressive decay process.
Ideally I'd like to run some kind of loop that would affect all those specific blocks in sequence rather than randomly within the update tick, but I realise that too would get very lag-intensive itself pretty quickly.
Not sure, you can probably figure something out that isn't invasive. Are you comfortable changing the code a bit in the Block class a tad? What would happen if you shifted the base getTileEntity() method (just returns null initially) to Block instead of BlockContainer, and no longer required that the block be an instance of BlockContainer? Instead, just check if the result of the method returned is null (or I guess your custom subclass! Depending). All the other Blocks will inherit this method, and you won't have to go in and change any of them. I believe this would also include any other mods that have custom blocks, which would be neat. This is just my thinking, I don't quite have the time to look at all the code atm, haha.
This certainly sounds like a good lead, and I can definitely see the flaws in the extant methodology (possibly something related to notch's self-taught status, though I can forgive him it given the relatively low-level of complexity when tile entities and containers first appeared in Minecraft).
In order to properly apply the tile entity, I need to use the player code which adds blocks whenever the player right-clicks with a block item. Is it possible to apply tile entities then or does it have to occur inside the blocks themselves when they're checked?
Note that no block that already has a TileEntity would work under the TileEntity method you're trying (though maybe it doesn't matter? Not sure what specifically you're trying to do).
In the root getTileEntity(), you can even check the current class (with instanceof) and only apply your method to whatever blocks you want : P
In theory I could use the tile entity PlayerBlock for most blocks and then add in special returns for any blocks that don't have that entity (most of which are man-made only, like signs and note blocks, at least for the moment)
To clarify, I'm trying to find a reliable and relatively low-lag method to discern if a given block was placed by a player in order to isolate aspects of my work-in-progress mod to only those blocks rather than applying them to every block in existence (which is tremendously lag intensive by comparison). Specifically my mod causes blocks to randomly turn into lower-level blocks as part of a progressive decay process.
Ideally I'd like to run some kind of loop that would affect all those specific blocks in sequence rather than randomly within the update tick, but I realise that too would get very lag-intensive itself pretty quickly.
This certainly sounds like a good lead, and I can definitely see the flaws in the extant methodology (possibly something related to notch's self-taught status, though I can forgive him it given the relatively low-level of complexity when tile entities and containers first appeared in Minecraft).
In order to properly apply the tile entity, I need to use the player code which adds blocks whenever the player right-clicks with a block item. Is it possible to apply tile entities then or does it have to occur inside the blocks themselves when they're checked?
In theory I could use the tile entity PlayerBlock for most blocks and then add in special returns for any blocks that don't have that entity (most of which are man-made only, like signs and note blocks, at least for the moment)
It is possible to add a TileEntity to a block without changing the blocks code (by changing the placement code) but its not advisable.
If using forge you can have a block that has a TileEntity as the getTileEntity function is now in the root block.
but if the block has getTileEntity it will be used every time it is placed so you cant use that as it will make every block in the game into a TileEntity.
What you will have to do is when ever a block is place you will have to add
TileEntity tileentity = getChunkBlockTileEntity(x, y, z);
if (tileentity == null)
{
tileentity = yourtileentity;
worldObj.setBlockTileEntity(x, y, z, tileentity);
}
This will stop you overriding furnaces and that sort of thing.
I would like to point out that although I cant see any reason you cant do that I also haven't checked every bit of code pertaining to adding a TileEntity so I cant say for sure it wont brake something
Cool, cool. What do you mean by "level"? If you working low-level enough, and this somehow involves block positioning/height, lighting updates might become a problem (not impossible or anything, though).
In order to properly apply the tile entity, I need to use the player code which adds blocks whenever the player right-clicks with a block item. Is it possible to apply tile entities then or does it have to occur inside the blocks themselves when they're checked?
Solution 1 (Not my favorite)
Ehh... hmm... what you might have to do is replicate the TileEntity code surrounding the call to getTileBlockEntity in Chunk's setBlock methods and stick it before/after the player's call to setBlock. Or stick the replicated code in the onBlockPlaced method in Block maybe (I think that's only called when players place, I'm not sure. Maybe Endermen, possibly all placements... I can't remember, you can use "Get Call Hierarchy" to figure it out.) Perhaps the PlayerController subclasses have a spot you can stick it in? If you can replicate it correctly, and maybe include a check to ensure it doesn't already have a TileEntity, I bet it'd work... just make SURE you understand what all is going on, lol.
The only problem I foresee is possibly the use of a private/protected method/field in Chunk based on whether or not a TileEntity was created in it. For any behavior like this (and only if absolutely necessary)... I'd probably create a new public method(s) in Chunk that calls the private/protected methods you need and modifies fields as necessary. (I'd say adding additional methods is better than forcing a Mojang method to public so we don't have to change a method that's currently used everywhere (and possibly even remove any inlining it's secretly receiving by being private, which would be really harmful considering how frequently these methods are called))
Solution 2 (My money's on this one)
Another solution (fast, easy, and less buggy, though open to misuse) is to give Block a public static boolean shouldMarkAsPlacedByPlayer (or something) and have Block's getTileEntity check it-- if true, return a tileentity, if false, return null. Then, before the player calls setBlock, set shouldMarkAsPlacedByPlayer to true, then set it back to false afterwards. Clever ain't it? Hehehe
I definitely like my second solution better, try that one, haha.
I just thought of something-- Mojang's code is probably written based on the assumption that kinds of blocks either always have TileEntities or never have TileEntities. What you're doing would be breaking this, and though I can't think of a problem off the top of my head (I've only looked around this code so much), it's something to keep in mind should something mysterious arise.
I just thought of something-- Mojang's code is probably written based on the assumption that kinds of blocks either always have TileEntities or never have TileEntities. What you're doing would be breaking this, and though I can't think of a problem off the top of my head (I've only looked around this code so much), it's something to keep in mind should something mysterious arise.
This is exactly what I said in my post. You should be very careful about giving blocks TileEntities when they are not meant to have them for instance they may not have them when they load back up depending on how you do it.
The only thing I can think of on that front is piston interactions, but I don't know if it's explicit that blocks with tile entities can't be pushed or just a list.
The only thing I can think of on that front is piston interactions, but I don't know if it's explicit that blocks with tile entities can't be pushed or just a list.
its more than that without going through all the code there could be some odd interaction that we don't know about.
I think in the end its best to ask do you really really need to do it this way, the fact that no other mod does it suggests that its impractical to do.
If we are to use that line of reasoning, can you think of any other mod that needs to?
Nature+ affects a lot of blocks for example, but does so by rewriting their class files. My mod on the other hand affects everything, and trimming it to player blocks only is an intensive lag-reduction measure as well as prevention of destruction of natural features (early test worlds ended up with entire cave systems collapsed and full of gravel, for example).
Which, to clarify again, when I say "lower-level blocks" I mean further down the chain of being useful. Smoothstone decays to cobblestone which in turn decays to gravel for example is one of the eldest decay lines I've made, and other blocks experience similar progressions tailored to their nature (wooden planks rot and become unstable, then fall and decay further dirt, whilst torches burn out and then crumble entirely to nothing, etc. etc.).
If you want more complete details of what precisely I'm doing with things, there's my WIP thread here: Nature Reclaims
Try out my second solution, it should take seconds to implement, then just see if it works.
The best way to find a possible bug with TileEntity "permanence" would probably be to first use Open Call Hierarchy on getBlockTileEntity and see what all's using it (not an unreasonable amount of code to examine), then if that checks out, release a beta and see if anyone stumbles on a bug.
Solution 2 (My money's on this one)
Another solution (fast, easy, and less buggy, though open to misuse) is to give Block a public static boolean shouldMarkAsPlacedByPlayer (or something) and have Block's getTileEntity check it-- if true, return a tileentity, if false, return null. Then, before the player calls setBlock, set shouldMarkAsPlacedByPlayer to true, then set it back to false afterwards. Clever ain't it? Hehehe
I definitely like my second solution better, try that one, haha.
So the steps, to break apart the paragraph, are:
The Block class has a public static boolean named shouldMark
The getTileEntity function references that shouldMark variable and returns a PlayerBlock tile entity if it's true or else null.
When a player places a block, shouldMark is set to true and then following block placement reset to false
So in effect shouldMark functions as a momentary switch that gives PlayerBlock tile entities to anything the player places (based on the usage context of when shouldMark becomes true) and nothing else, correct?
The Block class has a public static boolean named shouldMark
The getTileEntity function references that shouldMark variable and returns a PlayerBlock tile entity if it's true or else null.
When a player places a block, shouldMark is set to true and then following block placement reset to false
So in effect shouldMark functions as a momentary switch that gives PlayerBlock tile entities to anything the player places (based on the usage context of when shouldMark becomes true) and nothing else, correct?
Yep, that's the plan. Also, you need to remove the BlockContainer requirement as noted before. And yes, only at times when you explicitly set it to true would it give a TileEntity to the placed block. Also, make sure shouldMark is initially set to false.
To clarify, I'm trying to find a reliable and relatively low-lag method to discern if a given block was placed by a player in order to isolate aspects of my work-in-progress mod to only those blocks rather than applying them to every block in existence (which is tremendously lag intensive by comparison). Specifically my mod causes blocks to randomly turn into lower-level blocks as part of a progressive decay process.
Ideally I'd like to run some kind of loop that would affect all those specific blocks in sequence rather than randomly within the update tick, but I realise that too would get very lag-intensive itself pretty quickly.
Downsides to the tile entity approach:
- Large quantities of these blocks could potentially get a bit laggy, depending on how you are keeping track of a blocks decay progression.
- Tile entities do not tick if the chunk is not loaded
Both of these are potentially negligible, depending on what type of effect you are looking for. If it is only a few blocks, and they decay relatively fast (or they decay in sync with their surroundings), then tile entities should work fine. However let's say that you want to make the block a countdown timer (of sorts), where the player has to go collect stuff and then get back. A tile entity will work, but you will want to keep a list of blocks active and update them manually (outside of the tile entity's update tick method).
This is achievable by keeping an array list of active blocks, and saving that list to a file periodically (as well as at important moments). You will also need to repopulate the list based off of this file on load of a map. Perhaps this is overkill, and only ticking when the player has those chunks loaded is enough.
On a side note, meta data can be used as a means of storing extra things (for instance, creating a second metadata field, which runs parallel to the standard). Using a metadata method would be terribly slow though, as you would still need to scan through all surrounding blocks looking for a specific one (32K blocks per chunk).
When you go to ask for help, it is almost always a good idea to give as much information as you can. That way we know what sort of solution you need.
EDIT: just saw the post where you have your mod thread. Just so you know, I see a problem with using tile entities (unless you guys have already worked this out):
- you are doing common blocks, which will produce greater lag
- you are doing an erosion effect, so decay should be universally the same
- you are doing vanilla blocks, so a tile entity would require editing -every- vanilla block that you want to effect
New and revised suggestion!
Make a tracker for block placement. Every time a player places a block of interest, it's coordinates are added to the tracker's list of active blocks. The tracker updates every 80 ticks, and adds to the blocks decay time. When a block's decay time is complete, it runs through a decay handler, which will switch the block for an inferior and adjust the blocks coords in the decay handler to reflect the new changes. Placed blocks will be saved in a data file under GZip compression, an example file will look like:
The decay handler will write a save file inside of the current worlds save folder every time MC quick saves. It will load from this file when you start a world.
That might be a little bit off from what a final product would look like, but it should get you close, or at least started. This concludes my random late night rant, toodles!
Rollback Post to RevisionRollBack
Link Removed Tutorials and Mods and Things and Stuff - blog.yofreke.com
Downsides to the tile entity approach:
- Large quantities of these blocks could potentially get a bit laggy, depending on how you are keeping track of a blocks decay progression.
- Tile entities do not tick if the chunk is not loaded
Both of these are potentially negligible, depending on what type of effect you are looking for. If it is only a few blocks, and they decay relatively fast (or they decay in sync with their surroundings), then tile entities should work fine. However let's say that you want to make the block a countdown timer (of sorts), where the player has to go collect stuff and then get back. A tile entity will work, but you will want to keep a list of blocks active and update them manually (outside of the tile entity's update tick method).
Currently, I'm just piggy-backing on the updateTick method of Block.class and having it call my master decay method which determines the odds of a specific block decaying and then handles the subordinate decay methods (including growth of vines and moss and other non-specific features). The code not running on unloaded chunks is also not a major concern.
Presently, I only need to discern player-placed blocks from natural blocks in order to prevent the entire world running the full decay code and gradually deteriorating.
This is achievable by keeping an array list of active blocks, and saving that list to a file periodically (as well as at important moments). You will also need to repopulate the list based off of this file on load of a map. Perhaps this is overkill, and only ticking when the player has those chunks loaded is enough.
On a side note, meta data can be used as a means of storing extra things (for instance, creating a second metadata field, which runs parallel to the standard). Using a metadata method would be terribly slow though, as you would still need to scan through all surrounding blocks looking for a specific one (32K blocks per chunk).
When you go to ask for help, it is almost always a good idea to give as much information as you can. That way we know what sort of solution you need.
EDIT: just saw the post where you have your mod thread. Just so you know, I see a problem with using tile entities (unless you guys have already worked this out):
- you are doing common blocks, which will produce greater lag
- you are doing an erosion effect, so decay should be universally the same
- you are doing vanilla blocks, so a tile entity would require editing -every- vanilla block that you want to affect
I'm not scanning through every block in a chunk looking for player-placed blocks, I'm running a code that checks if specific individual blocks are player-placed and decaying them if true. If the block doesn't have that PlayerBlock tag (however such a tag is achieved) the code stops doing anything to it.
New and revised suggestion!
Make a tracker for block placement. Every time a player places a block of interest, it's coordinates are added to the tracker's list of active blocks. The tracker updates every 80 ticks, and adds to the blocks decay time. When a block's decay time is complete, it runs through a decay handler, which will switch the block for an inferior and adjust the blocks coords in the decay handler to reflect the new changes. Placed blocks will be saved in a data file under GZip compression, an example file will look like:
The decay handler will write a save file inside of the current worlds save folder every time MC quick saves. It will load from this file when you start a world.
That might be a little bit off from what a final product would look like, but it should get you close, or at least started. This concludes my random late night rant, toodles!
I can maintain tile entities by modifying (very slightly) the behaviour of falling blocks and pistons, and they'll otherwise stick around pretty neatly.
I'm also not using a hard "age" variable like you suggest, but instead a percentage odds for each tick, modified for the decay rate setting of the user (so the Day setting is the slowest decay with Millennia being the fastest, by modifying the percentage odds). This allows me to have neighbor blocks influence the odds of a given block decaying, rather than blocks just decaying in the order they were placed. Therefore that's one less variable to store.
With these corrections in mind, is there any significant benefit to this method over Frizzil's suggestion?
There is still the issue of adding a TileEntity to the standard blocks. In order for a block to load TileEntities, it must be an extension of BlockContainer. This limits you because java will only accept one extension for a class (unlike some languages). In order to make vanilla blocks load tile entities as well, which extend something besides BlockContainer, you will need to rewrite how chunks load TileEntities to function based on an interface (which a normal block can implement overtop of its super class).
If you are doing it based on a percentage and not an age, you will likely still want to keep track of blocks that have been marked by the player in some sort of watcher and update the placed blocks outside of the standard update tick (more reliable).
I can maintain tile entities by modifying (very slightly) the behaviour of falling blocks and pistons, and they'll otherwise stick around pretty neatly.
Explain?
This allows me to have neighbor blocks influence the odds of a given block decaying, rather than blocks just decaying in the order they were placed. Therefore that's one less variable to store.
True, it is one less variable. However, you can achieve the speed setting by altering how delayed the update of the main watcher is (40 ticks, 60, 80). Having surrounding blocks influence decay can also be pretty simply added using any method, as every method will require knowledge of a blocks coordinates.
Rollback Post to RevisionRollBack
Link Removed Tutorials and Mods and Things and Stuff - blog.yofreke.com
There is still the issue of adding a TileEntity to the standard blocks. In order for a block to load TileEntities, it must be an extension of BlockContainer. This limits you because java will only accept one extension for a class (unlike some languages). In order to make vanilla blocks load tile entities as well, which extend something besides BlockContainer, you will need to rewrite how chunks load TileEntities to function based on an interface (which a normal block can implement overtop of its super class).
If you are doing it based on a percentage and not an age, you will likely still want to keep track of blocks that have been marked by the player in some sort of watcher and update the placed blocks outside of the standard update tick (more reliable).
As previously discussed, we can move the getBlockEntity out of BlockContainer and into Block, thereby removing the necessity of every affected block being an extension of the BlockContainer class.
when gravity-enabled blocks fall and pistons push blocks, the blocks are stored in tile entities, so the PlayerBlock entity would cease to exist. If I modify the code for those new tile entities, I can have a new PlayerBlock entity be instantiated when the block is recreated in the new location.
True, it is one less variable. However, you can achieve the speed setting by altering how delayed the update of the main watcher is (40 ticks, 60, 80). Having surrounding blocks influence decay can also be pretty simply added using any method, as every method will require knowledge of a blocks coordinates.
changing all the blocks out for tileentitys will kill and computer trying to run it.
Not changing them out, adding tile entities to a specific group of blocks. If they weren't placed by the player, then they wouldn't have a PlayerBlock tile entity.
And then, when the game selects 20 random blocks to update, the code would just check if the block had that PlayerBlock tile entity before doing anything to it. Having an array would certainly make it easier to affect player-placed blocks specifically, which would be very useful indeed, but lag-reduction is a big issue here.
you will have to be careful as it creates a tileentity for all blocks that u put the code in no matter what unless you manuly add the tileentitys in
Yes, you do need to extend BlockContainer, now that I think about it. Hopefully I didn't forget anything else :/ This is due to a bad design decision on Mojang's part (unnecessary use of the instanceof operator), which must be overcome by the block being derived from... a BlockContainer. Who knows, maybe it's more efficient than the alternative (that I'm about to recommend trying.)
Not sure, you can probably figure something out that isn't invasive. Are you comfortable changing the code a bit in the Block class a tad? What would happen if you shifted the base getTileEntity() method (just returns null initially) to Block instead of BlockContainer, and no longer required that the block be an instance of BlockContainer? Instead, just check if the result of the method returned is null (or I guess your custom subclass! Depending). All the other Blocks will inherit this method, and you won't have to go in and change any of them. I believe this would also include any other mods that have custom blocks, which would be neat. This is just my thinking, I don't quite have the time to look at all the code atm, haha.
Note that no block that already has a TileEntity would work under the TileEntity method you're trying (though maybe it doesn't matter? Not sure what specifically you're trying to do).In the root getTileEntity(), you can even check the current class (with instanceof) and only apply your method to whatever blocks you want : P
Ideally I'd like to run some kind of loop that would affect all those specific blocks in sequence rather than randomly within the update tick, but I realise that too would get very lag-intensive itself pretty quickly.
This certainly sounds like a good lead, and I can definitely see the flaws in the extant methodology (possibly something related to notch's self-taught status, though I can forgive him it given the relatively low-level of complexity when tile entities and containers first appeared in Minecraft).
In order to properly apply the tile entity, I need to use the player code which adds blocks whenever the player right-clicks with a block item. Is it possible to apply tile entities then or does it have to occur inside the blocks themselves when they're checked?
In theory I could use the tile entity PlayerBlock for most blocks and then add in special returns for any blocks that don't have that entity (most of which are man-made only, like signs and note blocks, at least for the moment)
It is possible to add a TileEntity to a block without changing the blocks code (by changing the placement code) but its not advisable.
If using forge you can have a block that has a TileEntity as the getTileEntity function is now in the root block.
but if the block has getTileEntity it will be used every time it is placed so you cant use that as it will make every block in the game into a TileEntity.
What you will have to do is when ever a block is place you will have to add
This will stop you overriding furnaces and that sort of thing.
I would like to point out that although I cant see any reason you cant do that I also haven't checked every bit of code pertaining to adding a TileEntity so I cant say for sure it wont brake something
Solution 1 (Not my favorite)
Ehh... hmm... what you might have to do is replicate the TileEntity code surrounding the call to getTileBlockEntity in Chunk's setBlock methods and stick it before/after the player's call to setBlock. Or stick the replicated code in the onBlockPlaced method in Block maybe (I think that's only called when players place, I'm not sure. Maybe Endermen, possibly all placements... I can't remember, you can use "Get Call Hierarchy" to figure it out.) Perhaps the PlayerController subclasses have a spot you can stick it in? If you can replicate it correctly, and maybe include a check to ensure it doesn't already have a TileEntity, I bet it'd work... just make SURE you understand what all is going on, lol.
The only problem I foresee is possibly the use of a private/protected method/field in Chunk based on whether or not a TileEntity was created in it. For any behavior like this (and only if absolutely necessary)... I'd probably create a new public method(s) in Chunk that calls the private/protected methods you need and modifies fields as necessary. (I'd say adding additional methods is better than forcing a Mojang method to public so we don't have to change a method that's currently used everywhere (and possibly even remove any inlining it's secretly receiving by being private, which would be really harmful considering how frequently these methods are called))
Solution 2 (My money's on this one)
Another solution (fast, easy, and less buggy, though open to misuse) is to give Block a public static boolean shouldMarkAsPlacedByPlayer (or something) and have Block's getTileEntity check it-- if true, return a tileentity, if false, return null. Then, before the player calls setBlock, set shouldMarkAsPlacedByPlayer to true, then set it back to false afterwards. Clever ain't it? Hehehe
I definitely like my second solution better, try that one, haha.
This is exactly what I said in my post. You should be very careful about giving blocks TileEntities when they are not meant to have them for instance they may not have them when they load back up depending on how you do it.
its more than that without going through all the code there could be some odd interaction that we don't know about.
I think in the end its best to ask do you really really need to do it this way, the fact that no other mod does it suggests that its impractical to do.
Nature+ affects a lot of blocks for example, but does so by rewriting their class files. My mod on the other hand affects everything, and trimming it to player blocks only is an intensive lag-reduction measure as well as prevention of destruction of natural features (early test worlds ended up with entire cave systems collapsed and full of gravel, for example).
Which, to clarify again, when I say "lower-level blocks" I mean further down the chain of being useful. Smoothstone decays to cobblestone which in turn decays to gravel for example is one of the eldest decay lines I've made, and other blocks experience similar progressions tailored to their nature (wooden planks rot and become unstable, then fall and decay further dirt, whilst torches burn out and then crumble entirely to nothing, etc. etc.).
If you want more complete details of what precisely I'm doing with things, there's my WIP thread here: Nature Reclaims
Try out my second solution, it should take seconds to implement, then just see if it works.
The best way to find a possible bug with TileEntity "permanence" would probably be to first use Open Call Hierarchy on getBlockTileEntity and see what all's using it (not an unreasonable amount of code to examine), then if that checks out, release a beta and see if anyone stumbles on a bug.
So the steps, to break apart the paragraph, are:
Yep, that's the plan. Also, you need to remove the BlockContainer requirement as noted before. And yes, only at times when you explicitly set it to true would it give a TileEntity to the placed block. Also, make sure shouldMark is initially set to false.
Downsides to the tile entity approach:
- Large quantities of these blocks could potentially get a bit laggy, depending on how you are keeping track of a blocks decay progression.
- Tile entities do not tick if the chunk is not loaded
Both of these are potentially negligible, depending on what type of effect you are looking for. If it is only a few blocks, and they decay relatively fast (or they decay in sync with their surroundings), then tile entities should work fine. However let's say that you want to make the block a countdown timer (of sorts), where the player has to go collect stuff and then get back. A tile entity will work, but you will want to keep a list of blocks active and update them manually (outside of the tile entity's update tick method).
This is achievable by keeping an array list of active blocks, and saving that list to a file periodically (as well as at important moments). You will also need to repopulate the list based off of this file on load of a map. Perhaps this is overkill, and only ticking when the player has those chunks loaded is enough.
On a side note, meta data can be used as a means of storing extra things (for instance, creating a second metadata field, which runs parallel to the standard). Using a metadata method would be terribly slow though, as you would still need to scan through all surrounding blocks looking for a specific one (32K blocks per chunk).
When you go to ask for help, it is almost always a good idea to give as much information as you can. That way we know what sort of solution you need.
EDIT: just saw the post where you have your mod thread. Just so you know, I see a problem with using tile entities (unless you guys have already worked this out):
- you are doing common blocks, which will produce greater lag
- you are doing an erosion effect, so decay should be universally the same
- you are doing vanilla blocks, so a tile entity would require editing -every- vanilla block that you want to effect
New and revised suggestion!
Make a tracker for block placement. Every time a player places a block of interest, it's coordinates are added to the tracker's list of active blocks. The tracker updates every 80 ticks, and adds to the blocks decay time. When a block's decay time is complete, it runs through a decay handler, which will switch the block for an inferior and adjust the blocks coords in the decay handler to reflect the new changes. Placed blocks will be saved in a data file under GZip compression, an example file will look like:
The decay handler will write a save file inside of the current worlds save folder every time MC quick saves. It will load from this file when you start a world.
That might be a little bit off from what a final product would look like, but it should get you close, or at least started. This concludes my random late night rant, toodles!
Tutorials and Mods and Things and Stuff - blog.yofreke.com
Currently, I'm just piggy-backing on the updateTick method of Block.class and having it call my master decay method which determines the odds of a specific block decaying and then handles the subordinate decay methods (including growth of vines and moss and other non-specific features). The code not running on unloaded chunks is also not a major concern.
Presently, I only need to discern player-placed blocks from natural blocks in order to prevent the entire world running the full decay code and gradually deteriorating.
I'm not scanning through every block in a chunk looking for player-placed blocks, I'm running a code that checks if specific individual blocks are player-placed and decaying them if true. If the block doesn't have that PlayerBlock tag (however such a tag is achieved) the code stops doing anything to it.
I can maintain tile entities by modifying (very slightly) the behaviour of falling blocks and pistons, and they'll otherwise stick around pretty neatly.
I'm also not using a hard "age" variable like you suggest, but instead a percentage odds for each tick, modified for the decay rate setting of the user (so the Day setting is the slowest decay with Millennia being the fastest, by modifying the percentage odds). This allows me to have neighbor blocks influence the odds of a given block decaying, rather than blocks just decaying in the order they were placed. Therefore that's one less variable to store.
With these corrections in mind, is there any significant benefit to this method over Frizzil's suggestion?
If you are doing it based on a percentage and not an age, you will likely still want to keep track of blocks that have been marked by the player in some sort of watcher and update the placed blocks outside of the standard update tick (more reliable).
Explain?
True, it is one less variable. However, you can achieve the speed setting by altering how delayed the update of the main watcher is (40 ticks, 60, 80). Having surrounding blocks influence decay can also be pretty simply added using any method, as every method will require knowledge of a blocks coordinates.
Tutorials and Mods and Things and Stuff - blog.yofreke.com
As previously discussed, we can move the getBlockEntity out of BlockContainer and into Block, thereby removing the necessity of every affected block being an extension of the BlockContainer class.
when gravity-enabled blocks fall and pistons push blocks, the blocks are stored in tile entities, so the PlayerBlock entity would cease to exist. If I modify the code for those new tile entities, I can have a new PlayerBlock entity be instantiated when the block is recreated in the new location.
How exactly would such a "watcher" be created?