   Is this getting crazy? [Component based entity replication]
  So I'm working on a network game with a component based entity architecture (just like everyone else it seems), and, while it works, I think it's getting a little out of hand, code complexity-wise.Here's the basic structure:Simulation -  - Maintains hash map of entities  - publishes entityAdded, entityRemoved events  ComponentSystem  - Keeps a hash map of components keyed on Entity ID  - Listens to Simulation events. When an entity is added or removed it    inspects the entity to see if it has a component it's interested in.    if so, then it registers the component with itself. Same goes forentityRemoved only that it removes the component.ViewState  - Manages a collection of EntityViews.  - When a registered EntityView reports that its entity is somehow changed    since the last time it was sent to the remote peer, it asks the EntityView    to serialize itself into a buffer. That buffer is sent to the remote peer.  - When an EntityView is added essentially the same process happens as compared    to updating a dirty view, only instead of sending an update flag it sends    a create flag and all shared components are forced to serialize.EntityView  - Is responsible for watching for changes in the entity it's watching.    When the EntityView is assigned an entity, the first thing it does is    inspect the entity for its components. The EntityView has access to a    collection of ComponentViewFactories that construct a ComponentView    for each of the entities registered components. These ComponentViews    are responsible for serializing changes to an individual component.This works well, but as more and more component types are being created the number of classes I need to implement is growing extremely fast. For each component type I must create three classes:* XXXServerComponent* XXXServerComponentView* XXXServerComponentViewFactory* XXXClientComponent* XXXClientComponentView* XXXClientComponentViewFactoryYou can see how this can get unmanageable pretty fast. The thing that I really like about how this comes together is that I can throw any type of component into any entity, and it is automagically distributed to every client having this entity in their ViewState.Is there some more obvious way to replicate that I've just overlooked somehow? Anyone have any ideas on how I could make this simpler?   
Quote:Original post by smr  - Listens to Simulation events. When an entity is added or removed it    inspects the entity to see if it has a component it's interested in.    if so, then it registers the component with itself. Same goes forentityRemoved only that it removes the component.Why wouldn't the component register itself with the system, instead?That avoids one source of message sending/listening complication.[qoute]ViewState  - Manages a collection of EntityViews.  - When a registered EntityView reports that its entity is somehow changed    since the last time it was sent to the remote peer, it asks the EntityView    to serialize itself into a buffer. That buffer is sent to the remote peer.You actually just want to put the entity in a "dirty queue" for each viewer. The viewer can then figure out which entities to update when. This allows you to send the latest-available data for each entity when time comes to update that specific entity. Also, be careful about serialization, the built-in serialization formats of most frameworks is way too big to work well for games.Quote:* XXXServerComponent* XXXServerComponentView* XXXServerComponentViewFactory* XXXClientComponent* XXXClientComponentView* XXXClientComponentViewFactoryWhy wouldn't "View" and "Factory" be totally mechanically derived from what the component itself is? A component exposes properties, which the view replicates. Thus, "View" really is something that looks for properties and replicates them. That can be re-used across all possible components. The Factory just needs to be a template that knows its name, and what class to instantiate.Separating server vs client is a bit of a hot-button issue with some people. Often, it's not strictly necessary to separate the two. It might be more advantageous to simply choose to not instantiate certain components on certain hosts -- for example, "render" and "user interaction" components aren't needed on the server, and "path planning" components may not be needed on the client.;Quote:Original post by hplus0603Why wouldn't the component register itself with the system, instead?That avoids one source of message sending/listening complication.I'm not sure how I would do this without pinging the component somehow and passing it a reference to the system to be registered to, unless the component systems are global. If I go as far as passing each component instance a reference to its system or a list of systems, then I might as well skip that and register the component with the system outside the component. Maybe I'm missing something obvious though; I do that way more often than I'd like to admit.Quote:You actually just want to put the entity in a "dirty queue" for each viewer. The viewer can then figure out which entities to update when. This allows you to send the latest-available data for each entity when time comes to update that specific entity. Also, be careful about serialization, the built-in serialization formats of most frameworks is way too big to work well for games.That's actually how the system works. The EntityView maintains a copy of whatever state needs to be replicated. When a delta update is being created to be sent, the ViewState iterates over all EntityViews. Each EntityView iterates over its ComponentViews asking them to update their dirty flags. If at least one is dirty, then it asks each ComponentView to serialize an update into a buffer. If no components reported dirty then the buffer is left unchanged.I'm also not using the baked-in serialization.Edit: Oh, there's a separate ViewState for every client.Quote:Why wouldn't "View" and "Factory" be totally mechanically derived from what the component itself is? A component exposes properties, which the view replicates. Thus, "View" really is something that looks for properties and replicates them. That can be re-used across all possible components. The Factory just needs to be a template that knows its name, and what class to instantiate.Yeah, I considered this too, and I'm starting to lean toward implementing it in that way using reflection. The only reason why I've shied away from this so far is because I envisioned that component views might have different rules for determining when an update is appropriate. The best example I could think of is for Position data. Position data isn't necessarily that critical to be precisely synced to the server. Depending on the distance from the observer it may only want to update if the difference is outside of a certain tolerance. I guess I could implement configurable property replicators or something, or create custom replicators in exceptional circumstances... Edit: Oh, and yes, the ViewFactory typically always looks like:public class ServerSpacialComponentViewFactory implements ComponentViewFactory {    public ComponentView create() {   return new ServerSpacialComponentView();    }}I'm not sure if that's close in concept to what you were describing. Maybe?Quote:Separating server vs client is a bit of a hot-button issue with some people. Often, it's not strictly necessary to separate the two. It might be more advantageous to simply choose to not instantiate certain components on certain hosts -- for example, "render" and "user interaction" components aren't needed on the server, and "path planning" components may not be needed on the client.I totally agree. Each component has a flag indicating whether it's replicated or not.   ;Quote:Original post by smrI'm not sure how I would do this without pinging the component somehow and passing it a reference to the system to be registered toOptions:- The factory could know which system it makes components for.- You could use a ServiceEnvironment that components execute in, it contains pointers to the appropriate subsystem instances. When an entity enters the world, each component is notified of becoming active, and register with their subsystem.- The subsystem could *be* the component factory.Quote:Yeah, I considered this too, and I'm starting to lean toward implementing it in that way using reflection. The only reason why I've shied away from this so far is because I envisioned that component views might have different rules for determining when an update is appropriate.You can support specialization for classes that really need it. That ought to be a minimal set, compared to the set of all components. Paying once for each specialization is much better than paying for each component class...Quote:Edit: Oh, and yes, the ViewFactory typically always looks like:public class ServerSpacialComponentViewFactory implements ComponentViewFactory {    public ComponentView create() {   return new ServerSpacialComponentView();    }}I'm not sure if that's close in concept to what you were describing. Maybe?I suggest you to use generics / templates / whatever-your-language-supports, meaning you'd just say:myEnvironment.addFactory(new ViewFactory<SpatialComponent>());