Aaah! I want to be really careful here, what do we mean by “serialization is up to the developer”? Does that mean we have to have 80 connections to a MySQL server again? Because I hated that part of Bukkit metadata. Component systems hit all my separation-of-concerns buttons, I love this idea. Please, please, please give us a switch to just make this data persistent!
RemoteEntites try this …
It is very hard to implement a typesafe, performant, generic persistent layer …
Correct! Which is why asking every plugin that needs to use this data to do it is suicide for plugin quality.
Then let’s break it now when there’s not too much to break. It’s simply the better system. Former Bukkit developers will adept to it.
Absolutely love it (which is why getting feedback is optimal)
I’ve been thinking about it, and really, components do need to handle their own serialization and deserialization, but not necessarily the storage. Possibly factory methods like
Health health = game.getSystem(HealthSystem.class).deserializeComponent(someByteArray);
where the method signatures are something like
public byte[] ComponentSystem.serializeComponent(final C component);
public C ComponentSystem.deserializeComponent(byte[] bytes);
and possibly even have the ComponentSystem itself responsible for storage (e.g. builtin health has a different kind of serialization from stargates). Then we could either have a ComponentSystemWithStore, which offers a default implementation for writing the blob to a database or flatfile depending on server config.
Serialization support would be optional, and the default implementation elsewhere can throw an UnsupportedOperationException.
First commit done:
In a proper entity system the components holds the data and is the only class/object that does that, while the system only works with the data and modifies it. A system generally can combine / access two components as well,
Example:
We have Velocity and Position components. A system would then add the velocity to the position each tick. The position does not know about movement and the velocity does not know about positioning, and the system only works with the values.
Agreed, I have some changes coming to the interfaces.
@Zidane: You saw this pull request?
A draft,
white = current system
blue = PR from jacklin213
orange = my idea for Components
Yah, he “pulled” somehow lol
Edit: Though I like the orange don’t you think its going to create a heap lot of classes thats like 16 classes when you can Categories the first 6 into like idk what but you know. Unless you already meant that my mistake
Let me just crosspost this from github.
Since when does an entity system has an entity type?
In an ideal ES an entity should be nothing more than an integer, which works but would be inconvenient if you want to get its components - thats why its often a class storing its ID and the manager it came from.
A “type” generally does not exist. There is an “EntityFactory” that you call to create your entities when you have your specific entity types (creeper, skeleton, player, vehicle, item…). The getID for the type component is redundant when you just add a component thats holds the model-ID, something like “Renderable” or “Model”. This current system is kind of mixing the OOP and ES approach together, which can quickly go into chaos imo …
Since the Mod-maker should be able to create entities as well, the EntityFactory is just a helper class to not write the same code over and over and over. We could add some more methods to it as well though. Some example code:
public interface EntityCreator {
Entity createEntity(EntityFactory factory, EntitySystem system);
}
public interface EntityFactory {
// General Vanilla mobs - we could even leave those out...
Entity createCreeper();
Entity createSkeleton();
// ...
// Helper methods
void addLivingAttributes(Entity entity); // Adds position, velocity and health
// Custom entity support
void addEntitySupport(String id, EntityCreator creator);
Entity createEntity(String id);
}
Example usage:
public class MinirobotEntityCreator implements EntityCreator {
@Override
public Entity createEntity(EntityFactory factory, EntitySystem system) {
Entity entity = system.createEntity();
factory.addLivingAttributes(entity);
// Add custom and other components ...
entity.addComponent(SmartMovement.class);
entity.addComponent(Storage.class);
}
}
@spaceemotion - you’re right about avoiding types in the ES system - but you are then creating a factory system which is polymorphic - would it be better to use something like the builder pattern which is also type/class agnostic, so you can refer to the entity as an ID instead? I don’t see the need to create loads of types for a factory if you don’t need to create them for an ES system.
Something like (with an extra method added in to show how you might customise a component of an entity):
Entity e = new EntityBuilder().ofType(id).withComponent(comopnentClass, value).build();
The ofType
method should set the default parametersa of the mod - which could be held in a map somewhere.
You could then have a different method that specifies a vanilla entity if you create an enum of them, for example:
Entity e = new EntityBuilder().ofVanillaType(VanillaEntityType.CREEPER).build();
It would also have the benefit of not breaking an interface if an update is needed to support another component - custom mob creators could just register their mob in the ID->Defaults map and not care about implementing the builder.
I would go into more detail, but I have to leave the house in five minutes, and won’t be back until tomorrow. I just wanted to get my thoughts down, just as an alternative!
Well, the factory I wrote is just an example and one way of doing it.
Yes, sure you can also create a fluid entity builder! That’s also perfectly fine, and I like your approach, however there are a few things I dislike.
First thing is the ofType
. Is the id an integer? or is it a string? If its a string, its okay, but if its an integer it wouldn’t really be dynamic anymore.
The second thing would be the vanilla type. If you create a dynamic builder, why even declare something like “vanilla”? What’s that, can I eat that? If you already provide a method to create things from IDs, and make the method calls chainable like that, why not have a class storing public static final
fields of Strings?
(I guess I could have done the same thing with my factory …)
The withComponent
seems like a bit too complex. If you just provide an instance the system can figure the underlying class out by itself. Thus you’d only need a withComponent(EntityComponent component)
. Since we know that there’ll be most likely only components, you could even rename it too “with” - similar to the StringBuilder’s append-fashion.
If you specify both, the ofType and withComponent methods - what does each one do? The ofType (if a string) should already declare the components then, no? Is it simply because you might want to add a component to an entity that might not have had that one before?
It’s all up for discussion - I was more suggesting the pattern rather than the actual form. I was just concerned that the factory pattern (used for polymorphic type creation) was used in a non-polymorphic way. My other concern was that if components get added, and the interface changes - then it’d break all implementations too.
I realise what I’ve suggested is a bit unrefined! Tearing it apart like that is good. OfType could be folded into the constructor - the IDs could be anything. Depends on how the actual system settles. When I’m back, I’ll try to make a more concrete prototype if it’s appropriate to do so.
I have some questions @Zidane
-
Component<H>
must beComponent<H extends ComponentHolder>
or? - What purpose has the
ComponentHolder
? In my eyes the Component interface mark the Component. - You plan a interface for each mob type oO
For all that miss the commit, here a class diagram:
blue = Entity
orange = Component
green = System
@IDragonFire You still got the type component wrong. There should be no such thing as an enderman. The only thing that exists is a Renderable component specifying the ID - a component should never be extended.
I too created a small diagram trying to simplify it as much as possible:
@Zidane
The current issues I see and questions I have are the following:
Where are the components getting stored? That would be a component manager, right? So where are the entities stored? In an entity manager? The EntityUniverse
? If it is the universe - can we move entities from on world another easily or would there be problems with client updates and so forth?
These are things that need some further investigation and discussion. The way the current system is set up it looks like a mix 'n match between OOP and ES, which seems pretty much against why we’re doing this.
@dualspiral Yes, I think that would help out.
I also don’t like the fact, the all current Components extends EntityComponent, why?
Also fallings blocks have a position and a velocity
But I love the new system
We only need some tutorials, because it confused most people.
They think OOP, but it is NOT oop.
Those blocks are moving entities disguised as blocks.
Now have a new components tab, take a look Google Document
Edit: why it lose its view counter