380 lines
13 KiB
C++
380 lines
13 KiB
C++
/*
|
|
ZEntity.hpp
|
|
Author: James Russell <jcrussell@762studios.com>
|
|
Created: 2/5/2013
|
|
|
|
Purpose:
|
|
|
|
Entity class for the ZSimulation framework.
|
|
|
|
All objects affecting the simulation will exist as an entity. Entities can either
|
|
be created with state or without state. Entities with and without state can
|
|
be messaged by other entities within the simulation. Entities with state
|
|
have their state function called once per tick, and this state function
|
|
can modify the entity state, making the entity an autonomous state machine.
|
|
|
|
// ENTITY MESSAGING //
|
|
|
|
Entities are created in order to be processed in a threaded fashion. When
|
|
entities have their current state function called, they should be expected to be
|
|
able to process this in a thread-safe manner, able to call their own non-const methods
|
|
but only able to affect other entities via messaging.
|
|
|
|
After the state functions are called, remaining messages are delivered to the entity
|
|
'mailbox'. Any action that could mutate an entity that is not done from within the
|
|
call to the state function must be handled via a message.
|
|
|
|
These delivered messages are then processed in a multi threaded manner, but each entity
|
|
has it's messages processed serially, meaning that modifications can take place as per
|
|
normal.
|
|
|
|
Entity messages are processed by deferring to the handler installed for a particular
|
|
message type on an entity. If no message handler is installed for that message type
|
|
on an entity, the message handler installed for that type on the simulation message
|
|
stream will be called. If no message handler is installed there, the message is
|
|
dropped.
|
|
|
|
// ENTITY PROPERTIES //
|
|
|
|
Entities hold their state via allocation into the simulation 'property buffer', which
|
|
allows for contiguous space allocation for properties to be stored. The property
|
|
buffer is a raw memory allocator and does not care what the underlying data actually
|
|
is.
|
|
|
|
Entity properties can be allocated as 'local' or 'synchronized'. Data stored locally
|
|
is not updated to other simulation instances. Data stored in a 'synchronized' state is
|
|
mirrored to other simulation instances.
|
|
|
|
License:
|
|
|
|
Copyright 2013, 762 Studios
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef ZENTITY_HPP
|
|
#define ZENTITY_HPP
|
|
|
|
#include <ZUtil/ZRandomGenerator.hpp>
|
|
#include <ZUtil/ZName.hpp>
|
|
|
|
#include "ZSimulationDefs.hpp"
|
|
#include "ZPropertyBuffer.hpp"
|
|
#include "ZStringBuffer.hpp"
|
|
|
|
// forward decl
|
|
class ZSimulation;
|
|
struct ZMessage;
|
|
|
|
/*
|
|
Entity class.
|
|
*/
|
|
class ZEntity
|
|
{
|
|
public:
|
|
/*
|
|
This is the entity state typedef, which corresponds to 'AI State'. The current think state
|
|
is called once per simulation tick.
|
|
|
|
@param entity - the entity who is thinking
|
|
@param sim - the running simulation
|
|
@param dt - the time (expressed in seconds) since last call of this function
|
|
*/
|
|
typedef void (*StateFunc)(ZEntity& entity, const ZSimulation& sim, double dt);
|
|
|
|
/*
|
|
This is the entity message handler typedef, which corresponds to 'Behavior'. If there is no message
|
|
handler installed for a given message type, the default handler installed in the message queue
|
|
is used.
|
|
|
|
@param entity - the entity receiving the message
|
|
@param sim - the running simulation
|
|
@param sender - the sending entity
|
|
@param payload - the payload of the message
|
|
*/
|
|
typedef void (*MessageFunc)(ZEntity& entity, const ZSimulation& sim, eID sender, void* payload);
|
|
|
|
/*
|
|
This is the entity initialization function typedef, which can be passed to the simulation to initialize
|
|
the entity upon creation.
|
|
|
|
@param entity - the entity to initialize
|
|
@param sim - the running simulation
|
|
*/
|
|
typedef void (*InitFunc)(ZEntity& entity, const ZSimulation& sim);
|
|
|
|
/*
|
|
Entity property class. An ease of access class for reading and writing
|
|
property data.
|
|
|
|
This class does not handle type coercion on read. Types will change when
|
|
values are set.
|
|
*/
|
|
struct Property {
|
|
|
|
// we'll be using this a lot
|
|
typedef ZStringBuffer::StringKey StringKey;
|
|
|
|
enum {
|
|
BOOL, // boolean type
|
|
INT, // integer type
|
|
FLOAT, // floating point type
|
|
DOUBLE, // double precision floating point type
|
|
STRING, // string type (stored in string buffer or dynamic, limited size)
|
|
VECTOR, // vector type (4 floating point values)
|
|
MATRIX, // matrix type (16 floating point values)
|
|
|
|
NONE // untyped data
|
|
|
|
} Type; // the type of property
|
|
|
|
ZString LocalString; // local storage for strings
|
|
uint8_t Local[64]; // local storage for simple types
|
|
void* Data; // data for more complex types
|
|
size_t Size; // size of data (in bytes)
|
|
|
|
// default constructor, which initializes an empty string
|
|
Property();
|
|
|
|
// generic and array constructor, which takes data and size
|
|
Property(void* data, size_t size);
|
|
|
|
// value constructors
|
|
Property(const Property& other);
|
|
Property(const bool val);
|
|
Property(const int val);
|
|
Property(const float val);
|
|
Property(const double val);
|
|
Property(const char* val); // checks to see if this string has a string key, if not makes a dynamic string
|
|
Property(const StringKey val); // quicker method of directly creating a static string type
|
|
Property(const SST_Vec4f& val);
|
|
Property(const SST_Vec3f& val); // convenience for SST_Vec4f(x, y, z, 0.0)
|
|
Property(const SST_Vec2f& val); // convenience for SST_Vec4f(x, y, 0.0, 0.0)
|
|
Property(const SST_Mat44f& val);
|
|
|
|
// assignment operators
|
|
Property& operator = (const Property& other);
|
|
Property& operator = (const bool& val);
|
|
Property& operator = (const int& val);
|
|
Property& operator = (const float& val);
|
|
Property& operator = (const double& al);
|
|
Property& operator = (const char* val);
|
|
Property& operator = (const StringKey val); // quicker method of using a static string type
|
|
Property& operator = (const SST_Vec4f& val);
|
|
Property& operator = (const SST_Vec3f& val); // convenience for SST_Vec4f(x, y, z, 0.0)
|
|
Property& operator = (const SST_Vec2f& val); // convenience for SST_Vec4f(x, y, 0.0, 0.0)
|
|
Property& operator = (const SST_Mat44f& val);
|
|
|
|
// cast operators
|
|
operator bool () const;
|
|
operator int () const;
|
|
operator float () const;
|
|
operator double () const;
|
|
operator char* () const;
|
|
operator bool* () const;
|
|
operator int* () const;
|
|
operator float* () const;
|
|
operator double* () const;
|
|
operator SST_Vec4f () const;
|
|
operator SST_Vec3f () const; // gets [x, y, z] only
|
|
operator SST_Vec2f () const; // gets [x, y] only
|
|
operator SST_Mat44f () const;
|
|
};
|
|
|
|
// c'tor
|
|
ZEntity(eID entityId, ZSimulation& sim);
|
|
|
|
// parameterized c'tor (creates an actor)
|
|
ZEntity(eID entityId, ZSimulation& sim, StateFunc startState);
|
|
|
|
// d'tor
|
|
~ZEntity();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Member Data Getter Functions
|
|
|
|
eID GetId() const;
|
|
ZRandomGenerator& GetPRNG();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Property Manipulation Functions
|
|
|
|
/*
|
|
Property access functions. Used to create, remove, read, and write properties
|
|
and their values.
|
|
|
|
The 'HasProperty' function will return true if the named property exists on
|
|
this entity.
|
|
|
|
The 'CreateSyncProperty' functions is used to declare a synchronized property
|
|
on this entity. Synchronized properties are automatically mirrored across
|
|
the network system whenever a change is made. If the 'owner' boolean is
|
|
set to true, modifications to the entity on this simulation are synchronized
|
|
to other simulations. If the owner boolean is set to false, modifications
|
|
are not synchronized, and the property will be updated periodically from
|
|
other simulations. Only one simulation should be the owner of an entity,
|
|
or they will update over each other.
|
|
|
|
The 'GetProperty' function will fill out a Property instance that references
|
|
the read value of the named property. If the named property does not exist
|
|
on this entity, the function will return false.
|
|
|
|
The 'SetProperty' function will set the write value of the property to be
|
|
the value provided. If the named property does not exist, it will be created
|
|
as a non-synchronized property. Note that the read value is not updated until
|
|
the next simulation tick.
|
|
|
|
The 'EraseProperty' function will queue the property for removal at the end
|
|
of this tick, which allows 'get' operations to function as normal until the
|
|
next tick.
|
|
|
|
The template 'Get' function is a shortcut to directly get the value of
|
|
a specific property. Note that if the property does not exist, this will
|
|
return a default constructed property value.
|
|
*/
|
|
|
|
bool HasProperty(const ZName& name) const;
|
|
void CreateSyncProperty(const ZName& name, const Property& prop, bool owner);
|
|
bool GetProperty(const ZName& name, Property& val) const;
|
|
void SetProperty(const ZName& name, const Property& val);
|
|
void EraseProperty(const ZName& name);
|
|
|
|
template <typename T>
|
|
T Get(const ZName& name) const
|
|
{ Property prop; GetProperty(name, prop); return (T)prop; }
|
|
|
|
template <typename T>
|
|
void Set(const ZName& name, const T val)
|
|
{ Property prop(val); SetProperty(name, prop); }
|
|
|
|
/*************************************************************************/
|
|
|
|
/* State Management Functions */
|
|
|
|
/*
|
|
State functions. Used to get information about the current state and
|
|
manipulate the state stack, as well as call the current state function.
|
|
|
|
Push and Pop operate as you would expect for a state stack. The maximum
|
|
number of states is defined by ZENT_STACK_SIZE.
|
|
|
|
SetState sets the current state to the given state, replacing it.
|
|
|
|
ResetState clears the state stack and sets the current state to be the
|
|
provided one.
|
|
*/
|
|
|
|
StateFunc GetCurrentState() const;
|
|
double GetTimeInCurrentState() const;
|
|
void PushState(StateFunc state);
|
|
void PopState();
|
|
void SetState(StateFunc state);
|
|
void ResetState(StateFunc state);
|
|
|
|
/*
|
|
State property stack manipulation functions. Used to read and write information
|
|
to the state property stack, which can be used to pass transient information from
|
|
one state function to another.
|
|
*/
|
|
|
|
size_t GetStatePropertyCount() const;
|
|
Property PopStateProperty();
|
|
void PushStateProperty(const Property& prop);
|
|
void ClearStatePropertyStack();
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Messaging Management Functions */
|
|
|
|
/*
|
|
Messages, once posted to the message queue, can be 'delivered' to entities for
|
|
sorting purposes to be later processed in a convenient fashion.
|
|
|
|
When processing delivered messages, order of delivery is maintained. Any
|
|
messages that do not have a corresponding handler type installed will be
|
|
handled by the handler installed in the message stream. If no corresponding
|
|
handler is installed there, the message is dropped, and the simulation is
|
|
notified.
|
|
*/
|
|
|
|
void DeliverMessage(ZMessage* msg);
|
|
void ProcessMessages();
|
|
void PushMessageHandler(mID type, MessageFunc handler);
|
|
void PopMessageHandler(mID type);
|
|
void ClearMessageHandlers();
|
|
|
|
protected:
|
|
/*
|
|
Typedef for the property map used by ZEntity. It has a bucket size of 32, local
|
|
storage for the buckets of 32, 10 local nodes for each hash-chain, 10 local storage
|
|
for each property array, and will not resize based on load factor. Uses a 64-bit
|
|
hash value.
|
|
*/
|
|
typedef ZHashMap<ZName, ZPropertyBuffer::Property, int64_t, ZHasher<ZName, int64_t>, 0> PropMap;
|
|
|
|
/*
|
|
Stack used to indicate which properties have been modified since last swap of properties.
|
|
*/
|
|
typedef ZArray<ZPair<ZName, ZPropertyBuffer::Property>> PropModifiedStack;
|
|
|
|
/*
|
|
Stack used to indicate which properties have been deleted since last swap of properties.
|
|
*/
|
|
typedef ZArray<ZName> PropDeletedStack;
|
|
|
|
/*
|
|
Stack used for state properties, which can be used to send data from one state to another.
|
|
*/
|
|
typedef ZArray<Property> StatePropStack;
|
|
|
|
/*
|
|
Buffer used as an entity mailbox - targeted messages are delivered here.
|
|
*/
|
|
typedef ZRingBuffer<ZMessage*> Mailbox;
|
|
|
|
/*
|
|
Typedef for the handler map used by ZEntity, which maps message type to a
|
|
stack of handlers. Only keeps two local nodes in the allocator, and will not
|
|
resize based on load factor.
|
|
*/
|
|
typedef ZHashMap<mID, ZArray<MessageFunc>, int64_t, ZHasher<ZName, int64_t>, 0,
|
|
ZListPooledAllocator<ZHashNode<mID, ZArray<MessageFunc>, int64_t>, 2 >> HandlerMap;
|
|
|
|
/* Member Data */
|
|
ZSimulation& Sim; // the simulation running this thing
|
|
const eID Id; // the id of the entity
|
|
ZRandomGenerator PRNG; // entity PRNG, kept so there are no thread conflicts with PRNG access
|
|
|
|
/* Property Management */
|
|
PropMap PropertyMap; // entity properties map
|
|
PropModifiedStack PropertyModifiedStack; // properties that need to be mirrored into the read properties map
|
|
PropDeletedStack PropertyDeletedStack; // properties have been deleted
|
|
|
|
/* State Management */
|
|
int StateIndex; // index to our current state (-1 indicates no state)
|
|
StateFunc StateStack[ZSIM_ENT_STATE_STACK_SIZE]; // stack of states (StateStack[StateIndex] is our current)
|
|
StatePropStack StatePropertyStack; // stack of properties so that states can pass data to each other
|
|
double StateTime; // amount of time we have spent in our current state
|
|
|
|
/* Message Management */
|
|
Mailbox MessageMailbox; // entity 'Mailbox', which is where messages get delivered to
|
|
HandlerMap MessageHandlers; // entity handlers, used to process received messages
|
|
|
|
private:
|
|
friend class ZSimulation;
|
|
friend class ActorTickTask;
|
|
DISABLE_COPY_AND_ASSIGN(ZEntity);
|
|
|
|
// allocates a new property
|
|
// TODO
|
|
|
|
// called by the simulation to tick the current state
|
|
void StateTick(double dt);
|
|
|
|
// called by the simulation to dealloc properties
|
|
void HandlePropertyDelete();
|
|
};
|
|
|
|
#endif
|
|
|