package westworldwithmessaging // Entity is what every game object in the world must be able to do. // The C++ code used pure virtual functions (Update()=0, and now // HandleMessage()=0) to force every subclass to write its own // versions. Go has no subclasses, so instead we say: "anything with // Update(), ID() and HandleMessage() methods counts as an Entity." A // type only satisfies this interface once it has all three - just // like the C++ version couldn't be used until both were implemented. type Entity interface { Update() ID() int // HandleMessage lets an entity respond to a Telegram sent to it // by the message dispatcher. It returns true if the message was // actually handled, false otherwise - callers use that to decide // whether to try routing the message somewhere else instead. HandleMessage(msg Telegram) bool } // nextValidID plays the role of the C++ "static int m_iNextValidID". // In C++, "static" on a class member means "one shared copy for the // whole class, not one per object." Go doesn't have that keyword for // structs, so we just use a normal package-level variable - it's // shared by every BaseGameEntity for the same reason: there's only // one of it. var nextValidID int // BaseGameEntity is the Go version of the C++ class BaseGameEntity. // Go doesn't have "classes" or "inheritance" - instead, other types // (like a Miner or a Wife later in the book) will embed this struct // inside themselves to borrow its fields and methods, and then add // their own Update method on top. type BaseGameEntity struct { id int // was "m_ID" - the entity's own unique number } // NewBaseGameEntity replaces the C++ constructor: // // BaseGameEntity(int id) { SetID(id); } // // Go structs don't run any code automatically when you create them, // so we write a plain function that builds one correctly. Any code // that wants a BaseGameEntity should call this instead of building // the struct by hand. func NewBaseGameEntity(id int) *BaseGameEntity { e := &BaseGameEntity{} e.setID(id) return e } // setID is the Go version of the private C++ method SetID. It does // exactly what the comment in the book says: check the requested ID // isn't lower than the next free one, store it, then move the // "next free ID" counter past it. // // The C++ code used assert() for the check, which only runs in // debug builds and does nothing in a release build. Go has no // assert, so we use panic - it always runs, and it stops the // program immediately if this ever happens, which is exactly what // a broken invariant like this deserves. func (e *BaseGameEntity) setID(val int) { if val < nextValidID { panic("BaseGameEntity.setID: invalid ID") } e.id = val nextValidID = e.id + 1 } // ID returns the entity's unique number. This is the Go version of // the C++ "int ID() const { return m_ID; }" - a small read-only // accessor for the private field. func (e *BaseGameEntity) ID() int { return e.id }