package westworldwithmessaging import "sync" // entityManager is the Go version of the singleton class // EntityManager. Same singleton pattern used throughout this // package: an unexported type, one shared instance, reached only // through the EntityManager() function below. // // The C++ version stores "BaseGameEntity*" pointers in its map. In // C++, a BaseGameEntity* pointing at an actual Miner still calls // Miner's real Update() (that's what "virtual" functions do - even // through a base-class pointer, the real subclass's version runs). // Go doesn't have virtual functions or base-class pointers, but our // Entity interface (from entity.go: Update() and ID()) gives us the // exact same behavior - a variable of type Entity holding a *Miner // still calls *Miner's own Update(). So Entity is what we store here // instead of *BaseGameEntity, to get the same real-subclass-runs // behavior C++ gets from virtual dispatch. type entityManager struct { // entityMap cross-references entities by their ID number, same // as the book's std::map m_EntityMap. (The // book's own comment above that field actually describes a // std::vector instead - a leftover mismatch in the book's text // itself. We're matching the real field, the map.) entityMap map[int]Entity } var ( entityManagerInstance *entityManager entityManagerOnce sync.Once ) // EntityManager is the Go stand-in for "EntityManager::Instance()". func EntityManager() *entityManager { entityManagerOnce.Do(func() { entityManagerInstance = &entityManager{ entityMap: make(map[int]Entity), } }) return entityManagerInstance } // EntityMgr is a shorthand for EntityManager(), matching the book's // "#define EntityMgr EntityManager::Instance()" macro. Go has no // preprocessor and no macros, so instead this is just a plain // package-level variable, set up once when the package is loaded - // EntityMgr.RegisterEntity(...) reads the same as the book's // EntityMgr->RegisterEntity(...), just with a dot instead of an // arrow (Go doesn't distinguish "." for values from "->" for // pointers the way C++ does - it's always "."). var EntityMgr = EntityManager() // RegisterEntity stores an entity so it can be looked up later by // its ID. func (m *entityManager) RegisterEntity(newEntity Entity) { m.entityMap[newEntity.ID()] = newEntity } // GetEntityFromID returns the entity with the given ID, or nil if // none is registered under that ID (same as the C++ version // implicitly returning nullptr for a lookup miss). func (m *entityManager) GetEntityFromID(id int) Entity { return m.entityMap[id] } // RemoveEntity removes an entity from the registry. func (m *entityManager) RemoveEntity(entity Entity) { delete(m.entityMap, entity.ID()) }