Now the question I have is should it be entity.get(“component”) or entity.get(Component.class);
I guess i will just post my thoughts I already posted on github about this here:
I personally prefer the component based entity system. Maybe cause I am a fan of the whole non-OOP design approach in this case. You can read more about the system here on the site: http://entity-systems.wikidot.com/ or look at java-examples like Artemis or Ashley (based on Artemis and LibGDX, github.com/libgdx/ashley).
The class one. Strings are like magic numbers, only more complicated.
The component system sounds really powerful and I like it a lot!
It would make it so much easier for plugins/mods to extend/add functionality to the existing entities/objects. I would go with the componentHolder.getComponent(Health.class) method since it avoids “cast guessing”.
The fact is, MC doesn’t currently use a component system itself so the idea isn’t as sound as it seems.
Sure, this definitely makes support for custom mobs either, but would about vanilla clients? How would they react to being sent only partially complete or mixed up entity data?
Or are we working on the premise that you can only play on servers with Forge installed?
I’m a big fan of the Entity Component system, but not sure how compatible it is until Minecraft’s actual system changes.
Willing to be proven wrong!
After thinking about this for a while, I don’t like the idea of having the entities themselves be able to get their components. It should either be static on the component or on another class. This way we’ll be able to manage context of entity component systems, which I think could be useful. E.g with what was previously suggested
Only allows for one semantic ‘context’. Meanwhile, if we do:
context.get(entity, Component.class);
This will allow for different semantic ‘contexts’ isolated from mod to mod that may not be useful for the server. So the server will have a context:
server.context.get(entity, Health.class).getHealth();
And a plugin can have a context of its own:
ComponentContext cc = new ComponentContext();
cc.set(entity, new Health());
cc.get(entity, Health.class).getHealth();
Alternate names could be ComponentSystem
, etc. And in addition, it would also manage entities and such, and would have an APi like:
cc.getEntity(myUUID);
cc.getEntities();
I think that would be a perfect abstraction in terms of dealing with the component system in-game.
Entities and Components have no logic
→ they did not init themself
Please read my last post,
You describe the system aspect
(Missing in the first post)
The problem I see with this is that you will have multiple instances of the health component attached to the same entity. One Plugin will change the health in its own context but the server won’t know.
I would stick with one unique content instance on the same entity to avoid confusion and strange behavior
The system has also drawbacks:
- inter system communication
- we need a good data structure to grab the components for each entity
Yes, that’s the point. It’ll allow plugins to store their own data on the entity without the server knowing. If they wish to update the data so the server knows, they simply use the server’s context. There is absolutely nothing that a plugin can do in its own context that the server can see.
For instance, adding a health component in the plugin’s context and setting the health will not set the health in the server’s view, because it’s not the same context. That make sense?
The reason you would want to do this is for separation and testing. Anything that can further abstract out the server from its implementation.
- This brings up a good point. If we have contexts, we should tie events to the contexts of the component system, and this would be a super-interesting feature. That would solve the problem of inter-system communication in a super-clean elegant way…
- The data structure is as proposed. Either using contexts, .get(Component.class), or something similar.
Really hope this will be used.
Just like Unity assign some components to a object and you create something custom.
And yeah please go for the .class instead of string.
Love the feedback, keep it coming!
game.getSystem(HealthSystem.class).get(entity).setHealth(10);
This allows a plugin to define its own system. setHealth would fire off an event…?
Throwing out ideas based on above…
API:
interface Game {
<T extends ComponentSystem> getSystem(Class<T> clazz);
<T extends ComponentSystem> registerSystem(Class<T> clazz);
}
interface Component {
Game getGame();
}
interface ComponentSystem<B, C extends Component> {
C set(B instance, C type);
C get(B instance);
}
interface Health extends Component {
double getHealth();
void setHealth(double value);
}
Impl:
class HealthImpl implements Health {
private double health;
public double getHealth() {
return health;
}
public void setHealth(double value) {
this.health = health;
}
}
class HealthSystem extends ComponentSystem<Entity, Health> {
public Health set(B instance, C type) {
// Set in the system if not present or overwrite?
return health;
}
public Health get(Entity instance) {
// Check in the system if the entity has health...
return health;
}
}
Bring on feedback!
(Generics are probably not right sooooo)
Oh so now you’re talking full on separate components and using systems at the end of a tick to sync Minecraft and the components. I was thinking of just having the components for now which directly chain to Minecraft internals when modified. Basically pretending we have components when we really don’t. I’ll have to think on that one some more.
As far as some of the other posts having different contexts makes no sense, let’s not do that. As far as plugins adding their own components, that’s tricky because we don’t have a good way of serializing them so it’d basically be Bukkit’s Metadata again. Finally as far as plugins adding their own systems, that’s kind of the point. Your systems, if properly defined, will work on any new entities (added by mods, for example) that match your criteria without having to do extra work to detect them. Makes things more flexible and future proof.
On systems, I’m not sure I understand why you’d get the system and call something on it. Only the server itself should be making any calls to systems, plugins should be modifying components.
@components-access
Maybe,
but Components are only “data driven accessors” used by the systems …
If you change data direct in the components, it is like changeing a field/member of a object directly over reflection (or because it is public).
The system can not react …
Systems create and manage Components …
If you create a CustomComponent, you also need a CustomSystem that load, save, create, the components …
If we’re going to do real Components and not just proxies then we should do them right. Each Component has three copies of its data: previous tick, current tick, next tick. Modifying the component only modifies the next tick values. Systems should only do anything once a tick so calling them directly is weird.
I like the tracking of data idea … (previous, current, next)
Not sure if that put to much logic in the Components …
Should an API not hide this system?
Also everything can change anything silent…
Last Caller wins?
If you use the system, we can trigger events, inform other systems, …
(debug, track, …)
I’m not sure the semantics you have here, but it seems like there’s one System per component? To me that seems verbose, very not DRY, and honestly not really necessary.
I created a gist that compiles and runs fine, just as a quick test. Here’s a summary of what the interfaces look like:
public interface Component<H> {
public H getHolder();
public void setHolder(H holder);
}
public interface ComponentHolder<C> {
}
public interface ComponentSystem {
public <T extends Component>
T lookup(ComponentHolder<? super T> holder, Class<T> clazz);
public <T extends Component> boolean
has(ComponentHolder<? super T> holder, Class<T> clazz);
public <T extends Component> void
remove(ComponentHolder<? super T> holder, Class<T> clazz);
public <T extends Component> void
register(ComponentHolder<? super T> holder, T component);
}
The best thing is, the whole thing is completely typesafe, and without much reflection magic! I may consider ‘duplicating’ the ComponentSystem api over to individual ComponentHolders.
Imo the different components should only hold the data. A system then can see if the value got changed and updates the data (sends updates to clients / server). This should be completely up to the author; A health component would also have a health system that then sends the proper packets. A custom implementation might use the Plugin channel for that - the “serialization” would be up to the developer then.
Great example,
and yes …
Not every Component need a system
In that way mods, plugins can set custom data for each entity and react as they wish …
We can also add debug components without any systems …