Component System and Minecraft

Why not write your own system?
But, yes …
How can we inject existing systems?

You cann access it over the system (manager store it):
https://github.com/SpongePowered/SpongeAPI/blob/component-system/src/main/java/org/spongepowered/api/component/ComponentSystem.java#L78
ComponentSystem

Collection<H> getAll();

I’m sorry, but the system does not store the components. It just works with them. The ComponentManager or the ComponentHolder (not quite sure yet) stores the instances.

That’s not right, “H” refers to “holder”, it’s just a collection of entities, not components.

I think it should be the Manager, as it makes it easier to handle saving and loading of component instances.

What about this?

Well, for now the plan is that we just provide the API - it depends on the implementation how to store the data directly.

If you want to create a custom mod that adds a few new components you might want to think about how to store them. Since we probably wont have a meta-data system, but a component-based system I am sure that there’ll be an implementation (like NBT) that can add new data to entities.

In the end it really just comes down to you; Whether it’ll be a text-file, just fields or something else.

Just a question(s)…
Lets say i want to add mana for each player.

  • i start by creating a mana component

    interface Mana extends Component {
    public static ComponentKey key = new blah…
    double getMax(); double getCurrent();
    void setMax(double d); void setCurrent(double d);
    }

then i will need to create ComponentManager for my mana thing

class ManaComponentManager implements ComponentManager <Mana> {
          <overrided methods>
}

when player joins the server ill call method

componentManager.addComponent(H holder, Mana.key,<object which implements mana interface>);

where holder is the player object

if i want to handle all mana changes “manually” (eg.: on command) then my componentsystem must return always false in method boolean shouldProcess(), but if i will want to create for example manaregen then my best friend is going to be method void process(H holder, float dt); which is called on every game tick?

which class will hold an instance of my componentmanager and componentsystem.
am i guessing right that componentsystem must be registered into some kind of tickhandler in minecraft. And how about concurrency. Is it going to be threadsafe access/add/remove components from another thread?

(im bad at writting pseudocode :/)

No! You make a component manager for entity types, not one every component.

Use the component manager already linked with the player:

Entity playerEntity = server.getPlayer("Notch");

ComponentManager<Entity> componentManager = playerEntity.getComponentManager();

componentManager.addSystem(new ManaSystem(), ManaSystem.class);

componentManager.addComponent(playerEntity, new ManaComponent());
//or instead of that:
playerEntity.addComponent(new ManaComponent());

I have pushed another big change to the spec (I’m sorry FAQ writers, truly!).

I’ll quickly break down some concepts (much more indepth doc coming soon), bottom up

GameObject - Any object in an engine. Minecrat is our engine and we are focusing on Entities (with Blocks and Items to follow)

Component - Simply a data holder. Plugin devs extend this to add their own attributes to a GameObject

ComponentSystem - An object whose job is to take a filter of Components and compile together a list of GameObjects that fit this filter. Only these objects get processed by…

ComponentManager - An object whose job is to register ComponentSystems as well as track which Components are on which GameObjects. Typically a World or Game has a ComponentManager and they pass off GameObjects to be processed to the system (if they meet the filter)

From a plugin developer’s prespective, you will get in the habit of making Components, attaching them to Entities/etc (myEntity.addComponent(myComponent)) and creating a system to do something with those Entities/etc if they have your Component. You can manually process your system or let Minecraft do it each game loop (from the ComponentManager in World).

You can even get much more intricate and define your own ComponentManager for your own custom game objects! By default, we’ll give your classic Entity, Block, and Item their own ComponentManagers per World but if you add your own object to the game (dunno what it would be), the API lets you control the ENTIRE process.

Last but not least, the latest spec allows you to attach multiple of the same Component (such as Inventory) with your extended versions! In example, a Player would have an Inventory for their typical Player inventory and one for an Enderchest version.

2 Likes

Couldn’t this also be a method of implement something like this:

EDIT for clarification:
I am thinking about unity/engine like scripting functionality

1 Like

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.