Dynamically creating blocks from prefabs

Mike Kienenberger

Active Member
Contributor
Architecture
GUI
I admit it -- I don't get it.

The minion code creates new blocks:
Code:
                        Block newBlock = blockManager.getBlock("miniion:OreonPlant0");
                        worldProvider.setBlock(new Vector3i(currentTarget.x, y + 1, currentTarget.z), newBlock);
from the following assets, OreonCrop.prefab
Code:
{
    "OreonCrop" = {
        "stages" = 7
    }
}
and OreonPlant0.block
Code:
{
    "author" : "overdhose",
    "basedOn" : "core:plant",
    "entity" : {
        "prefab" : "miniion:OreonCrop",
        "mode" : "persistent"
    }
}
Then attempts to work with the block later on, but the block is either missing a BlockComponent nor LocationComponent or it will not update properties on OreonCropComponent.

So I added to the prefab the following, hoping unrealistically that this would make a difference (as I'm not sure why defining these on a prefab would magically cause them to get populated rather than being intrinsic components of the block or prefab)

Code:
,
    LocationComponent : {},
    BlockComponent  : {}
Still not much help.

When I start a new game and try this out,

Code:
        for (EntityRef cropEntity : entityManager.getEntitiesWith(OreonCropComponent.class)){
I only get
Code:
EntityRef{id = 114, prefab = 'Miniion:OreonCrop'}
However, changes to 114's OreonCropComponent properties are never saved, even when using cropEntity.save(cropComponent);

If I save the game and reload, I suddenly have two of these:
Code:
EntityRef{id = 113, netId = 0, prefab = 'engine:blockType'}
EntityRef{id = 114, prefab = 'Miniion:OreonCrop'}
113 will save changes to the cropComponent properties, but never has a BlockComponent or LocationComponent.
114 won't save changes to the properties, but always has the components.

113 seems to be created by

Code:
                        Block newBlock = blockManager.getBlock("miniion:OreonPlant0");
and 114 by the following line of code
Code:
                        worldProvider.setBlock(new Vector3i(currentTarget.x, y + 1, currentTarget.z), newBlock);
I've been trying to debug this for several hours, so my apologies if some of my data is wrong or swapped or incomplete. What I do know is that the current setup does not have both a location-providing component entity and a modifiable crop component entity at the same time. At times, I seemed to have actually found a couple more odd variations of the entity being created, but I did not save that information.

No doubt there is something lacking in my understanding of blocks and prefabs.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
Ok, one thing you need to know is there is an entity for each block type. This is used for sending bulk block load/unload events to when a chunk is loaded/unloaded. So that would be 113. It never has a Location or Block component, because it isn't a block. You shouldn't otherwise need to worry about that one.

In general blocks entities are a little special, given that we have to be careful to avoid having them whenever possible (because there's just too many blocks). They way they behave could undoubtedly be improved upon. Anyway, the root of your issue is that

Code:
"mode" : "persisted"
does not do anything anymore. Instead you can either add the property

Code:
"keepActive" : true
Or mark the OreonCropComponent with the @ForceBlockActive annotation, which will cause any block with that component to be kept active. Without this the block entity will be erased at the end of the frame and then recreated as needed.
 

Mike Kienenberger

Active Member
Contributor
Architecture
GUI
Thanks! I suspected that 113 was a prototype/archetype since it had the Component BlockType attached to it.

I also gathered that blocks did not support components very well from all of the block-specific hard-coded properties that they have.
"grass"? really? as an engine type? :)

Are there any concepts in the works for allowing blocks to have true components? Maybe at least as a property of the prototype block which currently has a BlockType? One of the things I was looking for was a way to identify all "core:plant" blocks. I understand why I can't look it up as a parent prefab (that information is only available during loading of prefabs), but there probably should be a way to figure out that something is a grass block without adding "boolean isGrass" to the Block.java file :) -- or a plant. Maybe this is already possible with the prototype block as I haven't had a chance to look at Terasology development since I read your message.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
I have thoughts but no time to implement them. But basically it would be much as you imagine - block definitions would become special prefabs, and most properties split out into components. Some properties would be renamed - such as grass, which actual enables a specific type of rendering (nothing to do with it being flora).

You can use categories - these are string labels that can be axded to a block.
 
Top