Question about designing an Entity Prefab (Blueprint) System


#1

Hi it’s me again… :slightly_smiling_face:

Suppose you have a character entity, you add physics components, name component, model info, stats, and so on… to it in editor. Now you want to be able to create a prefab (blueprint) from that entity so you can reuse it in game and be able to spawn it by it’s name.

For this, I serialize my entity to a json string using Gson library. I have a PrefabSystem, which can get an entity and check for all components that entity has and retrieve all components and serialize that array of components to a json string.

My first question is, is this an anti pattern to check for all available components on entity ? because my prefab system does not know anything about entity, it just gets an entity ID and tries to get any component it may have.

My second question is should I save this json string in my ES database or into a file ?
I mean should I create a entity and add a JsonString component to it and put the json string in that component or I should save it to a file ?


#2

Well, yes… generally this is not an answerable question. Probably you only really wanted a subset of “all possible components in the universe” anyway.

We like to do these things because we think it saves us time: avoiding adding a class name to a list somewhere… in the end, the other approach has a dozen traps and pitfalls that one will constantly work around. just to avoid typing a class name.

I’ve seen it again and again in various types of systems… not just an ES. All of this engineering to avoid a very simple alternative.

I’d also question the whole approach. Where did this entity come from in the first place that you are trying to make a prefab of it in JSON?


#3

Possibly relevant? thecodelesscode.com/case/167


#4

I create it in an editor gui at runtime dynamically. Each system has an editor gui (and an RMI service) which let me to add/edit/remove components provided by that system.

At first using a ModelPrefabEditor (and its RMI service ModelPrefabEditorClientService and ModelPrefabEditorHostedService) I create an entity with a ModelInfo, a SpawnPosition, an Interactable (this will make it clickable by mouse) and a Name component.

Then using PhysicEditor (and its RMI service PhysicEditorClientService and PhysicEditorHostedService) I can add/edit/remove physics components and collision shapes to it.
And in the similar way an StatEditor,… .
Beside that I can create/modify entity at runtime and see the result at the moment this is also user friendly to do it through a gui .

Finally after finished with editing I return to prefab editor and click on “Save As Prefab” and the result is gathered in a PrefabModel object

public class PrefabModel {

    private List<EntityComponent> components;
    private List<PrefabModel> children;

    public PrefabModel() {
        this.components = new ArrayList<>();
        this.children = new ArrayList<>();
    }

    public PrefabModel(List<EntityComponent> components) {
        this.components = components;
        this.children = new ArrayList<>();
    }

    public <T extends EntityComponent> T getComponent(Class<T> classType) {
        return (T) components.stream().filter(type -> classType.isInstance(type)).findFirst().get();
    }

    public List<EntityComponent> getComponents() {
        return components;
    }

    public void setComponents(List<EntityComponent> components) {
        this.components = components;
    }

    public List<PrefabModel> getChildren() {
        return children;
    }

    public void setChildren(List<PrefabModel> children) {
        this.children = children;
    }

    public EntityId clone(EntityData ed, EntityId parentId) {
        EntityId clone = ed.createEntity();

        components.forEach(component -> {
            if (component instanceof Buff && !parentId.equals(EntityId.NULL_ID)) {
                Buff buff = (Buff) component;
                ed.setComponent(clone, new Buff(parentId, buff.getStartTime()));
                return;
            }
            
            if (component instanceof ItemBuff && !parentId.equals(EntityId.NULL_ID)) {
                ItemBuff buff = (ItemBuff) component;
                ed.setComponent(clone, new ItemBuff(parentId, buff.getDecay()));
                return;
            }

            ed.setComponent(clone, component);
        });

        children.forEach(child -> child.clone(ed, clone));

        return clone;
    }
}

I give it to Google’s Gson library and get a JSON string out of it. :slightly_smiling_face:

Yes, I am registering all prefab components at game server, and PrefabSystem uses it to retrieve component from entity when creating a PrefabModel.

protected void registerPrefaComponents(PrefabSystem prefabSystem) {

        prefabSystem.register(ShapeInfo.class, 
                Mass.class,
                Buff.class,
                ItemBuff.class,
                BoxShape.class,
                SphereShape.class,
                CylinderShape.class,
                CapsuleShape.class,
                Terrain.class,
                TerrainBlock.class,
                BridgeBlock.class,
                BlockInfo.class,
                BlockJoint.class,
                ModelInfo.class,
                Name.class,
                SpawnPosition.class,
                Interactable.class,
                EntityTag.class,
                Stat.class
        );
    }

Ah Yes, I can do this at editors hosted services, when I set the component on entity I can also add that component to the list (I mean not the component class name, but the component itself) in PrefabModel object. Do you mean this ?

Edit:
So when I click on that “Save As Prefab” button, I already have the PrefabModel object ready and I just need to serialize it to JSON with Gson.


#5

@pspeed any thoughts. :slightly_smiling_face:

Anything is unclear ? Anything seems wrong to you ?
Are you agree with exporting to JSON ?

I am yet struggling with second question.


#6

Is it game data? Will an NPC pick it up?


#7

Not sure what you mean, it’s a prefab. I will use it to generate an entity and spawn it to scene.

No.


#8

Got what you mean. I will save it to file.


#9

So it’s like a jpg or a png or a j3o…

Do you store those in your game data database? (ie: the ES)

Edit: your reply ninja’ed mine.


#10

Wait, they are not visual stuff like j3o.
They are server side data. So they should be saved somewhere in serve side.
But they have nothing to do directly with ES systems.


#11

So could j3os if you are using them for physics meshes.

You’ve gotten my point, though.


#12

This might be off topic but this is how I handle my prefabs when users use parts to assemble a space ship. The ship’s total stats are saved as linked entities and a modelPath of a dynamically persisted and serialized .j3o containing a series of AssetLinkNodes is saved against the ship entity. This allows me to do stuff like in the video below and separate the data into the ES system from the visuals of the ship that the client uses.