📄 simbase.h
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _SIMBASE_H_
#define _SIMBASE_H_
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _TALGORITHM_H_
#include "core/tAlgorithm.h"
#endif
#ifndef _BITSET_H_
#include "core/bitSet.h"
#endif
#ifndef _CONSOLEOBJECT_H_
#include "console/consoleObject.h"
#endif
#ifndef _SIMDICTIONARY_H_
#include "console/simDictionary.h"
#endif
#ifndef _PLATFORMMUTEX_H_
#include "platform/platformMutex.h"
#endif
#ifndef _PLATFORMSEMAPHORE_H_
#include "platform/platformSemaphore.h"
#endif
//---------------------------------------------------------------------------
/// Definition of some basic Sim system constants.
///
/// These constants define the range of ids assigned to datablocks
/// (DataBlockObjectIdFirst - DataBlockObjectIdLast), and the number
/// of bits used to store datablock IDs.
///
/// Normal Sim objects are given the range of IDs starting at
/// DynamicObjectIdFirst and going to infinity. Sim objects use
/// a SimObjectId to represent their ID; this is currently a U32.
///
/// The RootGroupId is assigned to gRootGroup, in which most SimObjects
/// are addded as child members. See simManager.cc for details, particularly
/// Sim::initRoot() and following.
enum SimObjectsConstants
{
DataBlockObjectIdFirst = 3,
DataBlockObjectIdBitSize = 10,
DataBlockObjectIdLast = DataBlockObjectIdFirst + (1 << DataBlockObjectIdBitSize) - 1,
DynamicObjectIdFirst = DataBlockObjectIdLast + 1,
InvalidEventId = 0,
RootGroupId = 0xFFFFFFFF,
};
class SimEvent;
class SimObject;
class SimGroup;
class SimManager;
class Namespace;
class BitStream;
class Stream;
class LightManager;
typedef U32 SimTime;
typedef U32 SimObjectId;
/// A vector of SimObjects.
///
/// As this inherits from VectorPtr, it has the full range of vector methods.
class SimObjectList: public VectorPtr<SimObject*>
{
static S32 QSORT_CALLBACK compareId(const void* a,const void* b);
public:
void pushBack(SimObject*); ///< Add the SimObject* to the end of the list, unless it's already in the list.
void pushBackForce(SimObject*); ///< Add the SimObject* to the end of the list, moving it there if it's already present in the list.
void pushFront(SimObject*); ///< Add the SimObject* to the start of the list.
void remove(SimObject*); ///< Remove the SimObject* from the list; may disrupt order of the list.
/// Remove the SimObject* from the list; guaranteed to preserve list order.
void removeStable(SimObject* pObject);
void sortId(); ///< Sort the list by object ID.
};
//---------------------------------------------------------------------------
/// Represents a queued event in the sim.
///
/// Sim provides an event queue for your convenience, which
/// can be used to schedule events. A few things which use
/// this event queue:
///
/// - The scene lighting system. In order to keep the game
/// responsive while scene lighting occurs, the lighting
/// process is divided into little chunks. In implementation
/// terms, there is a subclass of SimEvent called
/// SceneLightingProcessEvent. The process method of this
/// subclass calls into the lighting code, telling it to
/// perform the next chunk of lighting calculations.
/// - The schedule() console function uses a subclass of
/// SimEvent called SimConsoleEvent to keep track of
/// scheduled events.
class SimEvent
{
public:
SimEvent *nextEvent; ///< Linked list details - pointer to next item in the list.
SimTime startTime; ///< When the event was posted.
SimTime time; ///< When the event is scheduled to occur.
U32 sequenceCount; ///< Unique ID. These are assigned sequentially based on order
/// of addition to the list.
SimObject *destObject; ///< Object on which this event will be applied.
SimEvent() { destObject = NULL; }
virtual ~SimEvent() {} ///< Destructor
///
/// A dummy virtual destructor is required
/// so that subclasses can be deleted properly
/// Function called when event occurs.
///
/// This is where the meat of your event's implementation goes.
///
/// See any of the subclasses for ideas of what goes in here.
///
/// The event is deleted immediately after processing. If the
/// object referenced in destObject is deleted, then the event
/// is not called. The even will be executed unconditionally if
/// the object referenced is NULL.
///
/// @param object Object stored in destObject.
virtual void process(SimObject *object)=0;
};
/// Implementation of schedule() function.
///
/// This allows you to set a console function to be
/// called at some point in the future.
class SimConsoleEvent : public SimEvent
{
protected:
S32 mArgc;
char **mArgv;
bool mOnObject;
public:
/// Constructor
///
/// Pass the arguments of a function call, optionally on an object.
///
/// The object for the call to be executed on is specified by setting
/// onObject and storing a reference to the object in destObject. If
/// onObject is false, you don't need to store anything into destObject.
///
/// The parameters here are passed unmodified to Con::execute() at the
/// time of the event.
///
/// @see Con::execute(S32 argc, const char *argv[])
/// @see Con::execute(SimObject *object, S32 argc, const char *argv[])
SimConsoleEvent(S32 argc, const char **argv, bool onObject);
~SimConsoleEvent();
virtual void process(SimObject *object);
};
/// Used by Con::threadSafeExecute()
struct SimConsoleThreadExecCallback
{
void *sem;
const char *retVal;
SimConsoleThreadExecCallback();
~SimConsoleThreadExecCallback();
void handleCallback(const char *ret);
const char *waitForResult();
};
class SimConsoleThreadExecEvent : public SimConsoleEvent
{
SimConsoleThreadExecCallback *cb;
public:
SimConsoleThreadExecEvent(S32 argc, const char **argv, bool onObject, SimConsoleThreadExecCallback *callback);
virtual void process(SimObject *object);
};
//---------------------------------------------------------------------------
/// Dictionary to keep track of dynamic fields on SimObject.
class SimFieldDictionary
{
friend class SimFieldDictionaryIterator;
public:
struct Entry
{
StringTableEntry slotName;
char *value;
Entry *next;
};
private:
enum
{
HashTableSize = 19
};
Entry *mHashTable[HashTableSize];
static Entry *mFreeList;
static void freeEntry(Entry *entry);
static Entry *allocEntry();
/// In order to efficiently detect when a dynamic field has been
/// added or deleted, we increment this every time we add or
/// remove a field.
U32 mVersion;
public:
const U32 getVersion() const { return mVersion; }
SimFieldDictionary();
~SimFieldDictionary();
void setFieldValue(StringTableEntry slotName, const char *value);
const char *getFieldValue(StringTableEntry slotName);
//void writeFields(SimObject *obj, Stream &strem, U32 tabStop); /// TGE_Theme
void writeFields(SimObject *obj, Stream &stream, U32 tabStop, U32 flags = 0); /// TGE_Theme
void printFields(SimObject *obj);
void assignFrom(SimFieldDictionary *dict);
};
class SimFieldDictionaryIterator
{
SimFieldDictionary * mDictionary;
S32 mHashIndex;
SimFieldDictionary::Entry * mEntry;
public:
SimFieldDictionaryIterator(SimFieldDictionary*);
SimFieldDictionary::Entry* operator++();
SimFieldDictionary::Entry* operator*();
};
//---------------------------------------------------------------------------
/// Base class for objects involved in the simulation.
///
/// @section simobject_intro Introduction
///
/// SimObject is a base class for most of the classes you'll encounter
/// working in Torque. It provides fundamental services allowing "smart"
/// object referencing, creation, destruction, organization, and location.
/// Along with SimEvent, it gives you a flexible event-scheduling system,
/// as well as laying the foundation for the in-game editors, GUI system,
/// and other vital subsystems.
///
/// @section simobject_subclassing Subclassing
///
/// You will spend a lot of your time in Torque subclassing, or working
/// with subclasses of, SimObject. SimObject is designed to be easy to
/// subclass.
///
/// You should not need to override anything in a subclass except:
/// - The constructor/destructor.
/// - processArguments()
/// - onAdd()/onRemove()
/// - onGroupAdd()/onGroupRemove()
/// - onNameChange()
/// - onStaticModified()
/// - onDeleteNotify()
/// - onEditorEnable()/onEditorDisable()
/// - inspectPreApply()/inspectPostApply()
/// - things from ConsoleObject (see ConsoleObject docs for specifics)
///
/// Of course, if you know what you're doing, go nuts! But in most cases, you
/// shouldn't need to touch things not on that list.
///
/// When you subclass, you should define a typedef in the class, called Parent,
/// that references the class you're inheriting from.
///
/// @code
/// class mySubClass : public SimObject {
/// typedef SimObject Parent;
/// ...
/// @endcode
///
/// Then, when you override a method, put in:
///
/// @code
/// bool mySubClass::onAdd()
/// {
/// if(!Parent::onAdd())
/// return false;
///
/// // ... do other things ...
/// }
/// @endcode
///
/// Of course, you want to replace onAdd with the appropriate method call.
///
/// @section simobject_lifecycle A SimObject's Life Cycle
///
/// SimObjects do not live apart. One of the primary benefits of using a
/// SimObject is that you can uniquely identify it and easily find it (using
/// its ID). Torque does this by keeping a global hierarchy of SimGroups -
/// a tree - containing every registered SimObject. You can then query
/// for a given object using Sim::findObject() (or SimSet::findObject() if
/// you want to search only a specific set).
///
/// @code
/// // Three examples of registering an object.
///
/// // Method 1:
/// AIClient *aiPlayer = new AIClient();
/// aiPlayer->registerObject();
///
/// // Method 2:
/// ActionMap* globalMap = new ActionMap;
/// globalMap->registerObject("GlobalActionMap");
///
/// // Method 3:
/// bool reg = mObj->registerObject(id);
/// @endcode
///
/// Registering a SimObject performs these tasks:
/// - Marks the object as not cleared and not removed.
/// - Assigns the object a unique SimObjectID if it does not have one already.
/// - Adds the object to the global name and ID dictionaries so it can be found
/// again.
/// - Calls the object's onAdd() method. <b>Note:</b> SimObject::onAdd() performs
/// some important initialization steps. See @ref simobject_subclassing "here
/// for details" on how to properly subclass SimObject.
/// - If onAdd() fails (returns false), it calls unregisterObject().
/// - Checks to make sure that the SimObject was properly initialized (and asserts
/// if not).
///
/// Calling registerObject() and passing an ID or a name will cause the object to be
/// assigned that name and/or ID before it is registered.
///
/// Congratulations, you have now registered your object! What now?
///
/// Well, hopefully, the SimObject will have a long, useful life. But eventually,
/// it must die.
///
/// There are a two ways a SimObject can die.
/// - First, the game can be shut down. This causes the root SimGroup
/// to be unregistered and deleted. When a SimGroup is unregistered,
/// it unregisters all of its member SimObjects; this results in everything
/// that has been registered with Sim being unregistered, as everything
/// registered with Sim is in the root group.
/// - Second, you can manually kill it off, either by calling unregisterObject()
/// or by calling deleteObject().
///
/// When you unregister a SimObject, the following tasks are performed:
/// - The object is flagged as removed.
/// - Notifications are cleaned up.
/// - If the object is in a group, then it removes itself from the group.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -