Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable dynamic block allocation. #4036

Draft
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

4Denthusiast
Copy link
Contributor

@4Denthusiast 4Denthusiast commented Jun 6, 2020

Load every possible block family while the game is loading, rather than only when each block is requested from the BlockManager. It isn't immediately obvious that this should be removed, but in my opinion it's more trouble than it was worth. Some of the main problems I have with the dynamic block assignment are that it's easy to miss that the block list may be incomplete (I missed it when writing FlowingLiquids for example), updating things can be complicated (there's a longstanding bug with registrations not propagating to clients properly in multiplayer), it just requires a lot of extra code to deal with dynamic restrations, and I vaguely remember people talking about a problem with including blocks that haven't yet been registered in UIs.

In order to avoid having such a huge number of blocks that just loading them all takes an excessive amount of time, freeform block families have been restricted to only use shapes explicitly marked as freeformUsable in their file. Currently only the cube, half-block, eighth-block and stair shapes are marked as freeformUsable. The engine also contains various slope shapes which look like they're probably intended for freeform use, but I've never seen them actually used and there are a lot of them, so I left them out. listed in the block file.

This will probably require some module updates. In particular, any BlockRegistrationListeners now no longer need to (or can) listen for block registrations, and if there are actual uses of any freeform block shapes other than the ones i marked, they will need to be explicitly listed in the block definition files.

(Now already implemented) It may become necessary to add some system to restrict freeform block families further if it turns out that there are a lot of shapes that are necessary in a few cases. From what I've seen though (mostly just Josharias Survival and Core actually), the wide range of options provided by the freeform block families aren't actually used much.

Probably resolves #3491, but I still need to actually test that.

@4Denthusiast 4Denthusiast added Topic: Stabilization Requests, Issues and Changes related to improving stablity and reducing flakyness WIP labels Jul 14, 2020
@pollend
Copy link
Member

pollend commented Jul 14, 2020

I was able to validate this with two clients. its probably a lot better then trying to hotload blocks on the fly since it adds its own set of complications that i'm not sure we are ready to deal with.

Re-enable multiple blocks per shape in a more controlled manner,
requiring all of them to be registered in the block definition.
Blocks without a shape now default to cube rather than freeform.
Existing block files should be usable unchanged except in the case
where the freeform feature was actually used, in which case the list
of possible shapes will have to be added.
@lgtm-com
Copy link

lgtm-com bot commented Sep 2, 2020

This pull request fixes 1 alert when merging 35f73eb into fe4f808 - view on LGTM.com

fixed alerts:

  • 1 for Dereferenced variable may be null

These classes existed to update things when new block families were
registered, therefore they're no longer necessary except the parts
that run during loading, which no longer need separate classes.
@4Denthusiast
Copy link
Contributor Author

This no longer allocates excessive numbers of blocks, so (once module updates are ready), it should be ready to merge. Blocks with variants of multiple shapes are now required to list their possible shapes in the block definition file, in the shapes attribute. This will probably affect several modules, but unfortunately, not updating this in modules would cause a runtime error rather than a compile-time error, making the modules that need to be updated harder to find.

@4Denthusiast 4Denthusiast removed the WIP label Sep 2, 2020
@lgtm-com
Copy link

lgtm-com bot commented Sep 2, 2020

This pull request fixes 1 alert when merging 86c4d0b into fe4f808 - view on LGTM.com

fixed alerts:

  • 1 for Dereferenced variable may be null

@@ -48,17 +51,25 @@ protected void doReload(BlockFamilyDefinitionData blockFamilyDefinitionData) {
}

public boolean isFreeform() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isFreeform is a bit strange in this context. never really quite understood the reasoning and how this fit into blockfamilies. at this point it just checks if the block has shapes defined for it. would it be worth deprecating and making getShapes return Optional<ArrayList>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning an Optional in this case wouldn't be better than just optionally returning null. I could just inline this method (it isn't used in many places), but I just kept it like this because block family definitions with the shapes attribute are treated a bit differently from ones without that attribute (the family can vary according to the shape, so for blocks with multiple shapes, the family is given less control over the construction of the block), so it seemed appropriate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between an empty list and null/Optional.empty()?

Change the way the BlockManager is handled in several tests, so that
it is initialised after the block definition assets are set up.
@lgtm-com
Copy link

lgtm-com bot commented Sep 3, 2020

This pull request fixes 1 alert when merging a7f9784 into fe4f808 - view on LGTM.com

fixed alerts:

  • 1 for Dereferenced variable may be null

@Cervator
Copy link
Member

Cervator commented Sep 3, 2020

So I've been meaning to comment on this for a long time, but it feels kinda hard to just sort of mentally eyeball its long term effects. I agree that simplifying the code would help for right now and fix some bugs, but constraining blocks to shapes up front seems limiting long term. For an example the ChiselBlocks module is just a gigantic set of textures in an auto directory (nearly 600) meaning they don't even have .block files. Would it need 600 near identical .block files now, which then set a series of allowable shapes? Imagine just 10 shapes - that's 6k ids. And - 600 files. If somebody then adds 5 cool new shapes to StructuralResources would we have to go edit those 600 files (not even considering other modules) and toss another 3k ids in the pile? 🤔

Is there a way we can add some sort of less lazy loading of block ids, where those we predefine will behave better with this PR, meaning the bug fixes apply and overall quality goes up, but we have an option to expand later, perhaps via a simple server admin / game update utility command that can hard- assign additional ids with the game/server offline, then we have a new static list of ids next startup / client connection? So in that case if there's a cool new shape in SR you want to make available to CB you just go pick it in some sort of listbox of available blocks/shapes?

I'm not personally going to lose sleep over losing functionality if we can see some clear future plan to help regain some lost flexibility, ideally with fewer bugs. I however don't think it is a reasonable permanent position to forego all dynamic block creation/addition, forever. Both options seem painful - more complexity in code, or more complexity in admin. Or less flexibility overall.

Two other related topics / concerns:

  • Rather than just lazy loading how about truly dynamic block creation in-game? Like the pretty mundane concept of shrinking a set of blocks into a single smaller block, fitting into a single blockspace. With some things that would be entity powered you could probably handle that as a non-simple block, but that doesn't scale / go well with primitive blocks you plan to use in large numbers. Or even if a player decides to grow a watermelon inside a spherical shape, forcing it to adopt the blasphemy of roundness (why anybody would attempt such heresy I don't know, but players are weird!). Plus: sophisticated wiring 😱
  • Another (maybe far) future concept is the idea of outright splitting block appearance from function. Has a roadmap card on Trello but isn't actively being worked: https://trello.com/c/w4q4jhza/46-separate-block-shape-function-from-rendering-its-visual-appearance - I don't know if that explicitly gets into block ids / lazy loading completely but it does possibly cover some cases like fences, where the engine might be able to figure out the shape + appearance purely based on block positions in the world. In some cases though you might still want an explicit shape (think a ruined village - would look weird with decrepit fences all perfectly reduced to generic stumps without any orphaned connectors)

Some of that might be reduced to game design choices / target game style. If you can't architect something to your liking just make up an in-character reason to handwave it to a more simple setup :-)

Also sending a ping to @Qwertygiy as I think he's been working on making shapes more complex/flexible

How does Minecraft / Minetest / others handle this, I wonder? Have they just gotten the complexity sorted out? Are we barking up the wrong tree simply because nobody dares dig through the code as-is to fix ugly bugs? That wouldn't be a first, I expect.

Regardless of case and future here I do want to thank you @4Denthusiast for the effort you've put into this. I know it isn't trivial. I just also can't help feeling rather conflicted about it 😕 I really don't want that to reflect poorly on your work - I'm just one person and don't want an out-sized influence on this. I just want to make sure we cover all our bases so the community doesn't wonder a few years down the road why we don't have lazy block ids, with contributors then either having forgotten or never known the pain from this topic.

@4Denthusiast
Copy link
Contributor Author

Would it need 600 near identical .block files now, which then set a series of allowable shapes? Imagine just 10 shapes - that's 6k ids. And - 600 files. If somebody then adds 5 cool new shapes to StructuralResources would we have to go edit those 600 files (not even considering other modules) and toss another 3k ids in the pile? thinking

You would have to include a block file for anything that's not just a cube, but you wouldn't have to update every one of them to add new shapes if they're all based on the same template.

Is there a way we can add some sort of less lazy loading of block ids, where those we predefine will behave better with this PR, meaning the bug fixes apply and overall quality goes up, but we have an option to expand later, perhaps via a simple server admin / game update utility command that can hard- assign additional ids with the game/server offline, then we have a new static list of ids next startup / client connection? So in that case if there's a cool new shape in SR you want to make available to CB you just go pick it in some sort of listbox of available blocks/shapes?

Even in the current state of the PR, if additional blocks become available between game loads (either by additional block files being added or by additional shapes being added to an existing block), they will be added just fine. It's only adding blocks part way through a run of the game that's the problem.

It also sort of sounds like you're suggesting leaving dynamic block allocation as-is, but allowing pre-defined shapes lists for freeform families and eagerly loading at least those for every block so that it's used less often. This would be worse than either extreme, because it has the complexity of both, and systems that require a list of all the blocks still have to take into account dynamic block allocation.

I'm not personally going to lose sleep over losing functionality if we can see some clear future plan to help regain some lost flexibility, ideally with fewer bugs. I however don't think it is a reasonable permanent position to forego all dynamic block creation/addition, forever. Both options seem painful - more complexity in code, or more complexity in admin. Or less flexibility overall.

Two other related topics / concerns:

Rather than just lazy loading how about truly dynamic block creation in-game? Like the pretty mundane concept of shrinking a set of blocks into a single smaller block, fitting into a single blockspace. With some things that would be entity powered you could probably handle that as a non-simple block, but that doesn't scale / go well with primitive blocks you plan to use in large numbers. Or even if a player decides to grow a watermelon inside a spherical shape, forcing it to adopt the blasphemy of roundness (why anybody would attempt such heresy I don't know, but players are weird!). Plus: sophisticated wiring scream

I think that in almost all cases, using an entity for something like this would already be a better option. In the case of shrinking multiple blocks into one composite block, making those actual block types would probably already be more difficult, and would only be much more efficient if large numbers of identical composite blocks were used. The sphere watermelon case would be one example where the existing system (with FreeformFamily) is actually a good fit, but it's quite contrived to be a good fit for the current system, and how many different vegetables and vegetable moulds do you expect to have anyway? Sphere watermelons are plausible, but fence watermelons, torch watermelons and cactus watermelons less so.
In the case of wiring, all those blocks probably already have entities, and if there are so many possible combinations of components that it's unreasonable to pre-allocate all of them (which could even be done by a custom asset loader rather than block files, which is what you'd need for the dynamic block allocation version anyway), there might not be all that much repitition of what combinations are used anyway.

In order to make dynamic blocks like this, you'd also have to transmit the assets defining them to all the clients in advance of registering it with the BlockManager, and similarly you'd have to somehow store these assets and re-load them before the RegisterBlocks loading step, which looks pretty much impossible without making these dynamic blocks an engine feature, because RegisterBlocks is one of the first loading steps.

More to the point, as far as I know Terasology doesn't currently have any features that use dynamic block allocation except freeform families. It seems like it's more of a solution looking for a problem than something that's actually necessary for likely future expansions of the game.

How does Minecraft / Minetest / others handle this, I wonder? Have they just gotten the complexity sorted out? Are we barking up the wrong tree simply because nobody dares dig through the code as-is to fix ugly bugs? That wouldn't be a first, I expect.

It's been a long time since I worked on Minecraft modding, but I don't think they had dynamic block allocation like us at all.

@4Denthusiast
Copy link
Contributor Author

The one remaining test failure doesn't look like it has anything to do with this PR, so I assume it's pre-existing.

@lgtm-com
Copy link

lgtm-com bot commented Sep 3, 2020

This pull request fixes 1 alert when merging 15cecd0 into fe4f808 - view on LGTM.com

fixed alerts:

  • 1 for Dereferenced variable may be null

@Cervator
Copy link
Member

Cervator commented Sep 4, 2020

Yep the flakey replay tests are pre-existing, no worries there 👍

And I do think I probably am missing some of the distinctiveness between different related concepts here, partly why it is hard for me to comment particularly well.

Even in the current state of the PR, if additional blocks become available between game loads (either by additional block files being added or by additional shapes being added to an existing block), they will be added just fine. It's only adding blocks part way through a run of the game that's the problem.

Oh so the block id list essentially refreshes between game loads? That's good to know.

leaving dynamic block allocation as-is

Ehh, I guess I was looking for a way to retain functionality but in a less dynamic way, somehow? Not sure. You're right in that it could easily become a worst of both. I started wondering if it made sense to change the free form family to a very limited set of shapes (full block, slab, a few others) then allow any generic / auto block to belong to that by default, but that's a slippery slope as well.

using an entity for something like this

I wonder - could a hybrid approach work where you can create composite blocks at runtime, using entities, then when the game reloads it can do an optimization pass where primitive new blocks get ids assigned and their entity removed? Then over time you can grow the block list dynamically in-game yet minimize entity bloat

In the case of wiring

Right now IIRC the BlockNetwork approach actually only uses one entity for a whole network, with no entity-per-block for the wires. That may well be a good candidate for that separation of appearance from function thing.

It's been a long time since I worked on Minecraft modding, but I don't think they had dynamic block allocation like us at all.

Interesting - I guess they resolved the block id conundrum some other way? Or just increased the id size 🤔

Thanks for the comments :-)

I'm not suggesting we try to address this perfectly right now, especially if nothing really uses the dynamic allocation at the moment. Just curious what we might think up as a future feature enhancement should it be needed one day.

@4Denthusiast
Copy link
Contributor Author

Ehh, I guess I was looking for a way to retain functionality but in a less dynamic way, somehow? Not sure. You're right in that it could easily become a worst of both. I started wondering if it made sense to change the free form family to a very limited set of shapes (full block, slab, a few others) then allow any generic / auto block to belong to that by default, but that's a slippery slope as well.

Allowing freeform families to take on a limited set of shapes was actually the approach I took in a previous version of this PR. You'd still end up with at least 6 blocks per freeform family (cube, slab, 4 stairs, possibly column, possibly 16 fencepost variants, etc.). Also freeform is currently (without this PR) the default, but even if you changed that, you could still end up with the majority of the block IDs taken up by ChiselBlocks quite easily.

Also, speaking of ChiselBlocks, it would definitely need to be canged if this PR gets merged, but an extraData field would actually be a pretty good fit for it. You could have one chisel block of each shape, and an extraData field specifying the texture (or vice-versa). In a world with, for example, FlowingLiquids also enabled, that data might even fit into the same field as the liquid data (as none of the chisel blocks are liquid, or have any other special properties that would require other hypothetical specific extraData fields), so in that case it wouldn't even take up any extra memory per chunk.

I wonder - could a hybrid approach work where you can create composite blocks at runtime, using entities, then when the game reloads it can do an optimization pass where primitive new blocks get ids assigned and their entity removed? Then over time you can grow the block list dynamically in-game yet minimize entity bloat

This would still run into the problem I described earlier where loading the block definition assets before block registration would be hard to do.

Right now IIRC the BlockNetwork approach actually only uses one entity for a whole network, with no entity-per-block for the wires. That may well be a good candidate for that separation of appearance from function thing.

Even if it's one entity per wire network, there's nothing stopping it from including this information about fancy composite blocks in its network too. If you could fit multiple wiring components (like electrical components, not entity Components) into one block space, the entity that stores the state of all the wiring would still need to store information about each of these components anyway.

@Cervator
Copy link
Member

Cervator commented Sep 6, 2020

an extraData field would actually be a pretty good fit

I've run into that desire several times, particularly with an old idea of tracking aquifers / soil humidity in solid blocks, water level in liquid blocks, and wind strength (or pollutants?) in open blocks. Loooong time ago, that one, and I wasn't sure how efficient it would be vs hassle. The new extra data stuff seems a lot more flexible than in the olden days. Curious what potential there might be there.

Could extra data itself be used for shapes, rather than textures? Paired with an overhaul a la https://trello.com/c/w4q4jhza/46-separate-block-shape-function-from-rendering-its-visual-appearance - one id for texture, one id for shape (potentially leading into some amorphous shapes for things like wires or fences that could be determined based on neighbors). I figure that way we'd suddenly have an immense id range no longer needing to mix the two. But I dunno how that works with the actual block registration and such (even with the two ids separate if you make a new block mid-game that'd still be a "new" combination / block)

including this information about fancy composite blocks in its network too

Fair enough 👍

@4Denthusiast
Copy link
Contributor Author

Could extra data itself be used for shapes, rather than textures? Paired with an overhaul a la https://trello.com/c/w4q4jhza/46-separate-block-shape-function-from-rendering-its-visual-appearance - one id for texture, one id for shape (potentially leading into some amorphous shapes for things like wires or fences that could be determined based on neighbors). I figure that way we'd suddenly have an immense id range no longer needing to mix the two. But I dunno how that works with the actual block registration and such (even with the two ids separate if you make a new block mid-game that'd still be a "new" combination / block)

Yes, an extraData field could be used for shapes. If you mean doing that just for ChiselBlocks, it would be a bit awkward in that you'd have to re-implement some of the existing behaviour of block families (e.g. placing stairs in the correct direction depending on how they're placed), which is why I suggested putting the texture in the extraData field instead, because that would be a bit simpler.

In either case, changing the rendering of a block based on its extraData values is currently quite awkward. I feel like the BlockMeshGenerator ought to be changed at some point to make things like this, or changing the rendering of fences based on their surrounding blocks, more convenient.

If you mean storing the shape of every block in the world in an extraData field, that could work, but it seems a bit over-the-top. It would make things like the SupportRequiredFamily more complicated, because they'd have to keep the shape in sync with the block ID, which determined the functionality.

@Cervator
Copy link
Member

So we discussed this some during the office hours today and I'm hoping to get some more feedback written up here on the PR, pinging some maybe relevant contributors: @pollend @skaldarnar @jdrueckert @keturn @casals @DarkWeird

I've written up a bunch of stuff above already, including several of the potential mitigation ideas to retain some of the benefit the current code gets us. To summarize that, the discussion points, and other related topics here are some bullets:

  • In a nutshell this does away with the lazy block id allocation for a variety of benefits. I don't think anybody is suggesting we preemptively assign all possible combos - we'd run out of id space fast and that just isn't efficient (most ids would go unused). We would use explicit block+shape combos to assign a larger-than-current number of ids - but how do we balance against a good target?
  • When the game starts if modules have been updated and have new blocks they will be assigned new ids (so you can expand the block id series at game restarts then send the full new list to clients as they connect)
  • StructureTemplates at present define block+shape combos on the fly. This wouldn't work and you'd need block files for every combo used (or technically: block files for all involved blocks that then include lists of all shapes supported)
    • A one-time conversion could probably be done that'd read an ST then write out the needed block files
  • Rather than try to mitigate against the block id concept as it exists today could we consider alternatives that leave the shapes and appearances up to some alternative system? Could block id just be the base block type with some of the additional metadata like shape stored/processed elsewhere?
  • Possible mitigation: Would it make sense to parse out in-use combos from more than just .block files? Parsing STs during game init, for instance, then figure out which blocks+shapes are needed. This is likely to be brittle and would get into which things we should parse
  • Possible mitigation: Would it help to have an external editor that could work as a creative mode BlockPicker purely for experimenting / preparing needed block lists? So no ids, but just a way of visualizing a StructureTemplate and both write it and all needed combos out. Again probably both brittle and not super helpful as any sort of primary editing mode (it could be a handy tool, but not a great replacement for being able to build in-game)
  • Possible mitigation: Use temporary entity-based methods to allow for new block combos in-game then process them into new block ids during game restarts (until the restart they'd be a given block id known to have entity-based metadata needed for rendering). Adds complexity for sure, could possibly also support new features that the current code does not (editing faces of a given block, creating new shapes for instance by shrinking a block selection into a single blockspace). Would allow full creative style editing in-game and more at the cost of complexity and eventually (without restarts) performance

I know none of the mitigating ideas or alternatives give us great options right now and some will likely add substantial effort. In the perfect world where available effort isn't a hindrance I'm drawn to the option of dynamic blocks that are all marked by the same unique block id which would instruct rendering to fetch details from an entity associated with that block position (which I think might already be the case with block type entities?). You'd end up with one entity per unique new dynamic block, which would probably hold a component with a list of all positions that block has been placed (or there'd be some other sort of cache somewhere)

Partly I'm drawn to that option because it is an old idea - I've been shopping around the idea of "composite blocks" for years (see https://trello.com/c/zkMdfjDz/45-composite-blocks-multiparts - which was written long after the concept originally arose) without any relation to lazy loading. That concept would potentially both buy us new functionality and allow us to discard lazy loading of ids for all the benefits this PR brings us.

STs that contain block combos lacking existing ids could probably just provision dynamic blocks on the fly.

During game restart as the game parses its save file and modules it could both look for new block assets as well as any entities representing dynamic blocks and allocate them ids as well, then update the chunk files with the new ids, before starting up. That'd probably be a new phase of some sort that I suspect we'll need eventually anyway (imagine updating an existing world with new module versions but there are conflicts of some sort an upgrade tool would need to help with)

Maybe we could even get to the point where a maintenance task could run live on a server and do a one-time refresh of the block id list to clients, rather than try to get lazy loading working everywhere, but I acknowledge that might just be tip-toeing back toward the original problem ...

@skaldarnar
Copy link
Member

Heh, this is a tricky topic, and I'm commenting just based on the discussion (didn't look at the code yet). Some interesting aspect have already been brought up, some others are missing… To start off, I may need a glossary for the terminology used all around blocks. Maybe you can help me filling this in…

  • Block - commonly used to refer to some form of object that can be placed in the world, occupying at most a single block voxel. can also refer to the block definition, the representation, anything really… easy to mix up
  • Block Definition - how the block is defined (a prefab in JSON). Defines how the block will be rendered and how it behaves in the world. we have special auto blocks without dedicated block definitions, they are created from simple block textures and some default configuration
  • Block Template - blocks can be basedOn another block, inheriting its properties. references another block definition.
  • Block Id - each block is identified by an id (currently a short?). This id is not fix, but determined separately for each game. currently the block id precisely describes the full block representation, including shape, texture, and rotation.
  • Block Shape - the shape of a block, 3D object modelled in Blender or the like. Used for creating the mesh for in-game rendering. Rotations of the shape are defined via block family. The set of block faces is pre-defined, but can be mapped freely on the shape.
  • Block Texture - which texture(s) to apply to the block's shape. there can be a separate texture per block face. we currently do not support texture variants for a single target face.
  • Block Family - determines which rotations are available for a block. also defines how the block placement behaves. needs to be explicitly set in the block definition, cannot be used dynamically. also related to hiding that many block ids belong to the same family.
  • Block Representation/Rendering - how the block look in game. mostly interesting for cosmetic and game play reasons. related to block families in the sense that players should not be aware that rotations or shape variants are actually separate blocks.

One thing I'm particularly worried about is how the migration after this change is going to work out. Who feels responsible for updating all structure templates, changing all modules, figuring out which blocks should be available in which shape, etc. …? I'd appreciate some small PoC, maybe with Lost and the STs defined in there.

On the same note, I'm wondering about the best practices evolving from this. How are blocks defined, how are we going to use templates, and are we sure that delta prefabs and overrides are working correctly in all scenarios we can envision? What does the structure of block inheritance look like (e.g., stone <- cobblestone <- mossy-cobblestone).

Furthermore, do we have a way to define optional delta prefabs in some way? How can two modules that don't know about each other be combined? The figure below uses the cheese block from FunnyBlocks and the pillar shape from StructuralResoucres as example, but this could actually be anything. To avoid unwanted module dependencies I think we currently would need to introduce a now augmentation module for every combination we want to add 😕 This can easily lead to bloated module space if we're not careful here…

The talk on extra data directly relates to untangling block rendering from block ids, doesn't it? I'd like to avoid custom solutions for some modules, but would rather like to take the opportunity to think about general solutions here. Varying the texture of a single block type has come up before (e.g., different grass path textures, or connected textures for larger areas of the same block type). Similarly, varying the shape depending on the block's context came up before (e.g., determining the exact shape of a fence or wire block, or connecting stairs placed around corners). If we work on some support here we should keep an eye on the full picture to fit everything in.

(credit to @jdrueckert for the figures)

@4Denthusiast
Copy link
Contributor Author

4Denthusiast commented Oct 20, 2020

Heh, this is a tricky topic, and I'm commenting just based on the discussion (didn't look at the code yet). Some interesting aspect have already been brought up, some others are missing… To start off, I may need a glossary for the terminology used all around blocks. Maybe you can help me filling this in…
* Block Family - determines which rotations are available for a block. also defines how the block placement behaves. needs to be explicitly set in the block definition, cannot be used dynamically. also related to hiding that many block ids belong to the same family.

One small correction: In many cases, the block family does not need to be explicitly specified. If the shape is rotationally symmetric (including the case where it's not explicitly defined and defaults to the cube shape), the family defaults to the SymmetricFamily, which contains only one block, and if the shape isn't symmetric (e.g. stairs), it defaults to the HorizontalFamily, which has 4 blocks: one for each horizontal rotation.

@skaldarnar
Copy link
Member

One (or maybe two) more thing(s) coming to my mind is that having a bunch of new block definitions kind of requires a good naming scheme for them. We touched at that with some special blocks for HjerlHjede some time ago (camel case vs snake case vs ...). This may seem benign, but I think it's rather important to not end up with woodenStair, wood_stair, and stair_wood in different modules.
The second point is - can we slowly work towards this, regardless of whether we merge this PR or not? Add more craftable blocks (like stairs with correct rotation behavior), actually integrate StructuralResources into the game play apart from pre-generated structures, ...

# Conflicts:
#	engine-tests/src/test/java/org/terasology/world/ChunkViewTest.java
#	engine-tests/src/test/java/org/terasology/world/generator/InternalLightGeneratorTest.java
#	engine-tests/src/test/java/org/terasology/world/propagation/BulkLightPropagationTest.java
#	engine/src/main/java/org/terasology/world/block/family/FreeformFamily.java
@lgtm-com
Copy link

lgtm-com bot commented Feb 16, 2021

This pull request fixes 1 alert when merging 4441796 into 46bf9eb - view on LGTM.com

fixed alerts:

  • 1 for Dereferenced variable may be null

@skaldarnar skaldarnar added this to the v4.3.0 milestone Feb 18, 2021
@keturn keturn modified the milestones: v4.3.0, v4.4.0 Mar 14, 2021
@jdrueckert
Copy link
Member

@skaldarnar skaldarnar added Breaking Change API breaking change requiring follow-up work in dependant areas Topic: Architecture Requests, Issues and Changes related to software architecture, programming patterns, etc. labels May 23, 2021
@jdrueckert jdrueckert removed this from the v5.0.0 milestone Jun 12, 2021
@jdrueckert jdrueckert marked this pull request as draft June 12, 2021 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change API breaking change requiring follow-up work in dependant areas Topic: Architecture Requests, Issues and Changes related to software architecture, programming patterns, etc. Topic: Stabilization Requests, Issues and Changes related to improving stablity and reducing flakyness
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Client unable to trigger block-family registration.
7 participants