I'm working on a server implementation for a large game with many gametypes. There are several kinds of interactable entities: players, monsters, objects, vehicles.
All entities share the same base class (which is Cython):
cdef class Entity: cdef public int id cdef public double x,y,z,yaw,pitch,speed def __init__(self, int id, double x, double y, double z, double yaw, double pitch): self.id = id self.x = x self.y = y self.z = z self.yaw = yaw self.pitch = pitch self.speed = 0.1
Then there's a subclass for each of the earlier mentioned entity types, these subclasses implement the different packets involved for each of those types.
All entities support position and rotation, and all entities can in theory support different behaviors (and there can be quite a lot depending on the gametype) but often do not need them. There could be around ~90 different behaviors, so supporting all of that on the base MonsterEntity/whatever class doesn't make sense. A lot of those behaviors depend on stuff like health though, so if I don't implement that in a base class I'd have to implement it in a subclass.. but there are so many behaviors like that that are related I'd end up with either a lot of repeated code in different subclasses or thousands of usually unnecessary lines in a single big class.
I decided some kind of composition would make a lot more sense here, so I've tried using multiple inheritance since Python handles it pretty well:
class EntityHealth(object): def __init__(self, maxhealth=20): self.health = maxhealth self.maxhealth = maxhealth def damage(self, amount): # damage the entity pass def setHealth(self, health): # set the entity's health pass class EntityInventory(object): def __init__(self): self.inventory = Inventory() def dropAllItems(self): # do stuff pass class SlayableMonster(Monster, EntityHealth, EntityInventory): def __init__(self, id, name, x, y, z, yaw, pitch): Monster.__init__(self, id, name, x, y, z, yaw, pitch, meta, uuid, skinblob) EntityHealth.__init__(self, 20) EntityInventory.__init__(self)
I've heard people argue multiple inheritance should never be used, but this seems like a very concise design.
- All "behavior" classes would inherit from object or one behavior only for extending that behavior.
- The diamond problem shouldn't ever happen as a result because you would never have two classes that inherit from the same class up the tree both applied to the same entity.
So MRO problems should be impossible because the design is simple, there is no complex inheritance hierarchy.
Is this the best solution here, or is there something equally/more concise with the same advantages? I just want to isolate relevant code together while being able to pick which entities need that kind of behavior.