Component System and Minecraft

I would love that, it would make a lot cleaner when a component of an entity reacts to an event without needing to make an event listener that gets fired for all entities that invoke that event.

1 Like

awesome. nice work!

:thumbsup:

Since the component system takes shape: Any thoughts how you want to save and load components of entities?
The values need to be saved too! (e.g. health).
Save it in the server world data? Or seperately, each plugin itself?

I thought about that, wanted to make a separate “Persistence API” topic for this.


Minecraft Stuff like health can be stored in world save.

Custom plugin data can be stored in a database, config file or just be temporary?


The real issue is how to detect a change:

//saves all components of an entity
componentManager.save(Entity entity);

//saves a specific component
componentManager.save(Entity entity, Class<C> clazz);

There is no code for saving and loading in the component class (so it’s easier to re-use a component like Velocity).

That means you need a load, save, and maybe a delete method…


And a way to register a DataStore class in componentManager. The DataStore would handle saving and loading,

// a source where the component is loaded from
componentManager.addComponentSource(ComponentSource<C> source, Class<C> clazz)

// a data storage. called on dataManager.save(...);
componentManager.addComponentStorage(ComponentStorage<C> storage, Class<? extends Component> clazz);

If it is planned to allow blocks to have components (even though by default they wont for performance reasons), what about giving chunks and worlds components as well?

Had a discussion with @OvermindDL1 and @API on the IRC. OvermindDL1 mentioned something which I thought made actual sense.

Lets say for instance there was a huge component A. When I call one method in there it has to load up the whole Component and when you do this for multiple entities it just goes urgh…

On the other had if you had something like doAction(Entity entity); and have some sorta way to store all the entities which have the attribute of component a inside the component. You wouldn’t have to load up the Component per entity.

I have have not explained it perfectly but i hope it makes sense. OvermindDL1 will probs come on later to clarify this

First of all, components should not be large. Second of all, components do not have logic. They only store data. Systems will handle the logic. Systems will only run on entities which have the components that are selected in the System filter(I assume the implementation is going to maintain lists of entities instead of trying to filter every tick for speed reasons).

Also, regarding java, it doesn’t really matter how big objects are memory wise. There is no “loading” of objects that is affected by its size. If this were a language where you had more control over the memory layout, then there would good ways to optimize this further by only having Systems affect 1-2 components and keeping those components next to each other in contiguous memory layout. This would allow you to reduce the amount of cache misses because the data next to the component is also loaded from memory because of the cache line size. But in Java you do not have any control over memory like that, so that is an optimization that is sadly not possible.

Yes normally there is no loading because java uses the references.
Nevertheless there is one case: Loading and saving from the file system e.g. when a chunk is saved/loaded.
But I hope this will happen asynchronously.


[quote=“boformer, post:106, topic:76”]
The DataStore would handle saving and loading,
[/quote] :thumbsup:
Maybe more like two things Handler + Store + StoreComponent.

public interface DateStoredComponent {
  public void writeInt(int v);
  public void writeFloat(float v);
  public void writeString(String v);
  ...
  public int readInt();
  ...
}

public interface DataStoreHandler<T extends Component> {
  public void onSave(DataStoredComponent data, T component);
  public T onLoad(DataStoredComponent data);
}

public class ComponentStorage<T extends Component> {
  public void save() {
    ...
    for(T c : this.components) {
      this.dataStoreHandler.onSave(new DataStoredComponent(c), c);
    }
    ...
  }
}

Just an idea how it could be done. :gift:

So, are we still having ComponentHolders? or is that now handled by the ComponentManager. What I really should be asking is: do the components have a link to their Entity?

Components have no need to know their “holder”

ComponenManager and ComponentSystem both know the holder and moreso ComponentSystem as it does the logic.

Right right. I keep forgetting about the logic being handled by the ComponentManager/System. If for instance, I want to damage an entity, is Sponge going to have a damage type system, like DamageType.PHYSICAL, MAGICAL, POTION, etc.?

Damage type system is completely unrelated to components.

But yes, probably. I really hope so, and even better would be not use enums.

Yup, identifiers seem to be a general good replacement for all things enum. for the damage reasons we can use “minecraft:physical”, “minecraft:something”, … and mods can add their own (by a spell, …).

Definitely not looking to have enums again. I was meaning to have some sort of public class DamageType that can be extended to provide more custom ones (allowing for some object identification rather than a string).

What I can imagine having is a Damage component that takes arguments like so: damage(double damage) (this will default to DamageType.PHYSICAL), and damage(double damage, DamageType damageType).

This would work with most entities even without having health since the System will handle whether the entity has health or not (think ItemFrames, they take damage and ‘pop-off’ but they do not register as having health).

EDIT: @spaceemotion @bensku @Zidane What I’m talking about is something like this: gist:93fc7bbdada07c756cdd · GitHub

3 Likes

this is nice…i want it :x

and also bukkit had a strange issue with damage type lava, if was combination of 2-3 (if i remember correctly it was a mixture of fire, fire_tick and contact…it was pretty annoing)

I think you can replace the “minecraft.damageType.something” with “minecraft:something”. If we want to look up a damage type, we know its a damage type - imo its not needed to specify that again.

I don’t really see why you have damagetype in the component. Also, you have methods like dealDamage that use it which sounds like logic which does not belong in the component.

Both those things belong in a system.

And finally, if you look at the PRs and the component-system branch, then you can see that there is already a Health component which holds the hp and invul state.

oh man, was just writing that haha.

I was writing about how we would implement a damage system. Tbh, I don’t even know how to do this. There are just too many options: If we have a health component, why not put it in there? But what about entities that have no health, but can be damaged (paintings, anvils, …). How would a system even calculate the damage?

@Zidane Any ideas?

The hard part will be syncing it up with the MC system. It would be relatively easy to override the vanilla code completely and write our own damage system, but that has the downside that it would need to be updated with every MC version. The other option is to just have the damage system being reactionary to the vanilla system and that it would only update components, but not do the calculation itself. Which would have the downside that it would be harder to override/change.

These would have their own components and systems taking care of that. The normal damage system would only affect the Health component and thus not affect these objects at all.

Thats what I thought as an alternative, yea.