Set svn:eol-style=native

This was SVN commit r6816.
This commit is contained in:
Ykkrosh 2009-04-11 17:00:39 +00:00
parent ce3994fc7a
commit 1e3cd00c72
47 changed files with 7201 additions and 7201 deletions

View File

@ -1,172 +1,172 @@
#include "precompiled.h"
#include "XMLFix.h"
#include "CommonConvert.h"
#include "FUtils/FUXmlParser.h"
/*
Things that are fixed here:
----
3ds Max "file://" image URLs
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
Problem: /COLLADA/library_images/image/init_from = "file://" which crashes some versions of FCollada
Fix: Delete the whole library_images subtree, since we never use it anyway.
Then delete library_effects and library_materials too, to avoid broken references.
----
3ds Max broken material references
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
Problem: /COLLADA/library_visual_scenes/.../instance_material/@target sometimes
refers to non-existent material IDs.
Fix: Delete the whole bind_material subtree, since we never use it anyway.
----
*/
static xmlNode* findChildElement(xmlNode* node, const char* name)
{
for (xmlNode* child = node->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, name) == 0)
return child;
}
return NULL;
}
static bool applyFBXFixesNode(xmlNode* node)
{
bool changed = false;
for (xmlNode* child = node->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE)
{
if (strcmp((const char*)child->name, "node") == 0)
{
if (applyFBXFixesNode(child))
changed = true;
}
else if (strcmp((const char*)child->name, "instance_geometry") == 0)
{
xmlNode* bind_material = findChildElement(child, "bind_material");
if (! bind_material) continue;
Log(LOG_INFO, "Found a bind_material to delete");
xmlUnlinkNode(bind_material);
xmlFreeNode(bind_material);
changed = true;
}
}
}
return changed;
}
static bool applyFBXFixes(xmlNode* root)
{
Log(LOG_INFO, "Applying fixes for 3ds Max exporter");
bool changed = false;
xmlNode* library_images = findChildElement(root, "library_images");
if (library_images)
{
Log(LOG_INFO, "Found library_images to delete");
xmlUnlinkNode(library_images);
xmlFreeNode(library_images);
changed = true;
}
xmlNode* library_materials = findChildElement(root, "library_materials");
if (library_materials)
{
Log(LOG_INFO, "Found library_materials to delete");
xmlUnlinkNode(library_materials);
xmlFreeNode(library_materials);
changed = true;
}
xmlNode* library_effects = findChildElement(root, "library_effects");
if (library_effects)
{
Log(LOG_INFO, "Found library_effects to delete");
xmlUnlinkNode(library_effects);
xmlFreeNode(library_effects);
changed = true;
}
xmlNode* library_visual_scenes = findChildElement(root, "library_visual_scenes");
if (library_visual_scenes) // (Assume there's only one of these)
{
xmlNode* visual_scene = findChildElement(library_visual_scenes, "visual_scene");
if (visual_scene) // (Assume there's only one of these)
{
for (xmlNode* child = visual_scene->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, "node") == 0)
if (applyFBXFixesNode(child))
changed = true;
}
}
}
return changed;
}
static bool processDocument(xmlNode* root)
{
xmlNode* asset = findChildElement(root, "asset");
if (! asset) return false;
xmlNode* contributor = findChildElement(asset, "contributor");
if (! contributor) return false;
xmlNode* authoring_tool = findChildElement(contributor, "authoring_tool");
if (! authoring_tool) return false;
xmlNode* authoring_tool_text = authoring_tool->children;
if (! authoring_tool_text) return false;
if (authoring_tool_text->type != XML_TEXT_NODE) return false;
xmlChar* toolname = authoring_tool_text->content;
Log(LOG_INFO, "Authoring tool: %s", toolname);
if (strcmp((const char*)toolname, "FBX COLLADA exporter") == 0)
return applyFBXFixes(root);
else
return false;
}
void FixBrokenXML(const char* text, const char** out, size_t* outSize)
{
Log(LOG_INFO, "Running FixBrokenXML");
size_t textSize = strlen(text);
xmlDocPtr doc = xmlParseMemory(text, textSize);
xmlNode* root = xmlDocGetRootElement(doc);
if (root && processDocument(root))
{
// Reserialising the document, then parsing it again inside FCollada, is a bit ugly;
// but it's the only way I can see to make it work through FCollada's public API
xmlChar* mem = NULL;
int size = -1;
xmlDocDumpFormatMemory(doc, &mem, &size, 0);
*out = (const char*)mem;
*outSize = size;
}
else
{
*out = text;
*outSize = textSize;
}
xmlFreeDoc(doc);
}
#include "precompiled.h"
#include "XMLFix.h"
#include "CommonConvert.h"
#include "FUtils/FUXmlParser.h"
/*
Things that are fixed here:
----
3ds Max "file://" image URLs
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
Problem: /COLLADA/library_images/image/init_from = "file://" which crashes some versions of FCollada
Fix: Delete the whole library_images subtree, since we never use it anyway.
Then delete library_effects and library_materials too, to avoid broken references.
----
3ds Max broken material references
Identifier: /COLLADA/asset/contributor/authoring_tool = "FBX COLLADA exporter"
Problem: /COLLADA/library_visual_scenes/.../instance_material/@target sometimes
refers to non-existent material IDs.
Fix: Delete the whole bind_material subtree, since we never use it anyway.
----
*/
static xmlNode* findChildElement(xmlNode* node, const char* name)
{
for (xmlNode* child = node->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, name) == 0)
return child;
}
return NULL;
}
static bool applyFBXFixesNode(xmlNode* node)
{
bool changed = false;
for (xmlNode* child = node->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE)
{
if (strcmp((const char*)child->name, "node") == 0)
{
if (applyFBXFixesNode(child))
changed = true;
}
else if (strcmp((const char*)child->name, "instance_geometry") == 0)
{
xmlNode* bind_material = findChildElement(child, "bind_material");
if (! bind_material) continue;
Log(LOG_INFO, "Found a bind_material to delete");
xmlUnlinkNode(bind_material);
xmlFreeNode(bind_material);
changed = true;
}
}
}
return changed;
}
static bool applyFBXFixes(xmlNode* root)
{
Log(LOG_INFO, "Applying fixes for 3ds Max exporter");
bool changed = false;
xmlNode* library_images = findChildElement(root, "library_images");
if (library_images)
{
Log(LOG_INFO, "Found library_images to delete");
xmlUnlinkNode(library_images);
xmlFreeNode(library_images);
changed = true;
}
xmlNode* library_materials = findChildElement(root, "library_materials");
if (library_materials)
{
Log(LOG_INFO, "Found library_materials to delete");
xmlUnlinkNode(library_materials);
xmlFreeNode(library_materials);
changed = true;
}
xmlNode* library_effects = findChildElement(root, "library_effects");
if (library_effects)
{
Log(LOG_INFO, "Found library_effects to delete");
xmlUnlinkNode(library_effects);
xmlFreeNode(library_effects);
changed = true;
}
xmlNode* library_visual_scenes = findChildElement(root, "library_visual_scenes");
if (library_visual_scenes) // (Assume there's only one of these)
{
xmlNode* visual_scene = findChildElement(library_visual_scenes, "visual_scene");
if (visual_scene) // (Assume there's only one of these)
{
for (xmlNode* child = visual_scene->children; child; child = child->next)
{
if (child->type == XML_ELEMENT_NODE && strcmp((const char*)child->name, "node") == 0)
if (applyFBXFixesNode(child))
changed = true;
}
}
}
return changed;
}
static bool processDocument(xmlNode* root)
{
xmlNode* asset = findChildElement(root, "asset");
if (! asset) return false;
xmlNode* contributor = findChildElement(asset, "contributor");
if (! contributor) return false;
xmlNode* authoring_tool = findChildElement(contributor, "authoring_tool");
if (! authoring_tool) return false;
xmlNode* authoring_tool_text = authoring_tool->children;
if (! authoring_tool_text) return false;
if (authoring_tool_text->type != XML_TEXT_NODE) return false;
xmlChar* toolname = authoring_tool_text->content;
Log(LOG_INFO, "Authoring tool: %s", toolname);
if (strcmp((const char*)toolname, "FBX COLLADA exporter") == 0)
return applyFBXFixes(root);
else
return false;
}
void FixBrokenXML(const char* text, const char** out, size_t* outSize)
{
Log(LOG_INFO, "Running FixBrokenXML");
size_t textSize = strlen(text);
xmlDocPtr doc = xmlParseMemory(text, textSize);
xmlNode* root = xmlDocGetRootElement(doc);
if (root && processDocument(root))
{
// Reserialising the document, then parsing it again inside FCollada, is a bit ugly;
// but it's the only way I can see to make it work through FCollada's public API
xmlChar* mem = NULL;
int size = -1;
xmlDocDumpFormatMemory(doc, &mem, &size, 0);
*out = (const char*)mem;
*outSize = size;
}
else
{
*out = text;
*outSize = textSize;
}
xmlFreeDoc(doc);
}

View File

@ -1,12 +1,12 @@
#ifndef XMLFIX_INCLUDED
#define XMLFIX_INCLUDED
/**
* Fixes some errors in COLLADA XML files that would otherwise prevent
* FCollada from loading them successfully.
* 'out' is either a new XML document, which must be freed with xmlFree;
* otherwise it is equal to 'text' if no changes were made.
*/
void FixBrokenXML(const char* text, const char** out, size_t* outSize);
#endif // XMLFIX_INCLUDED
#ifndef XMLFIX_INCLUDED
#define XMLFIX_INCLUDED
/**
* Fixes some errors in COLLADA XML files that would otherwise prevent
* FCollada from loading them successfully.
* 'out' is either a new XML document, which must be freed with xmlFree;
* otherwise it is equal to 'text' if no changes were made.
*/
void FixBrokenXML(const char* text, const char** out, size_t* outSize);
#endif // XMLFIX_INCLUDED

View File

@ -1,53 +1,53 @@
/**
* =========================================================================
* File : Noise.h
* Project : 0 A.D.
* Description : 2D and 3D seamless Perlin noise
* =========================================================================
*/
// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
// and http://mrl.nyu.edu/~perlin/paper445.pdf.
// Not optimized for speed yet.
#ifndef INCLUDED_NOISE
#define INCLUDED_NOISE
#include "Vector2D.h"
#include "Vector3D.h"
#include "MathUtil.h"
class Noise2D
{
/// Frequency in X and Y
int freq;
/// freq*freq random gradient vectors in the unit cube
CVector2D_Maths** grads;
public:
Noise2D(int freq);
~Noise2D();
/// Evaluate the noise function at a given point
float operator() (float x, float y);
};
class Noise3D
{
/// Frequency in X and Y
int freq;
/// Frequency in Z (vertical frequency)
int vfreq;
/// freq*freq*vfreq random gradient vectors in the unit cube
CVector3D*** grads;
public:
Noise3D(int freq, int vfreq);
~Noise3D();
/// Evaluate the noise function at a given point
float operator() (float x, float y, float z);
};
#endif
/**
* =========================================================================
* File : Noise.h
* Project : 0 A.D.
* Description : 2D and 3D seamless Perlin noise
* =========================================================================
*/
// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
// and http://mrl.nyu.edu/~perlin/paper445.pdf.
// Not optimized for speed yet.
#ifndef INCLUDED_NOISE
#define INCLUDED_NOISE
#include "Vector2D.h"
#include "Vector3D.h"
#include "MathUtil.h"
class Noise2D
{
/// Frequency in X and Y
int freq;
/// freq*freq random gradient vectors in the unit cube
CVector2D_Maths** grads;
public:
Noise2D(int freq);
~Noise2D();
/// Evaluate the noise function at a given point
float operator() (float x, float y);
};
class Noise3D
{
/// Frequency in X and Y
int freq;
/// Frequency in Z (vertical frequency)
int vfreq;
/// freq*freq*vfreq random gradient vectors in the unit cube
CVector3D*** grads;
public:
Noise3D(int freq, int vfreq);
~Noise3D();
/// Evaluate the noise function at a given point
float operator() (float x, float y, float z);
};
#endif

View File

@ -1,68 +1,68 @@
#include "lib/self_test.h"
#include <cstdlib>
#include <cmath>
#include "maths/Matrix3D.h"
#include "maths/Quaternion.h"
class TestMatrix : public CxxTest::TestSuite
{
public:
void test_inverse()
{
CMatrix3D m;
srand(0);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 16; ++j)
{
m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX);
}
CMatrix3D n;
m.GetInverse(n);
m *= n;
// verify identity has 1s on diagonal and 0 otherwise
for (int x = 0; x < 4; ++x)
{
for (int y = 0; y < 4; ++y)
{
const float expected = (x==y)? 1.0f : 0.0f;
TS_ASSERT_DELTA(m(x,y), expected, 0.0001f);
}
}
}
}
void test_quats()
{
srand(0);
for (int i = 0; i < 4; ++i)
{
CQuaternion q;
q.FromEulerAngles(
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX)
);
CMatrix3D m;
q.ToMatrix(m);
CQuaternion q2 = m.GetRotation();
// Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when
// interpreted as rotations, so it doesn't matter which we get
const bool ok_oneway =
feq(q2.m_W, q.m_W) &&
feq(q2.m_V.X, q.m_V.X) &&
feq(q2.m_V.Y, q.m_V.Y) &&
feq(q2.m_V.Z, q.m_V.Z);
const bool ok_otherway =
feq(q2.m_W, -q.m_W) &&
feq(q2.m_V.X, -q.m_V.X) &&
feq(q2.m_V.Y, -q.m_V.Y) &&
feq(q2.m_V.Z, -q.m_V.Z);
TS_ASSERT(ok_oneway ^ ok_otherway);
}
}
};
#include "lib/self_test.h"
#include <cstdlib>
#include <cmath>
#include "maths/Matrix3D.h"
#include "maths/Quaternion.h"
class TestMatrix : public CxxTest::TestSuite
{
public:
void test_inverse()
{
CMatrix3D m;
srand(0);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 16; ++j)
{
m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX);
}
CMatrix3D n;
m.GetInverse(n);
m *= n;
// verify identity has 1s on diagonal and 0 otherwise
for (int x = 0; x < 4; ++x)
{
for (int y = 0; y < 4; ++y)
{
const float expected = (x==y)? 1.0f : 0.0f;
TS_ASSERT_DELTA(m(x,y), expected, 0.0001f);
}
}
}
}
void test_quats()
{
srand(0);
for (int i = 0; i < 4; ++i)
{
CQuaternion q;
q.FromEulerAngles(
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX)
);
CMatrix3D m;
q.ToMatrix(m);
CQuaternion q2 = m.GetRotation();
// Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when
// interpreted as rotations, so it doesn't matter which we get
const bool ok_oneway =
feq(q2.m_W, q.m_W) &&
feq(q2.m_V.X, q.m_V.X) &&
feq(q2.m_V.Y, q.m_V.Y) &&
feq(q2.m_V.Z, q.m_V.Z);
const bool ok_otherway =
feq(q2.m_W, -q.m_W) &&
feq(q2.m_V.X, -q.m_V.X) &&
feq(q2.m_V.Y, -q.m_V.Y) &&
feq(q2.m_V.Z, -q.m_V.Z);
TS_ASSERT(ok_oneway ^ ok_otherway);
}
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,161 +1,161 @@
/**
*-----------------------------------------------------------------------------
* FILE : NetClient.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network client class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETCLIENT_H
#define NETCLIENT_H
// INCLUDES
#include "NetSession.h"
#include "ps/CStr.h"
#include "simulation/TurnManager.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptableObject.h"
#include "ps/scripting/JSMap.h"
#include <map>
// DECLARATIONS
enum
{
NCS_CONNECT = 200,
NCS_HANDSHAKE = 300,
NCS_AUTHENTICATE = 400,
NCS_PREGAME = 500,
NCS_INGAME = 600
};
class CPlayerSlot;
class CPlayer;
class CGame;
class CGameAttributes;
class CServerPlayer;
//typedef std::map< uint, CStr > PlayerMap;
typedef std::map< uint, CServerPlayer* > PlayerMap;
/*
CLASS : CServerPlayer
DESCRIPTION :
NOTES :
*/
class CServerPlayer : public CJSObject< CServerPlayer >
{
public:
CServerPlayer( uint sessionID, const CStr& nickname );
~CServerPlayer( void );
static void ScriptingInit( void );
uint GetSessionID( void ) const { return m_SessionID; }
const CStr GetNickname( void ) const { return m_Nickname; }
protected:
private:
CServerPlayer( const CServerPlayer& );
CServerPlayer& operator=( const CServerPlayer& );
uint m_SessionID; // Player session ID
CStr m_Nickname; // Player nickname
};
/*
CLASS : CNetClient
DESCRIPTION :
NOTES :
*/
class CNetClient: public CNetHost,
public CJSObject<CNetClient>,
protected CTurnManager
{
public:
CNetClient( CGame* pGame, CGameAttributes* pGameAttributes );
~CNetClient( void );
bool CreateSession ( void );
void OnPlayer ( uint ID, const CStr& name );
void OnPlayerLeave ( uint ID );
/**
* Returns true indicating the host acts as a client
*
* @return Always true
*/
virtual bool IsClient( void ) const { return true; }
// Get a pointer to our player
CPlayer* GetLocalPlayer();
CJSMap< PlayerMap > m_JsPlayers;
CStr m_Nickname;
CStr m_Password;
//int m_SessionID;
CPlayerSlot *m_pLocalPlayerSlot;
CGame *m_pGame;
CGameAttributes *m_pGameAttributes;
// Are we currently in a locally-yet-unsimulated turn?
// This is set to true when we receive a command batch and cleared in NewTurn().
// The server also ensures that it does not send a new turn until we ack one.
bool m_TurnPending;
// Mutex for accessing batches
CMutex m_Mutex;
// JS event scripts
CScriptObject m_OnStartGame;
CScriptObject m_OnChat;
CScriptObject m_OnConnectComplete;
CScriptObject m_OnDisconnect;
CScriptObject m_OnPlayerJoin;
CScriptObject m_OnPlayerLeave;
static void ScriptingInit( void );
int StartGame( void );
protected:
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession *pSession );
virtual void NewTurn ( void );
virtual bool NewTurnReady ( void ) { return m_TurnPending; }
virtual void QueueLocalCommand ( CNetMessage* pMessage );
void QueueIncomingMessage ( CNetMessage* pMessage );
private:
// Not implemented
CNetClient( const CNetClient& );
CNetClient& operator=( const CNetClient& );
static bool OnError ( void* pContext, CFsmEvent* pEvent );
static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
static bool OnStartGame ( void* pContext, CFsmEvent* pEvent );
bool SetupConnection( JSContext *cx, uintN argc, jsval *argv );
//CNetSession* m_Session; // Server session
PlayerMap m_Players; // List of online players
};
extern CNetClient *g_NetClient;
#endif // NETCLIENT_H
/**
*-----------------------------------------------------------------------------
* FILE : NetClient.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network client class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETCLIENT_H
#define NETCLIENT_H
// INCLUDES
#include "NetSession.h"
#include "ps/CStr.h"
#include "simulation/TurnManager.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptableObject.h"
#include "ps/scripting/JSMap.h"
#include <map>
// DECLARATIONS
enum
{
NCS_CONNECT = 200,
NCS_HANDSHAKE = 300,
NCS_AUTHENTICATE = 400,
NCS_PREGAME = 500,
NCS_INGAME = 600
};
class CPlayerSlot;
class CPlayer;
class CGame;
class CGameAttributes;
class CServerPlayer;
//typedef std::map< uint, CStr > PlayerMap;
typedef std::map< uint, CServerPlayer* > PlayerMap;
/*
CLASS : CServerPlayer
DESCRIPTION :
NOTES :
*/
class CServerPlayer : public CJSObject< CServerPlayer >
{
public:
CServerPlayer( uint sessionID, const CStr& nickname );
~CServerPlayer( void );
static void ScriptingInit( void );
uint GetSessionID( void ) const { return m_SessionID; }
const CStr GetNickname( void ) const { return m_Nickname; }
protected:
private:
CServerPlayer( const CServerPlayer& );
CServerPlayer& operator=( const CServerPlayer& );
uint m_SessionID; // Player session ID
CStr m_Nickname; // Player nickname
};
/*
CLASS : CNetClient
DESCRIPTION :
NOTES :
*/
class CNetClient: public CNetHost,
public CJSObject<CNetClient>,
protected CTurnManager
{
public:
CNetClient( CGame* pGame, CGameAttributes* pGameAttributes );
~CNetClient( void );
bool CreateSession ( void );
void OnPlayer ( uint ID, const CStr& name );
void OnPlayerLeave ( uint ID );
/**
* Returns true indicating the host acts as a client
*
* @return Always true
*/
virtual bool IsClient( void ) const { return true; }
// Get a pointer to our player
CPlayer* GetLocalPlayer();
CJSMap< PlayerMap > m_JsPlayers;
CStr m_Nickname;
CStr m_Password;
//int m_SessionID;
CPlayerSlot *m_pLocalPlayerSlot;
CGame *m_pGame;
CGameAttributes *m_pGameAttributes;
// Are we currently in a locally-yet-unsimulated turn?
// This is set to true when we receive a command batch and cleared in NewTurn().
// The server also ensures that it does not send a new turn until we ack one.
bool m_TurnPending;
// Mutex for accessing batches
CMutex m_Mutex;
// JS event scripts
CScriptObject m_OnStartGame;
CScriptObject m_OnChat;
CScriptObject m_OnConnectComplete;
CScriptObject m_OnDisconnect;
CScriptObject m_OnPlayerJoin;
CScriptObject m_OnPlayerLeave;
static void ScriptingInit( void );
int StartGame( void );
protected:
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession *pSession );
virtual void NewTurn ( void );
virtual bool NewTurnReady ( void ) { return m_TurnPending; }
virtual void QueueLocalCommand ( CNetMessage* pMessage );
void QueueIncomingMessage ( CNetMessage* pMessage );
private:
// Not implemented
CNetClient( const CNetClient& );
CNetClient& operator=( const CNetClient& );
static bool OnError ( void* pContext, CFsmEvent* pEvent );
static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
static bool OnStartGame ( void* pContext, CFsmEvent* pEvent );
bool SetupConnection( JSContext *cx, uintN argc, jsval *argv );
//CNetSession* m_Session; // Server session
PlayerMap m_Players; // List of online players
};
extern CNetClient *g_NetClient;
#endif // NETCLIENT_H

View File

@ -1,147 +1,147 @@
/*
*-----------------------------------------------------------------------------
* FILE : NetJsEvents.h
* PROJECT : 0 A.D.
* DESCRIPTION : Definitions for JavaScript events used by the network
* system
*-----------------------------------------------------------------------------
*/
#ifndef NETJSEVENTS_H
#define NETJSEVENTS_H
// INCLUDES
#include "NetSession.h"
#include "scripting/DOMEvent.h"
// DEFINES
enum NetJsEvents
{
JS_EVENT_CLIENT_CONNECT,
JS_EVENT_CONNECT_COMPLETE,
JS_EVENT_CLIENT_DISCONNECT,
JS_EVENT_DISCONNECT,
JS_EVENT_START_GAME,
JS_EVENT_CHAT,
JS_EVENT_LAST
};
class CStartGameEvent: public CScriptEvent
{
public:
CStartGameEvent():
CScriptEvent(L"startGame", JS_EVENT_START_GAME, false)
{}
};
class CChatEvent: public CScriptEvent
{
CStr m_Sender;
CStr m_Message;
public:
CChatEvent(const CStr& sender, const CStr& message):
CScriptEvent(L"chat", JS_EVENT_CHAT, false ),
m_Sender(sender),
m_Message(message)
{
AddLocalProperty(L"sender", &m_Sender, true);
AddLocalProperty(L"message", &m_Message, true);
}
};
class CConnectCompleteEvent: public CScriptEvent
{
CStr m_Message;
bool m_Success;
public:
CConnectCompleteEvent(const CStr& message, bool success):
CScriptEvent(L"connectComplete", JS_EVENT_CONNECT_COMPLETE, false),
m_Message(message),
m_Success(success)
{
AddLocalProperty(L"message", &m_Message, true);
AddLocalProperty(L"success", &m_Success, true);
}
};
class CDisconnectEvent: public CScriptEvent
{
CStrW m_Message;
public:
CDisconnectEvent(const CStr& message):
CScriptEvent(L"disconnect", JS_EVENT_DISCONNECT, false),
m_Message(message)
{
AddLocalProperty(L"message", &m_Message, true);
}
};
class CClientConnectDisconnectCommon: public CScriptEvent
{
uint m_SessionID;
CStr m_Name;
CNetSession *m_Session;
public:
CClientConnectDisconnectCommon(const wchar_t* UNUSED(eventName), int UNUSED(eventType),
int sessionID, const CStr& name, CNetSession* pSession)
: CScriptEvent(L"clientConnect", JS_EVENT_CLIENT_CONNECT, false),
m_SessionID(sessionID),
m_Name(name),
m_Session(pSession)
{
AddLocalProperty(L"id", &m_SessionID, true);
AddLocalProperty(L"name", &m_Name, true);
if (m_Session)
AddLocalProperty(L"session", &m_Session, true);
}
};
struct CClientConnectEvent: public CClientConnectDisconnectCommon
{
CClientConnectEvent(int sessionID, const CStr& name):
CClientConnectDisconnectCommon(
L"clientConnect",
JS_EVENT_CLIENT_CONNECT,
sessionID,
name,
NULL)
{}
CClientConnectEvent(CNetSession *pSession):
CClientConnectDisconnectCommon(
L"clientConnect",
JS_EVENT_CLIENT_CONNECT,
pSession->GetID(),
pSession->GetName(),
pSession)
{}
};
struct CClientDisconnectEvent: public CClientConnectDisconnectCommon
{
CClientDisconnectEvent(int sessionID, const CStr& name):
CClientConnectDisconnectCommon(
L"clientDisconnect",
JS_EVENT_CLIENT_DISCONNECT,
sessionID,
name,
NULL)
{}
CClientDisconnectEvent(CNetSession *pSession):
CClientConnectDisconnectCommon(
L"clientDisconnect",
JS_EVENT_CLIENT_DISCONNECT,
pSession->GetID(),
pSession->GetName(),
pSession)
{}
};
#endif // NETJSEVENTS_H
/*
*-----------------------------------------------------------------------------
* FILE : NetJsEvents.h
* PROJECT : 0 A.D.
* DESCRIPTION : Definitions for JavaScript events used by the network
* system
*-----------------------------------------------------------------------------
*/
#ifndef NETJSEVENTS_H
#define NETJSEVENTS_H
// INCLUDES
#include "NetSession.h"
#include "scripting/DOMEvent.h"
// DEFINES
enum NetJsEvents
{
JS_EVENT_CLIENT_CONNECT,
JS_EVENT_CONNECT_COMPLETE,
JS_EVENT_CLIENT_DISCONNECT,
JS_EVENT_DISCONNECT,
JS_EVENT_START_GAME,
JS_EVENT_CHAT,
JS_EVENT_LAST
};
class CStartGameEvent: public CScriptEvent
{
public:
CStartGameEvent():
CScriptEvent(L"startGame", JS_EVENT_START_GAME, false)
{}
};
class CChatEvent: public CScriptEvent
{
CStr m_Sender;
CStr m_Message;
public:
CChatEvent(const CStr& sender, const CStr& message):
CScriptEvent(L"chat", JS_EVENT_CHAT, false ),
m_Sender(sender),
m_Message(message)
{
AddLocalProperty(L"sender", &m_Sender, true);
AddLocalProperty(L"message", &m_Message, true);
}
};
class CConnectCompleteEvent: public CScriptEvent
{
CStr m_Message;
bool m_Success;
public:
CConnectCompleteEvent(const CStr& message, bool success):
CScriptEvent(L"connectComplete", JS_EVENT_CONNECT_COMPLETE, false),
m_Message(message),
m_Success(success)
{
AddLocalProperty(L"message", &m_Message, true);
AddLocalProperty(L"success", &m_Success, true);
}
};
class CDisconnectEvent: public CScriptEvent
{
CStrW m_Message;
public:
CDisconnectEvent(const CStr& message):
CScriptEvent(L"disconnect", JS_EVENT_DISCONNECT, false),
m_Message(message)
{
AddLocalProperty(L"message", &m_Message, true);
}
};
class CClientConnectDisconnectCommon: public CScriptEvent
{
uint m_SessionID;
CStr m_Name;
CNetSession *m_Session;
public:
CClientConnectDisconnectCommon(const wchar_t* UNUSED(eventName), int UNUSED(eventType),
int sessionID, const CStr& name, CNetSession* pSession)
: CScriptEvent(L"clientConnect", JS_EVENT_CLIENT_CONNECT, false),
m_SessionID(sessionID),
m_Name(name),
m_Session(pSession)
{
AddLocalProperty(L"id", &m_SessionID, true);
AddLocalProperty(L"name", &m_Name, true);
if (m_Session)
AddLocalProperty(L"session", &m_Session, true);
}
};
struct CClientConnectEvent: public CClientConnectDisconnectCommon
{
CClientConnectEvent(int sessionID, const CStr& name):
CClientConnectDisconnectCommon(
L"clientConnect",
JS_EVENT_CLIENT_CONNECT,
sessionID,
name,
NULL)
{}
CClientConnectEvent(CNetSession *pSession):
CClientConnectDisconnectCommon(
L"clientConnect",
JS_EVENT_CLIENT_CONNECT,
pSession->GetID(),
pSession->GetName(),
pSession)
{}
};
struct CClientDisconnectEvent: public CClientConnectDisconnectCommon
{
CClientDisconnectEvent(int sessionID, const CStr& name):
CClientConnectDisconnectCommon(
L"clientDisconnect",
JS_EVENT_CLIENT_DISCONNECT,
sessionID,
name,
NULL)
{}
CClientDisconnectEvent(CNetSession *pSession):
CClientConnectDisconnectCommon(
L"clientDisconnect",
JS_EVENT_CLIENT_DISCONNECT,
pSession->GetID(),
pSession->GetName(),
pSession)
{}
};
#endif // NETJSEVENTS_H

View File

@ -1,263 +1,263 @@
/**
*-----------------------------------------------------------------------------
* FILE : NetMessages.h
* PROJECT : 0 A.D.
* DESCRIPTION : The list of messages used by the network subsystem
*-----------------------------------------------------------------------------
*/
#ifndef NETMESSAGES_H
#define NETMESSAGES_H
// INCLUDES
#include "ps/CStr.h"
#include "scripting/JSSerialization.h"
#include "simulation/EntityHandles.h"
// DEFINES
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_VERSION 0x01010002 // Arbitrary protocol
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
// Defines the list of message types. The order of the list must not change
// The message types having a negative value are used internally and not sent
// over the network. The message types used for network communication have
// positive values.
enum NetMessageType
{
NMT_ERROR = -256, // Delivery of error states
NMT_CONNECT_COMPLETE, // Connection is complete
NMT_CLOSE_REQUEST, // Close connection request
NMT_INVALID = 0, // Invalid message
NMT_SERVER_HANDSHAKE, // Handshake stage
NMT_CLIENT_HANDSHAKE,
NMT_SERVER_HANDSHAKE_RESPONSE,
NMT_AUTHENTICATE, // Authentication stage
NMT_AUTHENTICATE_RESULT,
NMT_CHAT, // Common chat message
NMT_PLAYER_JOIN, // Pre-game stage
NMT_PLAYER_LEAVE,
NMT_GAME_SETUP,
NMT_ASSIGN_PLAYER_SLOT,
NMT_PLAYER_CONFIG,
NMT_FILES_REQUIRED,
NMT_FILE_REQUEST,
NMT_FILE_CHUNK,
NMT_FILE_CHUNK_ACK,
NMT_FILE_PROGRESS,
NMT_GAME_START,
NMT_END_COMMAND_BATCH, // In-game stage
NMT_GOTO,
NMT_COMMAND_FIRST = NMT_GOTO,
NMT_PATROL,
NMT_ADD_WAYPOINT,
NMT_CONTACT_ACTION,
NMT_PRODUCE,
NMT_PLACE_OBJECT,
NMT_REMOVE_OBJECT,
NMT_RUN,
NMT_SET_RALLY_POINT,
NMT_SET_STANCE,
NMT_NOTIFY_REQUEST,
NMT_FORMATION_GOTO,
NMT_FORMATION_CONTACT_ACTION,
NMT_COMMAND_LAST,
NMT_LAST // Last message in the list
};
// Authentication result codes
enum AuthenticateResultCode
{
ARC_OK,
ARC_PASSWORD_INVALID,
ARC_NICK_TAKEN,
ARC_NICK_INVALID,
};
enum
{
CHAT_RECIPIENT_FIRST = 0xFFFD,
CHAT_RECIPIENT_ENEMIES = 0xFFFD,
CHAT_RECIPIENT_ALLIES = 0xFFFE,
CHAT_RECIPIENT_ALL = 0xFFFF
};
enum
{
ASSIGN_OPEN,
ASSIGN_CLOSED,
ASSIGN_AI,
ASSIGN_SESSION
};
#endif // NETMESSAGES_H
#ifdef CREATING_NMT
#define ALLNETMSGS_DONT_CREATE_NMTS
#define START_NMT_CLASS_(_nm, _message) START_NMT_CLASS(C##_nm##Message, _message)
#define DERIVE_NMT_CLASS_(_base, _nm, _message) START_NMT_CLASS_DERIVED(C ## _base ## Message, C ## _nm ## Message, _message)
START_NMTS()
START_NMT_CLASS_(SrvHandshake, NMT_SERVER_HANDSHAKE)
NMT_FIELD_INT(m_Magic, u32, 4)
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()
START_NMT_CLASS_(CliHandshake,NMT_CLIENT_HANDSHAKE)
NMT_FIELD_INT(m_MagicResponse, u32, 4)
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()
START_NMT_CLASS_(SrvHandshakeResponse, NMT_SERVER_HANDSHAKE_RESPONSE)
NMT_FIELD_INT(m_UseProtocolVersion, u32, 4)
NMT_FIELD_INT(m_Flags, u32, 4)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE)
NMT_FIELD(CStrW, m_Name)
//NMT_FIELD(CPasswordHash, m_Password)
NMT_FIELD(CStrW, m_Password)
END_NMT_CLASS()
START_NMT_CLASS_(AuthenticateResult, NMT_AUTHENTICATE_RESULT)
NMT_FIELD_INT(m_Code, u32, 4)
NMT_FIELD_INT(m_SessionID, u32, 2)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(Chat, NMT_CHAT)
NMT_FIELD(CStrW, m_Sender)
NMT_FIELD_INT(m_Recipient, u32, 2)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(PlayerJoin, NMT_PLAYER_JOIN)
NMT_START_ARRAY(m_Clients)
NMT_FIELD_INT(m_SessionID, u32, 2)
NMT_FIELD(CStr, m_Name)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(PlayerLeave, NMT_PLAYER_LEAVE)
NMT_FIELD_INT(m_SessionID, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(GameSetup, NMT_GAME_SETUP)
NMT_START_ARRAY(m_Values)
NMT_FIELD(CStrW, m_Name)
NMT_FIELD(CStrW, m_Value)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(AssignPlayerSlot, NMT_ASSIGN_PLAYER_SLOT)
NMT_FIELD_INT(m_SlotID, u32, 2)
NMT_FIELD_INT(m_Assignment, u32, 1)
NMT_FIELD_INT(m_SessionID, u32, 2) // Only applicable for PS_ASSIGN_SESSION
END_NMT_CLASS()
START_NMT_CLASS_(PlayerConfig, NMT_PLAYER_CONFIG)
NMT_FIELD_INT(m_PlayerID, u32, 2)
NMT_START_ARRAY(m_Values)
NMT_FIELD(CStrW, m_Name)
NMT_FIELD(CStrW, m_Value)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(GameStart, NMT_GAME_START)
END_NMT_CLASS()
START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(Command, NMT_INVALID)
NMT_FIELD(CEntityList, m_Entities)
NMT_FIELD_INT(m_IsQueued, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Goto, NMT_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Run, NMT_RUN)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Patrol, NMT_PATROL)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, AddWaypoint, NMT_ADD_WAYPOINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetRallyPoint, NMT_SET_RALLY_POINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetStance, NMT_SET_STANCE)
NMT_FIELD(CStrW, m_Stance)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, ContactAction, NMT_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
NMT_FIELD_INT(m_Run, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Produce, NMT_PRODUCE)
NMT_FIELD_INT(m_Type, u32, 4)
NMT_FIELD(CStrW, m_Name)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, PlaceObject, NMT_PLACE_OBJECT)
NMT_FIELD(CStrW, m_Template)
NMT_FIELD_INT(m_X, u32, 4)
NMT_FIELD_INT(m_Y, u32, 4)
NMT_FIELD_INT(m_Z, u32, 4)
NMT_FIELD_INT(m_Angle, u32, 4) // Orientation angle
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, RemoveObject, NMT_REMOVE_OBJECT)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, NotifyRequest, NMT_NOTIFY_REQUEST)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationGoto, NMT_FORMATION_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationContactAction, NMT_FORMATION_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
END_NMTS()
#else
#ifndef ALLNETMSGS_DONT_CREATE_NMTS
# ifdef ALLNETMSGS_IMPLEMENT
# define NMT_CREATOR_IMPLEMENT
# endif
# define NMT_CREATE_HEADER_NAME "NetMessages.h"
# include "NMTCreator.h"
#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS
#endif // #ifdef CREATING_NMT
/**
*-----------------------------------------------------------------------------
* FILE : NetMessages.h
* PROJECT : 0 A.D.
* DESCRIPTION : The list of messages used by the network subsystem
*-----------------------------------------------------------------------------
*/
#ifndef NETMESSAGES_H
#define NETMESSAGES_H
// INCLUDES
#include "ps/CStr.h"
#include "scripting/JSSerialization.h"
#include "simulation/EntityHandles.h"
// DEFINES
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_VERSION 0x01010002 // Arbitrary protocol
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
// Defines the list of message types. The order of the list must not change
// The message types having a negative value are used internally and not sent
// over the network. The message types used for network communication have
// positive values.
enum NetMessageType
{
NMT_ERROR = -256, // Delivery of error states
NMT_CONNECT_COMPLETE, // Connection is complete
NMT_CLOSE_REQUEST, // Close connection request
NMT_INVALID = 0, // Invalid message
NMT_SERVER_HANDSHAKE, // Handshake stage
NMT_CLIENT_HANDSHAKE,
NMT_SERVER_HANDSHAKE_RESPONSE,
NMT_AUTHENTICATE, // Authentication stage
NMT_AUTHENTICATE_RESULT,
NMT_CHAT, // Common chat message
NMT_PLAYER_JOIN, // Pre-game stage
NMT_PLAYER_LEAVE,
NMT_GAME_SETUP,
NMT_ASSIGN_PLAYER_SLOT,
NMT_PLAYER_CONFIG,
NMT_FILES_REQUIRED,
NMT_FILE_REQUEST,
NMT_FILE_CHUNK,
NMT_FILE_CHUNK_ACK,
NMT_FILE_PROGRESS,
NMT_GAME_START,
NMT_END_COMMAND_BATCH, // In-game stage
NMT_GOTO,
NMT_COMMAND_FIRST = NMT_GOTO,
NMT_PATROL,
NMT_ADD_WAYPOINT,
NMT_CONTACT_ACTION,
NMT_PRODUCE,
NMT_PLACE_OBJECT,
NMT_REMOVE_OBJECT,
NMT_RUN,
NMT_SET_RALLY_POINT,
NMT_SET_STANCE,
NMT_NOTIFY_REQUEST,
NMT_FORMATION_GOTO,
NMT_FORMATION_CONTACT_ACTION,
NMT_COMMAND_LAST,
NMT_LAST // Last message in the list
};
// Authentication result codes
enum AuthenticateResultCode
{
ARC_OK,
ARC_PASSWORD_INVALID,
ARC_NICK_TAKEN,
ARC_NICK_INVALID,
};
enum
{
CHAT_RECIPIENT_FIRST = 0xFFFD,
CHAT_RECIPIENT_ENEMIES = 0xFFFD,
CHAT_RECIPIENT_ALLIES = 0xFFFE,
CHAT_RECIPIENT_ALL = 0xFFFF
};
enum
{
ASSIGN_OPEN,
ASSIGN_CLOSED,
ASSIGN_AI,
ASSIGN_SESSION
};
#endif // NETMESSAGES_H
#ifdef CREATING_NMT
#define ALLNETMSGS_DONT_CREATE_NMTS
#define START_NMT_CLASS_(_nm, _message) START_NMT_CLASS(C##_nm##Message, _message)
#define DERIVE_NMT_CLASS_(_base, _nm, _message) START_NMT_CLASS_DERIVED(C ## _base ## Message, C ## _nm ## Message, _message)
START_NMTS()
START_NMT_CLASS_(SrvHandshake, NMT_SERVER_HANDSHAKE)
NMT_FIELD_INT(m_Magic, u32, 4)
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()
START_NMT_CLASS_(CliHandshake,NMT_CLIENT_HANDSHAKE)
NMT_FIELD_INT(m_MagicResponse, u32, 4)
NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()
START_NMT_CLASS_(SrvHandshakeResponse, NMT_SERVER_HANDSHAKE_RESPONSE)
NMT_FIELD_INT(m_UseProtocolVersion, u32, 4)
NMT_FIELD_INT(m_Flags, u32, 4)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE)
NMT_FIELD(CStrW, m_Name)
//NMT_FIELD(CPasswordHash, m_Password)
NMT_FIELD(CStrW, m_Password)
END_NMT_CLASS()
START_NMT_CLASS_(AuthenticateResult, NMT_AUTHENTICATE_RESULT)
NMT_FIELD_INT(m_Code, u32, 4)
NMT_FIELD_INT(m_SessionID, u32, 2)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(Chat, NMT_CHAT)
NMT_FIELD(CStrW, m_Sender)
NMT_FIELD_INT(m_Recipient, u32, 2)
NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()
START_NMT_CLASS_(PlayerJoin, NMT_PLAYER_JOIN)
NMT_START_ARRAY(m_Clients)
NMT_FIELD_INT(m_SessionID, u32, 2)
NMT_FIELD(CStr, m_Name)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(PlayerLeave, NMT_PLAYER_LEAVE)
NMT_FIELD_INT(m_SessionID, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(GameSetup, NMT_GAME_SETUP)
NMT_START_ARRAY(m_Values)
NMT_FIELD(CStrW, m_Name)
NMT_FIELD(CStrW, m_Value)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(AssignPlayerSlot, NMT_ASSIGN_PLAYER_SLOT)
NMT_FIELD_INT(m_SlotID, u32, 2)
NMT_FIELD_INT(m_Assignment, u32, 1)
NMT_FIELD_INT(m_SessionID, u32, 2) // Only applicable for PS_ASSIGN_SESSION
END_NMT_CLASS()
START_NMT_CLASS_(PlayerConfig, NMT_PLAYER_CONFIG)
NMT_FIELD_INT(m_PlayerID, u32, 2)
NMT_START_ARRAY(m_Values)
NMT_FIELD(CStrW, m_Name)
NMT_FIELD(CStrW, m_Value)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(GameStart, NMT_GAME_START)
END_NMT_CLASS()
START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(Command, NMT_INVALID)
NMT_FIELD(CEntityList, m_Entities)
NMT_FIELD_INT(m_IsQueued, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Goto, NMT_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Run, NMT_RUN)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Patrol, NMT_PATROL)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, AddWaypoint, NMT_ADD_WAYPOINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetRallyPoint, NMT_SET_RALLY_POINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetStance, NMT_SET_STANCE)
NMT_FIELD(CStrW, m_Stance)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, ContactAction, NMT_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
NMT_FIELD_INT(m_Run, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Produce, NMT_PRODUCE)
NMT_FIELD_INT(m_Type, u32, 4)
NMT_FIELD(CStrW, m_Name)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, PlaceObject, NMT_PLACE_OBJECT)
NMT_FIELD(CStrW, m_Template)
NMT_FIELD_INT(m_X, u32, 4)
NMT_FIELD_INT(m_Y, u32, 4)
NMT_FIELD_INT(m_Z, u32, 4)
NMT_FIELD_INT(m_Angle, u32, 4) // Orientation angle
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, RemoveObject, NMT_REMOVE_OBJECT)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, NotifyRequest, NMT_NOTIFY_REQUEST)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationGoto, NMT_FORMATION_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationContactAction, NMT_FORMATION_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
END_NMTS()
#else
#ifndef ALLNETMSGS_DONT_CREATE_NMTS
# ifdef ALLNETMSGS_IMPLEMENT
# define NMT_CREATOR_IMPLEMENT
# endif
# define NMT_CREATE_HEADER_NAME "NetMessages.h"
# include "NMTCreator.h"
#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS
#endif // #ifdef CREATING_NMT

File diff suppressed because it is too large Load Diff

View File

@ -1,345 +1,345 @@
/**
*-----------------------------------------------------------------------------
* FILE : NetServer.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network server class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETSERVER_H
#define NETSERVER_H
// INCLUDES
#include "Network.h"
#include "NetSession.h"
#include "simulation/TurnManager.h"
#include "scripting/ScriptableObject.h"
#include "ps/GameAttributes.h"
#include "ps/scripting/JSMap.h"
#include "ps/Player.h"
#include "ps/Game.h"
#include "simulation/ScriptObject.h"
#include <map>
#include <vector>
// DECLARATIONS
#define SERVER_SESSIONID 1
#define CLIENT_MIN_SESSIONID 100
#define MAX_CLIENTS 8
#define MAX_OBSERVERS 5
#define DEFAULT_SERVER_SESSION_ID 1
#define DEFAULT_SERVER_NAME L"Noname Server"
#define DEFAULT_PLAYER_NAME L"Noname Player"
#define DEFAULT_WELCOME_MESSAGE L"Noname Server Welcome Message"
#define DEFAULT_HOST_PORT 0x5073
enum NetServerState
{
// We haven't opened the port yet, we're just setting some stuff up.
// This is probably equivalent to the first "Start Network Game" screen
SERVER_STATE_PREBIND,
// The server is open and accepting connections. This is the screen where
// rules are set up by the operator and where players join and select civs
// and stuff.
SERVER_STATE_PREGAME,
// The one with all the killing ;-)
SERVER_STATE_INGAME,
// The game is over and someone has won. Players might linger to chat or
// download the replay log.
SERVER_STATE_POSTGAME
};
enum
{
NSS_HANDSHAKE = 1300,
NSS_AUTHENTICATE = 1400,
NSS_PREGAME = 1500,
NSS_INGAME = 1600
};
enum
{
NMT_APP_PLAYER_LEAVE = NMT_LAST + 100,
NMT_APP_PREGAME = NMT_LAST + 200,
NMT_APP_OBSERVER = NMT_LAST + 300
};
typedef std::map< uint, CNetSession* > IDSessionMap;
typedef std::vector< CNetSession* > SessionList;
/*
CLASS : CNetServer
DESCRIPTION : CNetServer implements a network server for the game.
It receives data and connection requests from clients.
Under the hood, it uses ENet library to manage connected
peers and bandwidth among these.
NOTES :
*/
class CNetServer : public CNetHost,
public CJSObject<CNetServer>,
public CTurnManager
{
public:
CNetServer( CGame* pGame, CGameAttributes* pGameAttributes );
virtual ~CNetServer( void );
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
// void Shutdown ( void );
/**
* Returns true indicating the host acts as a server
*
* @return Always true
*/
virtual bool IsServer( void ) const { return true; }
/**
* Adds a new session to the list of sessions
*
* @param pSession New session to add
*/
void AddSession( CNetSession* pSession );
/**
* Removes the specified session from the list of sessions. If the session
* isn't found it returns NULL otherwise it returns the session object found.
*
* @param pSession Session to remove
* @return The session object if found, NULL otherwise
*/
CNetSession* RemoveSession( CNetSession* pSession );
/**
* Removes all the sessions managed by the network server
*
*/
//void RemoveAllSessions( void );
/**
* Returns the number of session the server manages
*
* @return The number of sessions
*/
//uint GetSessionCount( void ) const;
/**
* Returns the session object for the specified ID
*
* @param sessionID The session ID
* @return A pointer to session for the specified ID or
* NULL if not found
*/
CNetSession* GetSessionByID( uint sessionID );
protected:
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession *pSession );
private:
// Not implemented
CNetServer( const CNetServer& );
CNetServer& operator=( const CNetServer& );
//void ClientConnect ( ENetPeer* pPeer );
//void ClientDisconnect ( ENetPeer* pPeer );
//void ClientReceive ( ENetPeer* pPeer, ENetPacket* pPacket );
/**
* Returns the session associated with the specified ENet peer
*
* @param pPeer ENet peer
* @return The session object if found or NULL
*/
//CNetSession* GetSessionByPeer( const ENetPeer* pPeer );
/**
* Setup client game by sending the apropiate network messages. It also
* inform the client about the other connected clients as well as player
* slot assignment and attributes.
*
*/
//void SetupNewSession( CNetSession* pSession );
/**
* Loads the player properties into the specified message
*
* @param pMessage Message where to load player properties
* @param pPlayer Player for which we load the properties
*/
void BuildPlayerConfigMessage(
CPlayerConfigMessage* pMessage,
CPlayer* pPlayer );
/**
* Callback function used by the BuildPlayerSetupMessage to iterate over
* the player properties. It will be called for each property of the player
*
* @param name Property name
* @param pProperty Pointer to player property
* @param pData Context pointer passed on iteration startup
*/
static void PlayerConfigMessageCallback(
const CStrW& name,
ISynchedJSProperty* pProperty,
void* pData );
/**
* Loads game properties into the specified message
*
* @param pMessage Message where to load game properties
*/
void BuildGameSetupMessage( CGameSetupMessage* pMessage );
/**
* Loads player slot properties into the specified message
*
* @param pMessage Message where to load player properties
* @param pPlayerSlot Player slot properties
*/
void BuildPlayerSlotAssignmentMessage(
CAssignPlayerSlotMessage* pMessage,
CPlayerSlot* pPlayerSlot );
/**
* Callback function used by the BuildGameSetupMessage to iterate over the
* game properties. It will be called for each property of the game
*
* @param name Property name
* @param pProperty Pointer to game property
* @param pData Context pointer passed on iteration startup
*/
// IterateCB GameSetupMessageCallbak;
static void GameSetupMessageCallback(
const CStrW& name,
ISynchedJSProperty *pProperty,
void *pData );
/**
* Retrieves a free session ID from the recycled sessions list
*
* @return Free session ID
*/
uint GetFreeSessionID( void ) const;
IDSessionMap m_IDSessions; // List of connected ID and session pairs
//CScriptObject m_ScriptConnect; // Script client connect dispatch
//CScriptObject m_ScriptDisconnect; // Script client disconnect dispatch
//CScriptObject m_ScriptChat; // Script client chat dispatch
CPlayer* m_Player; // Server player
public:
/**
*
*
* @param addr Address where to bind
* @return PS_OK if bind successfully, error code otherwise
*/
//PS_RESULT Bind( const CSocketAddress& addr );
void SetPlayerPassword ( const CStr& password );
CStrW GetPlayerName ( void ) const { return m_PlayerName; }
NetServerState GetState ( void ) const { return m_State; }
int StartGame ( void );
static void ScriptingInit ( void );
protected:
// Assign a session ID to the session. Do this just before calling AddSession
void AssignSessionID( CNetSession* pSession );
// Add the session. This will be called after the session passes the
// handshake and authentication stages. AssignSessionID should've been called
// on the session prior to calling this method.
//void AddSession( CNetServerSession* pSession );
// Remove the session from the server
//void RemoveSession( CNetServerSession* pSession );
// Queue a command coming in from the wire. The command has been validated
// by the caller.
void QueueIncomingCommand( CNetMessage* pMessage );
// Call the JS callback for incoming events
void OnPlayerChat ( const CStrW& from, const CStrW& message );
void OnPlayerJoin ( CNetSession* pSession );
void OnPlayerLeave ( CNetSession* pSession );
void SetupPlayer ( CNetSession* pSession );
//static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
static bool OnError ( void* pContext, CFsmEvent* pEvent );
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
// OVERRIDES FROM CServerSocket
//virtual void OnAccept( const CSocketAddress& address );
// OVERRIDES FROM CTurnManager
virtual void NewTurn( void );
virtual bool NewTurnReady( void );
virtual void QueueLocalCommand( CNetMessage* pMessage );
// Will only be called from the Network Thread, by the OnAccept handler
//virtual CNetServerSession* CreateSession( CSocketInternal* pSocketInternal);
// Ask the server if the session is allowed to start observing.
//
// Returns:
// true if the session should be made an observer
// false otherwise
virtual bool AllowObserver( CNetSession* pSession );
private:
CGameAttributes* m_GameAttributes; // Stores game attributes
//int m_LastSessionID; // Stores the last session ID
//SessionMap m_Sessions; // Managed sessions
CJSMap< IDSessionMap > m_JsSessions;
CMutex m_Mutex; // Synchronization object for batches
/*
All sessions that have observer status (observer as in watcher - simple
chatters don't have an entry here, only in m_Sessions).
Sessions are added here after they have successfully requested observer
status.
*/
SessionList m_Observers;
uint m_MaxObservers; // Maximum number of observers
CGame* m_Game; // Pointer to actual game
NetServerState m_State; // Holds server state
CStrW m_Name; // Server name
CStrW m_WelcomeMessage; // Nice welcome message
//CPlayer* m_Player; // Pointer to 'server' player
CStrW m_PlayerName; // Player name
CStrW m_PlayerPassword; // Player password
int m_Port; // The listening port
CScriptObject m_OnChat;
CScriptObject m_OnClientConnect;
CScriptObject m_OnClientDisconnect;
// static CGameAttributes::UpdateCallback AttributeUpdate;
// static CPlayer::UpdateCallback PlayerAttributeUpdate;
// static PlayerSlotAssignmentCB PlayerSlotAssignmentCallback;
static void AttributeUpdate ( const CStrW& name, const CStrW& newValue, void* pData);
static void PlayerAttributeUpdate ( const CStrW& name, const CStrW& value, CPlayer* pPlayer, void* pData );
static void PlayerSlotAssignment ( void* pData, CPlayerSlot* pPlayerSlot );
};
extern CNetServer *g_NetServer;
#endif // NETSERVER_H
/**
*-----------------------------------------------------------------------------
* FILE : NetServer.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network server class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETSERVER_H
#define NETSERVER_H
// INCLUDES
#include "Network.h"
#include "NetSession.h"
#include "simulation/TurnManager.h"
#include "scripting/ScriptableObject.h"
#include "ps/GameAttributes.h"
#include "ps/scripting/JSMap.h"
#include "ps/Player.h"
#include "ps/Game.h"
#include "simulation/ScriptObject.h"
#include <map>
#include <vector>
// DECLARATIONS
#define SERVER_SESSIONID 1
#define CLIENT_MIN_SESSIONID 100
#define MAX_CLIENTS 8
#define MAX_OBSERVERS 5
#define DEFAULT_SERVER_SESSION_ID 1
#define DEFAULT_SERVER_NAME L"Noname Server"
#define DEFAULT_PLAYER_NAME L"Noname Player"
#define DEFAULT_WELCOME_MESSAGE L"Noname Server Welcome Message"
#define DEFAULT_HOST_PORT 0x5073
enum NetServerState
{
// We haven't opened the port yet, we're just setting some stuff up.
// This is probably equivalent to the first "Start Network Game" screen
SERVER_STATE_PREBIND,
// The server is open and accepting connections. This is the screen where
// rules are set up by the operator and where players join and select civs
// and stuff.
SERVER_STATE_PREGAME,
// The one with all the killing ;-)
SERVER_STATE_INGAME,
// The game is over and someone has won. Players might linger to chat or
// download the replay log.
SERVER_STATE_POSTGAME
};
enum
{
NSS_HANDSHAKE = 1300,
NSS_AUTHENTICATE = 1400,
NSS_PREGAME = 1500,
NSS_INGAME = 1600
};
enum
{
NMT_APP_PLAYER_LEAVE = NMT_LAST + 100,
NMT_APP_PREGAME = NMT_LAST + 200,
NMT_APP_OBSERVER = NMT_LAST + 300
};
typedef std::map< uint, CNetSession* > IDSessionMap;
typedef std::vector< CNetSession* > SessionList;
/*
CLASS : CNetServer
DESCRIPTION : CNetServer implements a network server for the game.
It receives data and connection requests from clients.
Under the hood, it uses ENet library to manage connected
peers and bandwidth among these.
NOTES :
*/
class CNetServer : public CNetHost,
public CJSObject<CNetServer>,
public CTurnManager
{
public:
CNetServer( CGame* pGame, CGameAttributes* pGameAttributes );
virtual ~CNetServer( void );
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
// void Shutdown ( void );
/**
* Returns true indicating the host acts as a server
*
* @return Always true
*/
virtual bool IsServer( void ) const { return true; }
/**
* Adds a new session to the list of sessions
*
* @param pSession New session to add
*/
void AddSession( CNetSession* pSession );
/**
* Removes the specified session from the list of sessions. If the session
* isn't found it returns NULL otherwise it returns the session object found.
*
* @param pSession Session to remove
* @return The session object if found, NULL otherwise
*/
CNetSession* RemoveSession( CNetSession* pSession );
/**
* Removes all the sessions managed by the network server
*
*/
//void RemoveAllSessions( void );
/**
* Returns the number of session the server manages
*
* @return The number of sessions
*/
//uint GetSessionCount( void ) const;
/**
* Returns the session object for the specified ID
*
* @param sessionID The session ID
* @return A pointer to session for the specified ID or
* NULL if not found
*/
CNetSession* GetSessionByID( uint sessionID );
protected:
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession *pSession );
private:
// Not implemented
CNetServer( const CNetServer& );
CNetServer& operator=( const CNetServer& );
//void ClientConnect ( ENetPeer* pPeer );
//void ClientDisconnect ( ENetPeer* pPeer );
//void ClientReceive ( ENetPeer* pPeer, ENetPacket* pPacket );
/**
* Returns the session associated with the specified ENet peer
*
* @param pPeer ENet peer
* @return The session object if found or NULL
*/
//CNetSession* GetSessionByPeer( const ENetPeer* pPeer );
/**
* Setup client game by sending the apropiate network messages. It also
* inform the client about the other connected clients as well as player
* slot assignment and attributes.
*
*/
//void SetupNewSession( CNetSession* pSession );
/**
* Loads the player properties into the specified message
*
* @param pMessage Message where to load player properties
* @param pPlayer Player for which we load the properties
*/
void BuildPlayerConfigMessage(
CPlayerConfigMessage* pMessage,
CPlayer* pPlayer );
/**
* Callback function used by the BuildPlayerSetupMessage to iterate over
* the player properties. It will be called for each property of the player
*
* @param name Property name
* @param pProperty Pointer to player property
* @param pData Context pointer passed on iteration startup
*/
static void PlayerConfigMessageCallback(
const CStrW& name,
ISynchedJSProperty* pProperty,
void* pData );
/**
* Loads game properties into the specified message
*
* @param pMessage Message where to load game properties
*/
void BuildGameSetupMessage( CGameSetupMessage* pMessage );
/**
* Loads player slot properties into the specified message
*
* @param pMessage Message where to load player properties
* @param pPlayerSlot Player slot properties
*/
void BuildPlayerSlotAssignmentMessage(
CAssignPlayerSlotMessage* pMessage,
CPlayerSlot* pPlayerSlot );
/**
* Callback function used by the BuildGameSetupMessage to iterate over the
* game properties. It will be called for each property of the game
*
* @param name Property name
* @param pProperty Pointer to game property
* @param pData Context pointer passed on iteration startup
*/
// IterateCB GameSetupMessageCallbak;
static void GameSetupMessageCallback(
const CStrW& name,
ISynchedJSProperty *pProperty,
void *pData );
/**
* Retrieves a free session ID from the recycled sessions list
*
* @return Free session ID
*/
uint GetFreeSessionID( void ) const;
IDSessionMap m_IDSessions; // List of connected ID and session pairs
//CScriptObject m_ScriptConnect; // Script client connect dispatch
//CScriptObject m_ScriptDisconnect; // Script client disconnect dispatch
//CScriptObject m_ScriptChat; // Script client chat dispatch
CPlayer* m_Player; // Server player
public:
/**
*
*
* @param addr Address where to bind
* @return PS_OK if bind successfully, error code otherwise
*/
//PS_RESULT Bind( const CSocketAddress& addr );
void SetPlayerPassword ( const CStr& password );
CStrW GetPlayerName ( void ) const { return m_PlayerName; }
NetServerState GetState ( void ) const { return m_State; }
int StartGame ( void );
static void ScriptingInit ( void );
protected:
// Assign a session ID to the session. Do this just before calling AddSession
void AssignSessionID( CNetSession* pSession );
// Add the session. This will be called after the session passes the
// handshake and authentication stages. AssignSessionID should've been called
// on the session prior to calling this method.
//void AddSession( CNetServerSession* pSession );
// Remove the session from the server
//void RemoveSession( CNetServerSession* pSession );
// Queue a command coming in from the wire. The command has been validated
// by the caller.
void QueueIncomingCommand( CNetMessage* pMessage );
// Call the JS callback for incoming events
void OnPlayerChat ( const CStrW& from, const CStrW& message );
void OnPlayerJoin ( CNetSession* pSession );
void OnPlayerLeave ( CNetSession* pSession );
void SetupPlayer ( CNetSession* pSession );
//static bool OnPlayerJoin ( void* pContext, CFsmEvent* pEvent );
static bool OnError ( void* pContext, CFsmEvent* pEvent );
static bool OnHandshake ( void* pContext, CFsmEvent* pEvent );
static bool OnAuthenticate ( void* pContext, CFsmEvent* pEvent );
static bool OnPreGame ( void* pContext, CFsmEvent* pEvent );
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
// OVERRIDES FROM CServerSocket
//virtual void OnAccept( const CSocketAddress& address );
// OVERRIDES FROM CTurnManager
virtual void NewTurn( void );
virtual bool NewTurnReady( void );
virtual void QueueLocalCommand( CNetMessage* pMessage );
// Will only be called from the Network Thread, by the OnAccept handler
//virtual CNetServerSession* CreateSession( CSocketInternal* pSocketInternal);
// Ask the server if the session is allowed to start observing.
//
// Returns:
// true if the session should be made an observer
// false otherwise
virtual bool AllowObserver( CNetSession* pSession );
private:
CGameAttributes* m_GameAttributes; // Stores game attributes
//int m_LastSessionID; // Stores the last session ID
//SessionMap m_Sessions; // Managed sessions
CJSMap< IDSessionMap > m_JsSessions;
CMutex m_Mutex; // Synchronization object for batches
/*
All sessions that have observer status (observer as in watcher - simple
chatters don't have an entry here, only in m_Sessions).
Sessions are added here after they have successfully requested observer
status.
*/
SessionList m_Observers;
uint m_MaxObservers; // Maximum number of observers
CGame* m_Game; // Pointer to actual game
NetServerState m_State; // Holds server state
CStrW m_Name; // Server name
CStrW m_WelcomeMessage; // Nice welcome message
//CPlayer* m_Player; // Pointer to 'server' player
CStrW m_PlayerName; // Player name
CStrW m_PlayerPassword; // Player password
int m_Port; // The listening port
CScriptObject m_OnChat;
CScriptObject m_OnClientConnect;
CScriptObject m_OnClientDisconnect;
// static CGameAttributes::UpdateCallback AttributeUpdate;
// static CPlayer::UpdateCallback PlayerAttributeUpdate;
// static PlayerSlotAssignmentCB PlayerSlotAssignmentCallback;
static void AttributeUpdate ( const CStrW& name, const CStrW& newValue, void* pData);
static void PlayerAttributeUpdate ( const CStrW& name, const CStrW& value, CPlayer* pPlayer, void* pData );
static void PlayerSlotAssignment ( void* pData, CPlayerSlot* pPlayerSlot );
};
extern CNetServer *g_NetServer;
#endif // NETSERVER_H

File diff suppressed because it is too large Load Diff

View File

@ -1,341 +1,341 @@
/**
*-----------------------------------------------------------------------------
* FILE : NetSession.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network session class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETSESSION_H
#define NETSESSION_H
// INCLUDES
#include "Network.h"
#include "ps/Singleton.h"
#include "ps/GameAttributes.h"
#include "ps/Player.h"
#include "fsm.h"
#include <enet/enet.h>
#include <vector>
// DECLARATIONS
#define INVALID_SESSION 0
#define ENET_DEFAULT_CHANNEL 0
class CNetSession;
class CNetHost;
typedef struct
{
ENetPeer* pPeer;
CNetSession* pSession;
} PeerSession;
typedef struct
{
CNetHost* pHost;
CNetSession* pSession;
} FsmActionCtx;
typedef std::vector< PeerSession > PeerSessionList;
/*
CLASS : CNetHost
DESCRIPTION : CNetHost is a wrapper around ENet host conecept
NOTES :
*/
class CNetHost : public Singleton< CNetHost >
{
public:
CNetHost( void );
virtual ~CNetHost( void );
bool Create( void );
bool Create( uint port, uint maxPeers );
void Shutdown( void );
/**
* Indicates whether the host is currently a server
*
* @return Boolean indicating whether the host is a server
*/
virtual bool IsServer( void ) const { return false; }
/**
* Indicates whether the host is currently a client
*
* @return Boolean indicating whether the host is a client
*/
virtual bool IsClient( void ) const { return false; }
/**
* Returns the number of sessions for the host
*
* @return The number of sessions
*/
uint GetSessionCount( void ) const;
/**
* Returns the session object for the specified index
*
* @param index Index for session
* @return Session object for index or NULL if not found
*/
CNetSession* GetSession( uint index );
/**
* Connects to foreign host
*
* @param host Foreign host name
* @param port Port on which the foreign host listens
* @return true on success, false on failure
*/
bool Connect( const CStr& host, uint port );
/**
* Disconnects session from host
*
* @param pSession Session representing peer
* @return true on success, false otherwise
*/
bool Disconnect( CNetSession* pSession );
/**
* Listens for incoming connections and dispatches host events
*
* @return true on exit, false dispatch failure
*/
//bool Run( void );
bool Poll( void );
/**
* Broadcast the specified message to connected clients
*
* @param pMessage Message to broadcast
*/
void Broadcast( const CNetMessage* pMessage );
/**
* Send the specified message to client
*
* @param pMessage The message to send
*/
virtual bool SendMessage(
const CNetSession* pSession,
const CNetMessage* pMessage );
/**
* Receive a message from client if available
*
*/
virtual CNetMessage* ReceiveMessage( const CNetSession* pSession );
protected:
/**
* Attempts to resize the internal buffer to the size indicated by the
* passed parameter.
*
* @param size The new size for the buffer
*/
void ResizeBuffer( size_t size );
// Allow application to handle new client connect
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession* pSession );
virtual bool HandleMessageReceive (
CNetMessage* pMessage,
CNetSession* pSession );
/**
* Worker thread function
*
* @pData Argument specified on thread creation
* @return NULL
*/
//static void* WorkerFunc( void* pData );
private:
// Not implemented
CNetHost( const CNetHost& );
CNetHost& operator=( const CNetHost& );
u8* m_Buffer; // Serialize out messages buffer
size_t m_BufferSize; // Output buffer size
ENetHost* m_Host; // Represents this host
PeerSessionList m_PeerSessions; // Session list of connected peers
//pthread_t m_WorkerID; // Worker thread
//sem_t* m_StopWorker; // Worker thread stop semaphore
};
/*
CLASS : CNetSession
DESCRIPTION : CNetSession is a wrapper class around ENet peer concept
which represents a peer from a network connection. A
network session is spawned by CNetServer each time a
client connects and destroyed when it disconnects. When a
new message is received fom a client, its representing
session object's message handler is called for processing
that message.
CNetSession is also a state machine. All client requests
are delegated to the current state. The current
CNetSessionState object's methods will change the current
state as appropriate.
NOTES :
*/
class CNetSession : public CFsm,
public CJSObject< CNetSession >,
public IMessagePipeEnd
{
friend class CNetHost;
public:
virtual ~CNetSession( void );
/**
* Retrieves the name of the session
*
* @return Session name
*/
const CStrW& GetName( void ) const { return m_Name; }
/**
* Set the new name for the session
*
* @param name The session new name
*/
void SetName( const CStr& name );
/**
* Retrieves the ID of the session
*
* @return Session ID
*/
uint GetID( void ) const { return m_ID; }
/**
* Set the ID for this session
*
* @param New session ID
*/
void SetID( uint ID );
/**
* Allows both client and server to set a callback handler
*
* @param pCallbackHandler Callback handler
*/
//void SetCallbackHandler( ISessionCallback* pCallbackHandler );
/**
* Disconnects the client from remote host
*
*/
void Reset( void );
void SetPlayer( CPlayer* pPlayer );
CPlayer* GetPlayer( void ) { return m_Player; }
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
void StartGame( void );
virtual void Push( CNetMessage* pMessage );
virtual CNetMessage* TryPop( void );
bool IsReadyForTurn( void ) const { return m_ReadyForTurn; }
void SetReadyForTurn( bool newValue ) { m_ReadyForTurn = newValue; }
bool JSI_Close( JSContext *cx, uintN argc, jsval *argv );
static void ScriptingInit( void );
//bool HandleMessage( CNetMessage* pMessage );
protected:
/**
* Process the message passed as parameter
*
* @param message The message to process
* @return true if the message was handler
* successufully, false otherwise
*/
//bool ProcessMessage( const CNetMessage& message );
private:
// Only the hosts can create sessions
CNetSession( CNetHost* pHost, ENetPeer* pPeer );
// Not implemented
CNetSession( void );
CNetSession( const CNetSession& );
CNetSession& operator=( const CNetSession& );
CNetHost* m_Host; // The associated local host
ENetPeer* m_Peer; // Represents the peer host
uint m_ID; // Session ID
CStrW m_Name; // Session name
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_ReadyForTurn; // Next turn ready flag
};
/*
CLASS : CNetServerSession
DESCRIPTION :
NOTES :
*/
/*class CNetServerSession : public CNetSession,
public CJSObject< CNetServerSession >
{
public:
bool IsObserver ( void ) const { return m_IsObserver; }
CPlayer* GetPlayer ( void ) const { return m_Player; }
CPlayerSlot* GetPlayerSlot ( void ) const { return m_PlayerSlot; }
void StartGame ( void );
void SetPlayer ( CPlayer* pPlayer );
void SetPlayerSlot ( CPlayerSlot* pPlayerSlot );
protected:
CNetServerSession(
CNetServer* pServer,
NetMessageHandler* pHandler = m_HandshakeHandler );
CNetServerSession(
CNetServer* pServer,
CSocketInternal* pSocketInternal,
NetMessageHandler* pHandler = m_HandshakeHandler );
virtual ~CNetServerSession( void );
private:
static void ScriptingInit ( void );
bool JSI_Close (
JSContext* pContext,
uintN argc,
jsval* argv );
CNetServer* m_Server;
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_IsObserver;
static bool HandshakeHandler( CNetMessage* pMessage, CNetSession* pSession );
static bool ObserverHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool BaseHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool AuthHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool PreGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool InGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool ChatHandler ( CNetMessage* pMessage, CNetSession* pSession );
};*/
#endif // NETSESSION_H
/**
*-----------------------------------------------------------------------------
* FILE : NetSession.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network session class interface file
*-----------------------------------------------------------------------------
*/
#ifndef NETSESSION_H
#define NETSESSION_H
// INCLUDES
#include "Network.h"
#include "ps/Singleton.h"
#include "ps/GameAttributes.h"
#include "ps/Player.h"
#include "fsm.h"
#include <enet/enet.h>
#include <vector>
// DECLARATIONS
#define INVALID_SESSION 0
#define ENET_DEFAULT_CHANNEL 0
class CNetSession;
class CNetHost;
typedef struct
{
ENetPeer* pPeer;
CNetSession* pSession;
} PeerSession;
typedef struct
{
CNetHost* pHost;
CNetSession* pSession;
} FsmActionCtx;
typedef std::vector< PeerSession > PeerSessionList;
/*
CLASS : CNetHost
DESCRIPTION : CNetHost is a wrapper around ENet host conecept
NOTES :
*/
class CNetHost : public Singleton< CNetHost >
{
public:
CNetHost( void );
virtual ~CNetHost( void );
bool Create( void );
bool Create( uint port, uint maxPeers );
void Shutdown( void );
/**
* Indicates whether the host is currently a server
*
* @return Boolean indicating whether the host is a server
*/
virtual bool IsServer( void ) const { return false; }
/**
* Indicates whether the host is currently a client
*
* @return Boolean indicating whether the host is a client
*/
virtual bool IsClient( void ) const { return false; }
/**
* Returns the number of sessions for the host
*
* @return The number of sessions
*/
uint GetSessionCount( void ) const;
/**
* Returns the session object for the specified index
*
* @param index Index for session
* @return Session object for index or NULL if not found
*/
CNetSession* GetSession( uint index );
/**
* Connects to foreign host
*
* @param host Foreign host name
* @param port Port on which the foreign host listens
* @return true on success, false on failure
*/
bool Connect( const CStr& host, uint port );
/**
* Disconnects session from host
*
* @param pSession Session representing peer
* @return true on success, false otherwise
*/
bool Disconnect( CNetSession* pSession );
/**
* Listens for incoming connections and dispatches host events
*
* @return true on exit, false dispatch failure
*/
//bool Run( void );
bool Poll( void );
/**
* Broadcast the specified message to connected clients
*
* @param pMessage Message to broadcast
*/
void Broadcast( const CNetMessage* pMessage );
/**
* Send the specified message to client
*
* @param pMessage The message to send
*/
virtual bool SendMessage(
const CNetSession* pSession,
const CNetMessage* pMessage );
/**
* Receive a message from client if available
*
*/
virtual CNetMessage* ReceiveMessage( const CNetSession* pSession );
protected:
/**
* Attempts to resize the internal buffer to the size indicated by the
* passed parameter.
*
* @param size The new size for the buffer
*/
void ResizeBuffer( size_t size );
// Allow application to handle new client connect
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession* pSession );
virtual bool HandleMessageReceive (
CNetMessage* pMessage,
CNetSession* pSession );
/**
* Worker thread function
*
* @pData Argument specified on thread creation
* @return NULL
*/
//static void* WorkerFunc( void* pData );
private:
// Not implemented
CNetHost( const CNetHost& );
CNetHost& operator=( const CNetHost& );
u8* m_Buffer; // Serialize out messages buffer
size_t m_BufferSize; // Output buffer size
ENetHost* m_Host; // Represents this host
PeerSessionList m_PeerSessions; // Session list of connected peers
//pthread_t m_WorkerID; // Worker thread
//sem_t* m_StopWorker; // Worker thread stop semaphore
};
/*
CLASS : CNetSession
DESCRIPTION : CNetSession is a wrapper class around ENet peer concept
which represents a peer from a network connection. A
network session is spawned by CNetServer each time a
client connects and destroyed when it disconnects. When a
new message is received fom a client, its representing
session object's message handler is called for processing
that message.
CNetSession is also a state machine. All client requests
are delegated to the current state. The current
CNetSessionState object's methods will change the current
state as appropriate.
NOTES :
*/
class CNetSession : public CFsm,
public CJSObject< CNetSession >,
public IMessagePipeEnd
{
friend class CNetHost;
public:
virtual ~CNetSession( void );
/**
* Retrieves the name of the session
*
* @return Session name
*/
const CStrW& GetName( void ) const { return m_Name; }
/**
* Set the new name for the session
*
* @param name The session new name
*/
void SetName( const CStr& name );
/**
* Retrieves the ID of the session
*
* @return Session ID
*/
uint GetID( void ) const { return m_ID; }
/**
* Set the ID for this session
*
* @param New session ID
*/
void SetID( uint ID );
/**
* Allows both client and server to set a callback handler
*
* @param pCallbackHandler Callback handler
*/
//void SetCallbackHandler( ISessionCallback* pCallbackHandler );
/**
* Disconnects the client from remote host
*
*/
void Reset( void );
void SetPlayer( CPlayer* pPlayer );
CPlayer* GetPlayer( void ) { return m_Player; }
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
void StartGame( void );
virtual void Push( CNetMessage* pMessage );
virtual CNetMessage* TryPop( void );
bool IsReadyForTurn( void ) const { return m_ReadyForTurn; }
void SetReadyForTurn( bool newValue ) { m_ReadyForTurn = newValue; }
bool JSI_Close( JSContext *cx, uintN argc, jsval *argv );
static void ScriptingInit( void );
//bool HandleMessage( CNetMessage* pMessage );
protected:
/**
* Process the message passed as parameter
*
* @param message The message to process
* @return true if the message was handler
* successufully, false otherwise
*/
//bool ProcessMessage( const CNetMessage& message );
private:
// Only the hosts can create sessions
CNetSession( CNetHost* pHost, ENetPeer* pPeer );
// Not implemented
CNetSession( void );
CNetSession( const CNetSession& );
CNetSession& operator=( const CNetSession& );
CNetHost* m_Host; // The associated local host
ENetPeer* m_Peer; // Represents the peer host
uint m_ID; // Session ID
CStrW m_Name; // Session name
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_ReadyForTurn; // Next turn ready flag
};
/*
CLASS : CNetServerSession
DESCRIPTION :
NOTES :
*/
/*class CNetServerSession : public CNetSession,
public CJSObject< CNetServerSession >
{
public:
bool IsObserver ( void ) const { return m_IsObserver; }
CPlayer* GetPlayer ( void ) const { return m_Player; }
CPlayerSlot* GetPlayerSlot ( void ) const { return m_PlayerSlot; }
void StartGame ( void );
void SetPlayer ( CPlayer* pPlayer );
void SetPlayerSlot ( CPlayerSlot* pPlayerSlot );
protected:
CNetServerSession(
CNetServer* pServer,
NetMessageHandler* pHandler = m_HandshakeHandler );
CNetServerSession(
CNetServer* pServer,
CSocketInternal* pSocketInternal,
NetMessageHandler* pHandler = m_HandshakeHandler );
virtual ~CNetServerSession( void );
private:
static void ScriptingInit ( void );
bool JSI_Close (
JSContext* pContext,
uintN argc,
jsval* argv );
CNetServer* m_Server;
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_IsObserver;
static bool HandshakeHandler( CNetMessage* pMessage, CNetSession* pSession );
static bool ObserverHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool BaseHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool AuthHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool PreGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool InGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool ChatHandler ( CNetMessage* pMessage, CNetSession* pSession );
};*/
#endif // NETSESSION_H

View File

@ -1,445 +1,445 @@
/**
*-----------------------------------------------------------------------------
* FILE : fsm.cpp
* PROJECT : 0 A.D.
* DESCRIPTION : Finite state machine class implementation
*-----------------------------------------------------------------------------
*/
// INCLUDES
#include "precompiled.h"
#include "fsm.h"
// DECLARATIONS
//-----------------------------------------------------------------------------
// Name: CFsmEvent()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsmEvent::CFsmEvent( unsigned int type )
{
m_Type = type;
m_Param = NULL;
}
//-----------------------------------------------------------------------------
// Name; ~CFsmEvent()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsmEvent::~CFsmEvent( void )
{
m_Param = NULL;
}
//-----------------------------------------------------------------------------
// Name: SetParamRef()
// Desc: Sets the parameter for the event
//-----------------------------------------------------------------------------
void CFsmEvent::SetParamRef( void* pParam )
{
m_Param = pParam;
}
//-----------------------------------------------------------------------------
// Name: CFsmTransition()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsmTransition::CFsmTransition( unsigned int state )
{
m_CurrState = state;
}
//-----------------------------------------------------------------------------
// Name: ~CFsmTransition()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsmTransition::~CFsmTransition( void )
{
m_Actions.clear();
m_Conditions.clear();
}
//-----------------------------------------------------------------------------
// Name: RegisterAction()
// Desc: Adds action that will be executed when the transition will occur
//-----------------------------------------------------------------------------
void CFsmTransition::RegisterAction( void* pAction, void* pContext )
{
CallbackFunction callback;
// Add action at the end of actions list
callback.pFunction = pAction;
callback.pContext = pContext;
m_Actions.push_back( callback );
}
//-----------------------------------------------------------------------------
// Name: AddCondition()
// Desc: Adds condition which will be evaluated when the transition will occurs
//-----------------------------------------------------------------------------
void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
{
CallbackFunction callback;
// Add condition at the end of conditions list
callback.pFunction = pCondition;
callback.pContext = pContext;
m_Conditions.push_back( callback );
}
//-----------------------------------------------------------------------------
// Name: SetEvent()
// Desc: Set event for which transition will occur
//-----------------------------------------------------------------------------
void CFsmTransition::SetEvent( CFsmEvent* pEvent )
{
m_Event = pEvent;
}
//-----------------------------------------------------------------------------
// Name: SetNextState()
// Desc: Set next state the transition will switch the system to
//-----------------------------------------------------------------------------
void CFsmTransition::SetNextState( unsigned int nextState )
{
m_NextState = nextState;
}
//-----------------------------------------------------------------------------
// Name: ApplyConditions()
// Desc: Evaluate conditions for the transition
// Note: If there are no conditions, assume true
//-----------------------------------------------------------------------------
bool CFsmTransition::ApplyConditions( void ) const
{
bool eval = true;
CallbackList::const_iterator it = m_Conditions.begin();
for( ; it != m_Conditions.end(); it++ )
{
if ( it->pFunction )
{
// Evaluate condition
CONDITION Condition = ( CONDITION )it->pFunction;
eval &= Condition( it->pContext );
}
}
return eval;
}
//-----------------------------------------------------------------------------
// Name: RunActions()
// Desc: Execur actions for the transition
// Note: If there are no actions, assume true
//-----------------------------------------------------------------------------
bool CFsmTransition::RunActions( void ) const
{
bool result = true;
CallbackList::const_iterator it = m_Actions.begin();
for( ; it != m_Actions.end(); it++ )
{
if ( it->pFunction )
{
// Run action
ACTION Action = ( ACTION )it->pFunction;
result &= Action( it->pContext, m_Event );
}
}
return result;
}
//-----------------------------------------------------------------------------
// Name: CFsm()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsm::CFsm( void )
{
m_Done = false;
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
}
//-----------------------------------------------------------------------------
// Name: ~CFsm()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsm::~CFsm( void )
{
Shutdown();
}
//-----------------------------------------------------------------------------
// Name: Setup()
// Desc: Setup events, actions and state transitions
//-----------------------------------------------------------------------------
void CFsm::Setup( void )
{
// Does nothing by default
}
//-----------------------------------------------------------------------------
// Name: Reset()
// Desc: Shuts down the state machine and releases any resources
//-----------------------------------------------------------------------------
void CFsm::Shutdown( void )
{
// Release transitions
TransitionList::iterator itTransition = m_Transitions.begin();
for ( ; itTransition < m_Transitions.end(); itTransition++ )
{
CFsmTransition* pCurrTransition = *itTransition;
if ( !pCurrTransition ) continue;
delete pCurrTransition;
}
// Release events
EventMap::iterator itEvent = m_Events.begin();
for( ; itEvent != m_Events.end(); itEvent++ )
{
CFsmEvent* pCurrEvent = itEvent->second;
if ( !pCurrEvent ) continue;
delete pCurrEvent;
}
m_States.clear();
m_Events.clear();
m_Transitions.clear();
m_Done = false;
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
}
//-----------------------------------------------------------------------------
// Name: AddState()
// Desc: Adds the specified state to the internal list of states
// Note: If a state with the specified ID exists, the state is not added
//-----------------------------------------------------------------------------
void CFsm::AddState( unsigned int state )
{
m_States.insert( state );
}
//-----------------------------------------------------------------------------
// Name: AddEvent()
// Desc: Adds the specified event to the internal list of events
// Note: If an eveny with the specified ID exists, the event is not added
//-----------------------------------------------------------------------------
CFsmEvent* CFsm::AddEvent( unsigned int eventType )
{
CFsmEvent* pEvent = NULL;
// Lookup event by type
EventMap::iterator it = m_Events.find( eventType );
if ( it != m_Events.end() )
{
pEvent = it->second;
}
else
{
pEvent = new CFsmEvent( eventType );
if ( !pEvent ) return NULL;
// Store new event into internal map
m_Events[ eventType ] = pEvent;
}
return pEvent;
}
//-----------------------------------------------------------------------------
// Name: AddTransition()
// Desc: Adds a new transistion to the state machine
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::AddTransition(
unsigned int state,
unsigned int eventType,
unsigned int nextState )
{
// Make sure we store the current state
AddState( state );
// Make sure we store the next state
AddState( nextState );
// Make sure we store the event
CFsmEvent* pEvent = AddEvent( eventType );
if ( !pEvent ) return NULL;
// Create new transition
CFsmTransition* pNewTransition = new CFsmTransition( state );
if ( !pNewTransition ) return NULL;
// Setup new transition
pNewTransition->SetEvent( pEvent );
pNewTransition->SetNextState( nextState );
// Store new transition
m_Transitions.push_back( pNewTransition );
return pNewTransition;
}
//-----------------------------------------------------------------------------
// Name: AddTransition()
// Desc: Adds a new transistion to the state machine
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::AddTransition(
unsigned int state,
unsigned int eventType,
unsigned int nextState,
void* pAction,
void* pContext )
{
CFsmTransition* pTransition = AddTransition( state, eventType, nextState );
if ( !pTransition ) return NULL;
// If action specified, register it
if ( pAction )
pTransition->RegisterAction( pAction, pContext );
return pTransition;
}
//-----------------------------------------------------------------------------
// Name: GetTransition()
// Desc: Lookup transition given the state, event and next state to transition
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::GetTransition(
unsigned int state,
unsigned int eventType ) const
{
// Valid state?
if ( !IsValidState( state ) ) return NULL;
// Valid event?
if ( !IsValidEvent( eventType ) ) return NULL;
// Loop through the list of transitions
TransitionList::const_iterator it = m_Transitions.begin();
for ( ; it != m_Transitions.end(); it++ )
{
CFsmTransition* pCurrTransition = *it;
if ( !pCurrTransition ) continue;
CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
if ( !pCurrEvent ) continue;
// Is it our transition?
if ( pCurrTransition->GetCurrState() == state &&
pCurrEvent->GetType() == eventType )
{
return pCurrTransition;
}
}
// No transition found
return NULL;
}
//-----------------------------------------------------------------------------
// Name: SetFirstState()
// Desc: Set initial state for FSM
//-----------------------------------------------------------------------------
void CFsm::SetFirstState( unsigned int firstState )
{
m_FirstState = firstState;
}
//-----------------------------------------------------------------------------
// Name: SetCurrState()
// Desc: Set current state and update last state to current state
//-----------------------------------------------------------------------------
void CFsm::SetCurrState( unsigned int state )
{
m_CurrState = state;
}
//-----------------------------------------------------------------------------
// Name: IsFirstTime()
// Desc: Verifies if the state machine has been already updated
//-----------------------------------------------------------------------------
bool CFsm::IsFirstTime( void ) const
{
return ( m_CurrState == FSM_INVALID_STATE );
}
//-----------------------------------------------------------------------------
// Name: Update()
// Desc: Updates state machine and retrieves next state
//-----------------------------------------------------------------------------
bool CFsm::Update( unsigned int eventType, void* pEventParam )
{
// Valid event?
if ( !IsValidEvent( eventType ) )
return false;
// First time update?
if ( IsFirstTime() )
m_CurrState = m_FirstState;
// Lookup transition
CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
if ( !pTransition ) return false;
// Setup event parameter
EventMap::iterator it = m_Events.find( eventType );
if ( it != m_Events.end() )
{
CFsmEvent* pEvent = it->second;
if ( pEvent ) pEvent->SetParamRef( pEventParam );
}
// Valid transition?
if ( !pTransition->ApplyConditions() ) return false;
// Run transition actions
if ( !pTransition->RunActions() ) return false;
// Switch state
SetCurrState( pTransition->GetNextState() );
return true;
}
//-----------------------------------------------------------------------------
// Name: IsDone()
// Desc: Tests whether the state machine has finished its work
// Note: This is state machine specific
//-----------------------------------------------------------------------------
bool CFsm::IsDone( void ) const
{
// By default the internal flag m_Done is tested
return m_Done;
}
//-----------------------------------------------------------------------------
// Name: IsValidState()
// Desc: Verifies whether the specified state is managed by FSM
//-----------------------------------------------------------------------------
bool CFsm::IsValidState( unsigned int state ) const
{
StateSet::const_iterator it = m_States.find( state );
if ( it == m_States.end() ) return false;
return true;
}
//-----------------------------------------------------------------------------
// Name: IsValidEvent()
// Desc: Verifies whether the specified event is managed by FSM
//-----------------------------------------------------------------------------
bool CFsm::IsValidEvent( unsigned int eventType ) const
{
EventMap::const_iterator it = m_Events.find( eventType );
if ( it == m_Events.end() ) return false;
return true;
}
/**
*-----------------------------------------------------------------------------
* FILE : fsm.cpp
* PROJECT : 0 A.D.
* DESCRIPTION : Finite state machine class implementation
*-----------------------------------------------------------------------------
*/
// INCLUDES
#include "precompiled.h"
#include "fsm.h"
// DECLARATIONS
//-----------------------------------------------------------------------------
// Name: CFsmEvent()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsmEvent::CFsmEvent( unsigned int type )
{
m_Type = type;
m_Param = NULL;
}
//-----------------------------------------------------------------------------
// Name; ~CFsmEvent()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsmEvent::~CFsmEvent( void )
{
m_Param = NULL;
}
//-----------------------------------------------------------------------------
// Name: SetParamRef()
// Desc: Sets the parameter for the event
//-----------------------------------------------------------------------------
void CFsmEvent::SetParamRef( void* pParam )
{
m_Param = pParam;
}
//-----------------------------------------------------------------------------
// Name: CFsmTransition()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsmTransition::CFsmTransition( unsigned int state )
{
m_CurrState = state;
}
//-----------------------------------------------------------------------------
// Name: ~CFsmTransition()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsmTransition::~CFsmTransition( void )
{
m_Actions.clear();
m_Conditions.clear();
}
//-----------------------------------------------------------------------------
// Name: RegisterAction()
// Desc: Adds action that will be executed when the transition will occur
//-----------------------------------------------------------------------------
void CFsmTransition::RegisterAction( void* pAction, void* pContext )
{
CallbackFunction callback;
// Add action at the end of actions list
callback.pFunction = pAction;
callback.pContext = pContext;
m_Actions.push_back( callback );
}
//-----------------------------------------------------------------------------
// Name: AddCondition()
// Desc: Adds condition which will be evaluated when the transition will occurs
//-----------------------------------------------------------------------------
void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
{
CallbackFunction callback;
// Add condition at the end of conditions list
callback.pFunction = pCondition;
callback.pContext = pContext;
m_Conditions.push_back( callback );
}
//-----------------------------------------------------------------------------
// Name: SetEvent()
// Desc: Set event for which transition will occur
//-----------------------------------------------------------------------------
void CFsmTransition::SetEvent( CFsmEvent* pEvent )
{
m_Event = pEvent;
}
//-----------------------------------------------------------------------------
// Name: SetNextState()
// Desc: Set next state the transition will switch the system to
//-----------------------------------------------------------------------------
void CFsmTransition::SetNextState( unsigned int nextState )
{
m_NextState = nextState;
}
//-----------------------------------------------------------------------------
// Name: ApplyConditions()
// Desc: Evaluate conditions for the transition
// Note: If there are no conditions, assume true
//-----------------------------------------------------------------------------
bool CFsmTransition::ApplyConditions( void ) const
{
bool eval = true;
CallbackList::const_iterator it = m_Conditions.begin();
for( ; it != m_Conditions.end(); it++ )
{
if ( it->pFunction )
{
// Evaluate condition
CONDITION Condition = ( CONDITION )it->pFunction;
eval &= Condition( it->pContext );
}
}
return eval;
}
//-----------------------------------------------------------------------------
// Name: RunActions()
// Desc: Execur actions for the transition
// Note: If there are no actions, assume true
//-----------------------------------------------------------------------------
bool CFsmTransition::RunActions( void ) const
{
bool result = true;
CallbackList::const_iterator it = m_Actions.begin();
for( ; it != m_Actions.end(); it++ )
{
if ( it->pFunction )
{
// Run action
ACTION Action = ( ACTION )it->pFunction;
result &= Action( it->pContext, m_Event );
}
}
return result;
}
//-----------------------------------------------------------------------------
// Name: CFsm()
// Desc: Constructor
//-----------------------------------------------------------------------------
CFsm::CFsm( void )
{
m_Done = false;
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
}
//-----------------------------------------------------------------------------
// Name: ~CFsm()
// Desc: Destructor
//-----------------------------------------------------------------------------
CFsm::~CFsm( void )
{
Shutdown();
}
//-----------------------------------------------------------------------------
// Name: Setup()
// Desc: Setup events, actions and state transitions
//-----------------------------------------------------------------------------
void CFsm::Setup( void )
{
// Does nothing by default
}
//-----------------------------------------------------------------------------
// Name: Reset()
// Desc: Shuts down the state machine and releases any resources
//-----------------------------------------------------------------------------
void CFsm::Shutdown( void )
{
// Release transitions
TransitionList::iterator itTransition = m_Transitions.begin();
for ( ; itTransition < m_Transitions.end(); itTransition++ )
{
CFsmTransition* pCurrTransition = *itTransition;
if ( !pCurrTransition ) continue;
delete pCurrTransition;
}
// Release events
EventMap::iterator itEvent = m_Events.begin();
for( ; itEvent != m_Events.end(); itEvent++ )
{
CFsmEvent* pCurrEvent = itEvent->second;
if ( !pCurrEvent ) continue;
delete pCurrEvent;
}
m_States.clear();
m_Events.clear();
m_Transitions.clear();
m_Done = false;
m_FirstState = ( unsigned int )FSM_INVALID_STATE;
m_CurrState = ( unsigned int )FSM_INVALID_STATE;
}
//-----------------------------------------------------------------------------
// Name: AddState()
// Desc: Adds the specified state to the internal list of states
// Note: If a state with the specified ID exists, the state is not added
//-----------------------------------------------------------------------------
void CFsm::AddState( unsigned int state )
{
m_States.insert( state );
}
//-----------------------------------------------------------------------------
// Name: AddEvent()
// Desc: Adds the specified event to the internal list of events
// Note: If an eveny with the specified ID exists, the event is not added
//-----------------------------------------------------------------------------
CFsmEvent* CFsm::AddEvent( unsigned int eventType )
{
CFsmEvent* pEvent = NULL;
// Lookup event by type
EventMap::iterator it = m_Events.find( eventType );
if ( it != m_Events.end() )
{
pEvent = it->second;
}
else
{
pEvent = new CFsmEvent( eventType );
if ( !pEvent ) return NULL;
// Store new event into internal map
m_Events[ eventType ] = pEvent;
}
return pEvent;
}
//-----------------------------------------------------------------------------
// Name: AddTransition()
// Desc: Adds a new transistion to the state machine
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::AddTransition(
unsigned int state,
unsigned int eventType,
unsigned int nextState )
{
// Make sure we store the current state
AddState( state );
// Make sure we store the next state
AddState( nextState );
// Make sure we store the event
CFsmEvent* pEvent = AddEvent( eventType );
if ( !pEvent ) return NULL;
// Create new transition
CFsmTransition* pNewTransition = new CFsmTransition( state );
if ( !pNewTransition ) return NULL;
// Setup new transition
pNewTransition->SetEvent( pEvent );
pNewTransition->SetNextState( nextState );
// Store new transition
m_Transitions.push_back( pNewTransition );
return pNewTransition;
}
//-----------------------------------------------------------------------------
// Name: AddTransition()
// Desc: Adds a new transistion to the state machine
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::AddTransition(
unsigned int state,
unsigned int eventType,
unsigned int nextState,
void* pAction,
void* pContext )
{
CFsmTransition* pTransition = AddTransition( state, eventType, nextState );
if ( !pTransition ) return NULL;
// If action specified, register it
if ( pAction )
pTransition->RegisterAction( pAction, pContext );
return pTransition;
}
//-----------------------------------------------------------------------------
// Name: GetTransition()
// Desc: Lookup transition given the state, event and next state to transition
//-----------------------------------------------------------------------------
CFsmTransition* CFsm::GetTransition(
unsigned int state,
unsigned int eventType ) const
{
// Valid state?
if ( !IsValidState( state ) ) return NULL;
// Valid event?
if ( !IsValidEvent( eventType ) ) return NULL;
// Loop through the list of transitions
TransitionList::const_iterator it = m_Transitions.begin();
for ( ; it != m_Transitions.end(); it++ )
{
CFsmTransition* pCurrTransition = *it;
if ( !pCurrTransition ) continue;
CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
if ( !pCurrEvent ) continue;
// Is it our transition?
if ( pCurrTransition->GetCurrState() == state &&
pCurrEvent->GetType() == eventType )
{
return pCurrTransition;
}
}
// No transition found
return NULL;
}
//-----------------------------------------------------------------------------
// Name: SetFirstState()
// Desc: Set initial state for FSM
//-----------------------------------------------------------------------------
void CFsm::SetFirstState( unsigned int firstState )
{
m_FirstState = firstState;
}
//-----------------------------------------------------------------------------
// Name: SetCurrState()
// Desc: Set current state and update last state to current state
//-----------------------------------------------------------------------------
void CFsm::SetCurrState( unsigned int state )
{
m_CurrState = state;
}
//-----------------------------------------------------------------------------
// Name: IsFirstTime()
// Desc: Verifies if the state machine has been already updated
//-----------------------------------------------------------------------------
bool CFsm::IsFirstTime( void ) const
{
return ( m_CurrState == FSM_INVALID_STATE );
}
//-----------------------------------------------------------------------------
// Name: Update()
// Desc: Updates state machine and retrieves next state
//-----------------------------------------------------------------------------
bool CFsm::Update( unsigned int eventType, void* pEventParam )
{
// Valid event?
if ( !IsValidEvent( eventType ) )
return false;
// First time update?
if ( IsFirstTime() )
m_CurrState = m_FirstState;
// Lookup transition
CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
if ( !pTransition ) return false;
// Setup event parameter
EventMap::iterator it = m_Events.find( eventType );
if ( it != m_Events.end() )
{
CFsmEvent* pEvent = it->second;
if ( pEvent ) pEvent->SetParamRef( pEventParam );
}
// Valid transition?
if ( !pTransition->ApplyConditions() ) return false;
// Run transition actions
if ( !pTransition->RunActions() ) return false;
// Switch state
SetCurrState( pTransition->GetNextState() );
return true;
}
//-----------------------------------------------------------------------------
// Name: IsDone()
// Desc: Tests whether the state machine has finished its work
// Note: This is state machine specific
//-----------------------------------------------------------------------------
bool CFsm::IsDone( void ) const
{
// By default the internal flag m_Done is tested
return m_Done;
}
//-----------------------------------------------------------------------------
// Name: IsValidState()
// Desc: Verifies whether the specified state is managed by FSM
//-----------------------------------------------------------------------------
bool CFsm::IsValidState( unsigned int state ) const
{
StateSet::const_iterator it = m_States.find( state );
if ( it == m_States.end() ) return false;
return true;
}
//-----------------------------------------------------------------------------
// Name: IsValidEvent()
// Desc: Verifies whether the specified event is managed by FSM
//-----------------------------------------------------------------------------
bool CFsm::IsValidEvent( unsigned int eventType ) const
{
EventMap::const_iterator it = m_Events.find( eventType );
if ( it == m_Events.end() ) return false;
return true;
}

View File

@ -1,193 +1,193 @@
/**
*-----------------------------------------------------------------------------
* FILE : fsm.h
* PROJECT : 0 A.D.
* DESCRIPTION : Finite state machine class definitions
*-----------------------------------------------------------------------------
*/
#ifndef FSM_H
#define FSM_H
// INCLUDES
#include <vector>
#include <set>
// DECLARATIONS
#define FSM_INVALID_STATE ( unsigned int )( ~0 )
class CFsmEvent;
class CFsmTransition;
class CFsm;
typedef bool ( *CONDITION ) ( void* pContext );
typedef bool ( *ACTION ) ( void* pContext, const CFsmEvent* pEvent );
typedef struct
{
void* pFunction;
void* pContext;
} CallbackFunction;
typedef std::set< unsigned int > StateSet;
typedef std::map< unsigned int, CFsmEvent* > EventMap;
typedef std::vector< CFsmTransition* > TransitionList;
typedef std::vector< CallbackFunction > CallbackList;
/*
CLASS : CFsmEvent
DESCRIPTION : CFsmEvent class represents a signal in the state machine
that a change has occured.
NOTES : The CFsmEvent objects are under the control of CFsm so
they are created and deleted via CFsm.
*/
class CFsmEvent
{
public:
CFsmEvent( unsigned int type );
~CFsmEvent( void );
unsigned int GetType ( void ) const { return m_Type; }
void* GetParamRef ( void ) { return m_Param; }
void SetParamRef ( void* pParam );
protected:
private:
// Not implemented
CFsmEvent( const CFsmEvent& );
CFsmEvent& operator=( const CFsmEvent& );
unsigned int m_Type; // Event type
void* m_Param; // Event paramater
};
/*
CLASS : CFsmTransition
DESCRIPTION : The CFsmTransition class is an association of event, condition,
action and next state.
NOTES :
*/
class CFsmTransition
{
public:
CFsmTransition( unsigned int state );
~CFsmTransition( void );
void RegisterAction (
void* pAction,
void* pContext );
void RegisterCondition (
void* pCondition,
void* pContext );
void SetEvent ( CFsmEvent* pEvent );
CFsmEvent* GetEvent ( void ) const { return m_Event; }
void SetNextState ( unsigned int nextState );
unsigned int GetNextState ( void ) const { return m_NextState; }
unsigned int GetCurrState ( void ) const { return m_CurrState; }
const CallbackList& GetActions ( void ) const { return m_Actions; }
const CallbackList& GetConditions ( void ) const { return m_Conditions; }
bool ApplyConditions ( void ) const;
bool RunActions ( void ) const;
protected:
private:
// Not implemented
CFsmTransition( const CFsmTransition& );
CFsmTransition& operator=( const CFsmTransition& );
unsigned int m_CurrState; // Current state
unsigned int m_NextState; // Next state
CFsmEvent* m_Event; // Transition event
CallbackList m_Actions; // List of actions for transition
CallbackList m_Conditions; // List of conditions for transition
};
/*
CLASS : CFsm
DESCRIPTION : CFsm manages states, events, actions and transitions
between states. It provides an interface for advertising
events and track the current state. The implementation is
a Mealy state machine, so the system respond to events
and execute some action.
NOTES : A Mealy state machine has behaviour associated with state
transitions; Mealy machines are event driven where an
event triggers a state transition
*/
class CFsm
{
public:
CFsm( void );
~CFsm( void );
/**
* Constructs the state machine. This method must be overriden so that
* connections are constructed for the particular state machine implemented
*
*/
virtual void Setup( void );
/**
* Clear event, action and condition lists and reset state machine
*
*/
void Shutdown( void );
void AddState ( unsigned int state );
CFsmEvent* AddEvent ( unsigned int eventType );
CFsmTransition* AddTransition (
unsigned int state,
unsigned int eventType,
unsigned int nextState );
CFsmTransition* AddTransition (
unsigned int state,
unsigned int eventType,
unsigned int nextState,
void* pAction,
void* pContext );
CFsmTransition* GetTransition (
unsigned int state,
unsigned int eventType ) const;
CFsmTransition* GetEventTransition ( unsigned int eventType ) const;
void SetFirstState ( unsigned int firstState );
unsigned int GetCurrState ( void ) const { return m_CurrState; }
const StateSet& GetStates ( void ) const { return m_States; }
const EventMap& GetEvents ( void ) const { return m_Events; }
const TransitionList& GetTransitions ( void ) const { return m_Transitions; }
bool Update ( unsigned int eventType, void* pEventData );
bool IsValidState ( unsigned int state ) const;
bool IsValidEvent ( unsigned int eventType ) const;
virtual bool IsDone ( void ) const;
protected:
private:
// Not implemented
CFsm( const CFsm& );
CFsm& operator=( const CFsm& );
void SetCurrState ( unsigned int state );
bool IsFirstTime ( void ) const;
bool m_Done; // FSM work is done
unsigned int m_FirstState; // Initial state
unsigned int m_CurrState; // Current state
StateSet m_States; // List of states
EventMap m_Events; // List of events
TransitionList m_Transitions; // State transitions
};
#endif // FSM_H
/**
*-----------------------------------------------------------------------------
* FILE : fsm.h
* PROJECT : 0 A.D.
* DESCRIPTION : Finite state machine class definitions
*-----------------------------------------------------------------------------
*/
#ifndef FSM_H
#define FSM_H
// INCLUDES
#include <vector>
#include <set>
// DECLARATIONS
#define FSM_INVALID_STATE ( unsigned int )( ~0 )
class CFsmEvent;
class CFsmTransition;
class CFsm;
typedef bool ( *CONDITION ) ( void* pContext );
typedef bool ( *ACTION ) ( void* pContext, const CFsmEvent* pEvent );
typedef struct
{
void* pFunction;
void* pContext;
} CallbackFunction;
typedef std::set< unsigned int > StateSet;
typedef std::map< unsigned int, CFsmEvent* > EventMap;
typedef std::vector< CFsmTransition* > TransitionList;
typedef std::vector< CallbackFunction > CallbackList;
/*
CLASS : CFsmEvent
DESCRIPTION : CFsmEvent class represents a signal in the state machine
that a change has occured.
NOTES : The CFsmEvent objects are under the control of CFsm so
they are created and deleted via CFsm.
*/
class CFsmEvent
{
public:
CFsmEvent( unsigned int type );
~CFsmEvent( void );
unsigned int GetType ( void ) const { return m_Type; }
void* GetParamRef ( void ) { return m_Param; }
void SetParamRef ( void* pParam );
protected:
private:
// Not implemented
CFsmEvent( const CFsmEvent& );
CFsmEvent& operator=( const CFsmEvent& );
unsigned int m_Type; // Event type
void* m_Param; // Event paramater
};
/*
CLASS : CFsmTransition
DESCRIPTION : The CFsmTransition class is an association of event, condition,
action and next state.
NOTES :
*/
class CFsmTransition
{
public:
CFsmTransition( unsigned int state );
~CFsmTransition( void );
void RegisterAction (
void* pAction,
void* pContext );
void RegisterCondition (
void* pCondition,
void* pContext );
void SetEvent ( CFsmEvent* pEvent );
CFsmEvent* GetEvent ( void ) const { return m_Event; }
void SetNextState ( unsigned int nextState );
unsigned int GetNextState ( void ) const { return m_NextState; }
unsigned int GetCurrState ( void ) const { return m_CurrState; }
const CallbackList& GetActions ( void ) const { return m_Actions; }
const CallbackList& GetConditions ( void ) const { return m_Conditions; }
bool ApplyConditions ( void ) const;
bool RunActions ( void ) const;
protected:
private:
// Not implemented
CFsmTransition( const CFsmTransition& );
CFsmTransition& operator=( const CFsmTransition& );
unsigned int m_CurrState; // Current state
unsigned int m_NextState; // Next state
CFsmEvent* m_Event; // Transition event
CallbackList m_Actions; // List of actions for transition
CallbackList m_Conditions; // List of conditions for transition
};
/*
CLASS : CFsm
DESCRIPTION : CFsm manages states, events, actions and transitions
between states. It provides an interface for advertising
events and track the current state. The implementation is
a Mealy state machine, so the system respond to events
and execute some action.
NOTES : A Mealy state machine has behaviour associated with state
transitions; Mealy machines are event driven where an
event triggers a state transition
*/
class CFsm
{
public:
CFsm( void );
~CFsm( void );
/**
* Constructs the state machine. This method must be overriden so that
* connections are constructed for the particular state machine implemented
*
*/
virtual void Setup( void );
/**
* Clear event, action and condition lists and reset state machine
*
*/
void Shutdown( void );
void AddState ( unsigned int state );
CFsmEvent* AddEvent ( unsigned int eventType );
CFsmTransition* AddTransition (
unsigned int state,
unsigned int eventType,
unsigned int nextState );
CFsmTransition* AddTransition (
unsigned int state,
unsigned int eventType,
unsigned int nextState,
void* pAction,
void* pContext );
CFsmTransition* GetTransition (
unsigned int state,
unsigned int eventType ) const;
CFsmTransition* GetEventTransition ( unsigned int eventType ) const;
void SetFirstState ( unsigned int firstState );
unsigned int GetCurrState ( void ) const { return m_CurrState; }
const StateSet& GetStates ( void ) const { return m_States; }
const EventMap& GetEvents ( void ) const { return m_Events; }
const TransitionList& GetTransitions ( void ) const { return m_Transitions; }
bool Update ( unsigned int eventType, void* pEventData );
bool IsValidState ( unsigned int state ) const;
bool IsValidEvent ( unsigned int eventType ) const;
virtual bool IsDone ( void ) const;
protected:
private:
// Not implemented
CFsm( const CFsm& );
CFsm& operator=( const CFsm& );
void SetCurrState ( unsigned int state );
bool IsFirstTime ( void ) const;
bool m_Done; // FSM work is done
unsigned int m_FirstState; // Initial state
unsigned int m_CurrState; // Current state
StateSet m_States; // List of states
EventMap m_Events; // List of events
TransitionList m_Transitions; // State transitions
};
#endif // FSM_H

View File

@ -1,10 +1,10 @@
#include "lib/precompiled.h" // common precompiled header
// Atlas-specific PCH:
#if HAVE_PCH
#include "tools/atlas/GameInterface/Messages.h"
#include "ps/CStr.h"
#endif // HAVE_PCH
#include "lib/precompiled.h" // common precompiled header
// Atlas-specific PCH:
#if HAVE_PCH
#include "tools/atlas/GameInterface/Messages.h"
#include "ps/CStr.h"
#endif // HAVE_PCH

View File

@ -1,17 +1,17 @@
#include "lib/precompiled.h" // common precompiled header
// "engine"-specific PCH:
#include "ps/Pyrogenesis.h" // MICROLOG and old error system
#if HAVE_PCH
// some other external libraries that are used in several places:
// .. CStr is included very frequently, so a reasonable amount of time is
// saved by including it here. (~10% in a full rebuild, as of r2365)
#include "ps/CStr.h"
#include "scripting/SpiderMonkey.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#endif // HAVE_PCH
#include "lib/precompiled.h" // common precompiled header
// "engine"-specific PCH:
#include "ps/Pyrogenesis.h" // MICROLOG and old error system
#if HAVE_PCH
// some other external libraries that are used in several places:
// .. CStr is included very frequently, so a reasonable amount of time is
// saved by including it here. (~10% in a full rebuild, as of r2365)
#include "ps/CStr.h"
#include "scripting/SpiderMonkey.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#endif // HAVE_PCH

View File

@ -1,3 +1,3 @@
#include "lib/precompiled.h" // common precompiled header
// "graphics"-specific PCH:
#include "lib/precompiled.h" // common precompiled header
// "graphics"-specific PCH:

View File

@ -1,3 +1,3 @@
#include "lib/precompiled.h" // common precompiled header
// "gui"-specific PCH:
#include "lib/precompiled.h" // common precompiled header
// "gui"-specific PCH:

View File

@ -1,3 +1,3 @@
#include "lib/precompiled.h" // common precompiled header
// "i18n"-specific PCH:
#include "lib/precompiled.h" // common precompiled header
// "i18n"-specific PCH:

View File

@ -1,3 +1,3 @@
#include "lib/precompiled.h" // common precompiled header
// "lowlevel"-specific PCH:
#include "lib/precompiled.h" // common precompiled header
// "lowlevel"-specific PCH:

View File

@ -1 +1 @@
#include "precompiled.h"
#include "precompiled.h"

View File

@ -1,7 +1,7 @@
#include "lib/precompiled.h" // common precompiled header
// network-specific PCH:
#if HAVE_PCH
#endif // HAVE_PCH
#include "lib/precompiled.h" // common precompiled header
// network-specific PCH:
#if HAVE_PCH
#endif // HAVE_PCH

View File

@ -1 +1 @@
#include "precompiled.h"
#include "precompiled.h"

View File

@ -1,7 +1,7 @@
#include "lib/precompiled.h" // common precompiled header
// se PCH:
#if HAVE_PCH
#endif // HAVE_PCH
#include "lib/precompiled.h" // common precompiled header
// se PCH:
#if HAVE_PCH
#endif // HAVE_PCH

View File

@ -1,71 +1,71 @@
#include "precompiled.h"
#include "Filesystem.h"
#include "ps/CLogger.h"
#define LOG_CATEGORY "file"
PIVFS g_VFS;
bool FileExists(const char* pathname)
{
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
}
bool FileExists(const VfsPath& pathname)
{
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
}
CVFSFile::CVFSFile()
{
}
CVFSFile::~CVFSFile()
{
}
PSRETURN CVFSFile::Load(const VfsPath& filename)
{
// Load should never be called more than once, so complain
if (m_Buffer)
{
debug_assert(0);
return PSRETURN_CVFSFile_AlreadyLoaded;
}
LibError ret = g_VFS->LoadFile(filename, m_Buffer, m_BufferSize);
if (ret != INFO::OK)
{
LOG(CLogger::Error, LOG_CATEGORY, "CVFSFile: file %s couldn't be opened (vfs_load: %d)", filename.string().c_str(), ret);
return PSRETURN_CVFSFile_LoadFailed;
}
return PSRETURN_OK;
}
const u8* CVFSFile::GetBuffer() const
{
// Die in a very obvious way, to avoid subtle problems caused by
// accidentally forgetting to check that the open succeeded
if (!m_Buffer)
{
debug_warn("GetBuffer() called with no file loaded");
throw PSERROR_CVFSFile_InvalidBufferAccess();
}
return m_Buffer.get();
}
size_t CVFSFile::GetBufferSize() const
{
return m_BufferSize;
}
CStr CVFSFile::GetAsString() const
{
return std::string((char*)GetBuffer(), GetBufferSize());
}
#include "precompiled.h"
#include "Filesystem.h"
#include "ps/CLogger.h"
#define LOG_CATEGORY "file"
PIVFS g_VFS;
bool FileExists(const char* pathname)
{
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
}
bool FileExists(const VfsPath& pathname)
{
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
}
CVFSFile::CVFSFile()
{
}
CVFSFile::~CVFSFile()
{
}
PSRETURN CVFSFile::Load(const VfsPath& filename)
{
// Load should never be called more than once, so complain
if (m_Buffer)
{
debug_assert(0);
return PSRETURN_CVFSFile_AlreadyLoaded;
}
LibError ret = g_VFS->LoadFile(filename, m_Buffer, m_BufferSize);
if (ret != INFO::OK)
{
LOG(CLogger::Error, LOG_CATEGORY, "CVFSFile: file %s couldn't be opened (vfs_load: %d)", filename.string().c_str(), ret);
return PSRETURN_CVFSFile_LoadFailed;
}
return PSRETURN_OK;
}
const u8* CVFSFile::GetBuffer() const
{
// Die in a very obvious way, to avoid subtle problems caused by
// accidentally forgetting to check that the open succeeded
if (!m_Buffer)
{
debug_warn("GetBuffer() called with no file loaded");
throw PSERROR_CVFSFile_InvalidBufferAccess();
}
return m_Buffer.get();
}
size_t CVFSFile::GetBufferSize() const
{
return m_BufferSize;
}
CStr CVFSFile::GetAsString() const
{
return std::string((char*)GetBuffer(), GetBufferSize());
}

View File

@ -1,45 +1,45 @@
#ifndef INCLUDED_FILESYSTEM
#define INCLUDED_FILESYSTEM
#include "lib/path_util.h"
#include "lib/file/file.h"
#include "lib/file/io/io.h"
#include "lib/file/vfs/vfs.h"
#include "lib/file/file_system_util.h"
#include "lib/file/io/write_buffer.h"
#include "ps/CStr.h"
#include "ps/Errors.h"
extern PIVFS g_VFS;
extern bool FileExists(const char* pathname);
extern bool FileExists(const VfsPath& pathname);
ERROR_GROUP(CVFSFile);
ERROR_TYPE(CVFSFile, LoadFailed);
ERROR_TYPE(CVFSFile, AlreadyLoaded);
ERROR_TYPE(CVFSFile, InvalidBufferAccess);
// Reads a file, then gives read-only access to the contents
class CVFSFile
{
public:
CVFSFile();
~CVFSFile();
// Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
// Dies if a file has already been successfully loaded.
PSRETURN Load(const VfsPath& filename);
// These die if called when no file has been successfully loaded.
const u8* GetBuffer() const;
size_t GetBufferSize() const;
CStr GetAsString() const;
private:
shared_ptr<u8> m_Buffer;
size_t m_BufferSize;
};
#endif // #ifndef INCLUDED_FILESYSTEM
#ifndef INCLUDED_FILESYSTEM
#define INCLUDED_FILESYSTEM
#include "lib/path_util.h"
#include "lib/file/file.h"
#include "lib/file/io/io.h"
#include "lib/file/vfs/vfs.h"
#include "lib/file/file_system_util.h"
#include "lib/file/io/write_buffer.h"
#include "ps/CStr.h"
#include "ps/Errors.h"
extern PIVFS g_VFS;
extern bool FileExists(const char* pathname);
extern bool FileExists(const VfsPath& pathname);
ERROR_GROUP(CVFSFile);
ERROR_TYPE(CVFSFile, LoadFailed);
ERROR_TYPE(CVFSFile, AlreadyLoaded);
ERROR_TYPE(CVFSFile, InvalidBufferAccess);
// Reads a file, then gives read-only access to the contents
class CVFSFile
{
public:
CVFSFile();
~CVFSFile();
// Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
// Dies if a file has already been successfully loaded.
PSRETURN Load(const VfsPath& filename);
// These die if called when no file has been successfully loaded.
const u8* GetBuffer() const;
size_t GetBufferSize() const;
CStr GetAsString() const;
private:
shared_ptr<u8> m_Buffer;
size_t m_BufferSize;
};
#endif // #ifndef INCLUDED_FILESYSTEM

View File

@ -1,8 +1,8 @@
#ifndef INCLUDED_KEYNAME
#define INCLUDED_KEYNAME
extern void InitKeyNameMap();
extern CStr FindKeyName( int keycode );
extern int FindKeyCode( const CStr& keyname );
#endif // #ifndef INCLUDED_KEYNAME
#ifndef INCLUDED_KEYNAME
#define INCLUDED_KEYNAME
extern void InitKeyNameMap();
extern CStr FindKeyName( int keycode );
extern int FindKeyCode( const CStr& keyname );
#endif // #ifndef INCLUDED_KEYNAME

View File

@ -1,211 +1,211 @@
#include "lib/self_test.h"
#include "ps/XML/XMLWriter.h"
class TestXmlWriter : public CxxTest::TestSuite
{
public:
void test1()
{
XML_Start();
{
XML_Element("Root");
{
XML_Comment("Comment test.");
XML_Comment("Comment test again.");
{
XML_Element("a");
XML_Attribute("one", 1);
XML_Attribute("two", "TWO");
XML_Text("b");
XML_Text(" (etc)");
}
{
XML_Element("c");
XML_Text("d");
}
XML_Setting("c2", "d2");
{
XML_Element("e");
{
{
XML_Element("f");
XML_Text("g");
}
{
XML_Element("h");
}
{
XML_Element("i");
XML_Attribute("j", 1.23);
{
XML_Element("k");
XML_Attribute("l", 2.34);
XML_Text("m");
}
}
}
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Root>\n"
"\t<!-- Comment test. -->\n"
"\t<!-- Comment test again. -->\n"
"\t<a one=\"1\" two=\"TWO\">b (etc)</a>\n"
"\t<c>d</c>\n"
"\t<c2>d2</c2>\n"
"\t<e>\n"
"\t\t<f>g</f>\n"
"\t\t<h/>\n"
"\t\t<i j=\"1.23\">\n"
"\t\t\t<k l=\"2.34\">m</k>\n"
"\t\t</i>\n"
"\t</e>\n"
"</Root>"
);
}
void test_basic()
{
XML_Start();
{
XML_Element("Test");
{
XML_Element("example");
{
XML_Element("content");
XML_Text("text");
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Test>\n"
"\t<example>\n"
"\t\t<content>text</content>\n"
"\t</example>\n"
"</Test>"
);
}
void test_nonpretty()
{
XML_Start();
XML_SetPrettyPrint(false);
{
XML_Element("Test");
{
XML_Element("example");
{
XML_Element("content");
XML_Text("text");
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<Test><example><content>text</content></example></Test>"
);
}
void test_text()
{
XML_Start();
{
XML_Element("Test");
XML_Text("a");
XML_Text("b");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Test>ab</Test>"
);
}
void test_utf8()
{
XML_Start();
{
XML_Element("Test");
{
const wchar_t text[] = { 0x0251, 0 };
XML_Text(text);
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>\xC9\x91</Test>"
);
}
void test_attr_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Attribute("example", "abc > ]]> < & \"\" ");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test example=\"abc > ]]> &lt; &amp; &quot;&quot; \"/>"
);
}
void test_chardata_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Text("abc > ]]> < & \"\" ");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>abc > ]]&gt; &lt; &amp; \"\" </Test>"
);
}
void test_comment_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Comment("test - -- --- ---- test");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>\n"
"\t<!-- test - \xE2\x80\x90\xE2\x80\x90 \xE2\x80\x90\xE2\x80\x90- \xE2\x80\x90\xE2\x80\x90\xE2\x80\x90\xE2\x80\x90 test -->\n"
"</Test>"
);
}
};
#include "lib/self_test.h"
#include "ps/XML/XMLWriter.h"
class TestXmlWriter : public CxxTest::TestSuite
{
public:
void test1()
{
XML_Start();
{
XML_Element("Root");
{
XML_Comment("Comment test.");
XML_Comment("Comment test again.");
{
XML_Element("a");
XML_Attribute("one", 1);
XML_Attribute("two", "TWO");
XML_Text("b");
XML_Text(" (etc)");
}
{
XML_Element("c");
XML_Text("d");
}
XML_Setting("c2", "d2");
{
XML_Element("e");
{
{
XML_Element("f");
XML_Text("g");
}
{
XML_Element("h");
}
{
XML_Element("i");
XML_Attribute("j", 1.23);
{
XML_Element("k");
XML_Attribute("l", 2.34);
XML_Text("m");
}
}
}
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Root>\n"
"\t<!-- Comment test. -->\n"
"\t<!-- Comment test again. -->\n"
"\t<a one=\"1\" two=\"TWO\">b (etc)</a>\n"
"\t<c>d</c>\n"
"\t<c2>d2</c2>\n"
"\t<e>\n"
"\t\t<f>g</f>\n"
"\t\t<h/>\n"
"\t\t<i j=\"1.23\">\n"
"\t\t\t<k l=\"2.34\">m</k>\n"
"\t\t</i>\n"
"\t</e>\n"
"</Root>"
);
}
void test_basic()
{
XML_Start();
{
XML_Element("Test");
{
XML_Element("example");
{
XML_Element("content");
XML_Text("text");
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Test>\n"
"\t<example>\n"
"\t\t<content>text</content>\n"
"\t</example>\n"
"</Test>"
);
}
void test_nonpretty()
{
XML_Start();
XML_SetPrettyPrint(false);
{
XML_Element("Test");
{
XML_Element("example");
{
XML_Element("content");
XML_Text("text");
}
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<Test><example><content>text</content></example></Test>"
);
}
void test_text()
{
XML_Start();
{
XML_Element("Test");
XML_Text("a");
XML_Text("b");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"<Test>ab</Test>"
);
}
void test_utf8()
{
XML_Start();
{
XML_Element("Test");
{
const wchar_t text[] = { 0x0251, 0 };
XML_Text(text);
}
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>\xC9\x91</Test>"
);
}
void test_attr_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Attribute("example", "abc > ]]> < & \"\" ");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test example=\"abc > ]]> &lt; &amp; &quot;&quot; \"/>"
);
}
void test_chardata_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Text("abc > ]]> < & \"\" ");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>abc > ]]&gt; &lt; &amp; \"\" </Test>"
);
}
void test_comment_escape()
{
XML_Start();
{
XML_Element("Test");
XML_Comment("test - -- --- ---- test");
}
CStr output = XML_GetOutput();
TS_ASSERT_STR_EQUALS(output,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"
"<Test>\n"
"\t<!-- test - \xE2\x80\x90\xE2\x80\x90 \xE2\x80\x90\xE2\x80\x90- \xE2\x80\x90\xE2\x80\x90\xE2\x80\x90\xE2\x80\x90 test -->\n"
"</Test>"
);
}
};

View File

@ -1,16 +1,16 @@
#include "lib/self_test.h"
// usually defined by main.cpp, used by engine's scripting/ScriptGlue.cpp,
// must be included here to placate linker.
void kill_mainloop()
{
}
// just so that cxxtestgen doesn't complain "No tests defined"
class TestDummy : public CxxTest::TestSuite
{
public:
void test_dummy()
{
}
};
#include "lib/self_test.h"
// usually defined by main.cpp, used by engine's scripting/ScriptGlue.cpp,
// must be included here to placate linker.
void kill_mainloop()
{
}
// just so that cxxtestgen doesn't complain "No tests defined"
class TestDummy : public CxxTest::TestSuite
{
public:
void test_dummy()
{
}
};

View File

@ -1,52 +1,52 @@
#include "lib/self_test.h"
#include "ps/CStr.h"
class TestCStr : public CxxTest::TestSuite
{
public:
void test_utf8_utf16_conversion()
{
const wchar_t chr_utf16[] = {
0x12,
0xff,
0x1234,
0x3456,
0x5678,
0x7890,
0x9abc,
0xbcde,
0xfffe
};
const unsigned char chr_utf8[] = {
0x12,
0xc3, 0xbf,
0xe1, 0x88, 0xb4,
0xe3, 0x91, 0x96,
0xe5, 0x99, 0xb8,
0xe7, 0xa2, 0x90,
0xe9, 0xaa, 0xbc,
0xeb, 0xb3, 0x9e,
0xef, 0xbf, 0xbe
};
CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t));
CStr8 str_utf8 = str_utf16.ToUTF8();
TS_ASSERT_EQUALS(str_utf8.length(), sizeof(chr_utf8));
TS_ASSERT_SAME_DATA(str_utf8.data(), chr_utf8, sizeof(chr_utf8));
CStrW str_utf16b = str_utf8.FromUTF8();
TS_ASSERT_WSTR_EQUALS(str_utf16b, str_utf16);
}
void test_invalid_utf8()
{
const unsigned char chr_utf8_a[] = { 'a', 0xef };
const unsigned char chr_utf8_b[] = { 'b', 0xef, 0xbf };
const unsigned char chr_utf8_c[] = { 'c', 0xef, 0xbf, 0x01 };
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_a, sizeof(chr_utf8_a)).FromUTF8(), L"");
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_b, sizeof(chr_utf8_b)).FromUTF8(), L"");
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_c, sizeof(chr_utf8_c)).FromUTF8(), L"");
}
};
#include "lib/self_test.h"
#include "ps/CStr.h"
class TestCStr : public CxxTest::TestSuite
{
public:
void test_utf8_utf16_conversion()
{
const wchar_t chr_utf16[] = {
0x12,
0xff,
0x1234,
0x3456,
0x5678,
0x7890,
0x9abc,
0xbcde,
0xfffe
};
const unsigned char chr_utf8[] = {
0x12,
0xc3, 0xbf,
0xe1, 0x88, 0xb4,
0xe3, 0x91, 0x96,
0xe5, 0x99, 0xb8,
0xe7, 0xa2, 0x90,
0xe9, 0xaa, 0xbc,
0xeb, 0xb3, 0x9e,
0xef, 0xbf, 0xbe
};
CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t));
CStr8 str_utf8 = str_utf16.ToUTF8();
TS_ASSERT_EQUALS(str_utf8.length(), sizeof(chr_utf8));
TS_ASSERT_SAME_DATA(str_utf8.data(), chr_utf8, sizeof(chr_utf8));
CStrW str_utf16b = str_utf8.FromUTF8();
TS_ASSERT_WSTR_EQUALS(str_utf16b, str_utf16);
}
void test_invalid_utf8()
{
const unsigned char chr_utf8_a[] = { 'a', 0xef };
const unsigned char chr_utf8_b[] = { 'b', 0xef, 0xbf };
const unsigned char chr_utf8_c[] = { 'c', 0xef, 0xbf, 0x01 };
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_a, sizeof(chr_utf8_a)).FromUTF8(), L"");
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_b, sizeof(chr_utf8_b)).FromUTF8(), L"");
TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_c, sizeof(chr_utf8_c)).FromUTF8(), L"");
}
};

View File

@ -1,95 +1,95 @@
#include "lib/self_test.h"
#include "ps/Parser.h"
class TestParser : public CxxTest::TestSuite
{
public:
void test1()
{
CParser Parser;
Parser.InputTaskType("test", "_$ident_=_$value_");
std::string str;
int i;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "value=23"));
TS_ASSERT(Line.GetArgString(0, str) && str == "value");
TS_ASSERT(Line.GetArgInt(1, i) && i == 23);
}
void test2()
{
CParser Parser;
Parser.InputTaskType("test", "_$value_[$value]_");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "12 34"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
TS_ASSERT(Line.ParseString(Parser, "56"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
TS_ASSERT(Line.GetArgString(0, str) && str == "56");
TS_ASSERT(! Line.ParseString(Parser, " "));
}
void test3()
{
CParser Parser;
Parser.InputTaskType("test", "_[$value]_[$value]_[$value]_");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "12 34 56"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 3);
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
TS_ASSERT(Line.GetArgString(2, str) && str == "56");
TS_ASSERT(Line.ParseString(Parser, "78 90"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
TS_ASSERT(Line.GetArgString(0, str) && str == "78");
TS_ASSERT(Line.GetArgString(1, str) && str == "90");
TS_ASSERT(Line.ParseString(Parser, "ab"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
TS_ASSERT(Line.GetArgString(0, str) && str == "ab");
TS_ASSERT(Line.ParseString(Parser, " "));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 0);
}
void test4()
{
CParser Parser;
Parser.InputTaskType("test", "<[_a_][_b_]_x_>");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "a b x a b x"));
TS_ASSERT(Line.ParseString(Parser, "a x b x"));
TS_ASSERT(Line.ParseString(Parser, "a x"));
TS_ASSERT(Line.ParseString(Parser, "b x"));
TS_ASSERT(Line.ParseString(Parser, "x"));
TS_ASSERT(! Line.ParseString(Parser, "a x c x"));
TS_ASSERT(! Line.ParseString(Parser, "a b a x"));
TS_ASSERT(! Line.ParseString(Parser, "a"));
TS_ASSERT(! Line.ParseString(Parser, "a a x"));
TS_ASSERT(Line.ParseString(Parser, "a x a b x a x b x b x b x b x a x a x a b x a b x b x a x"));
}
};
#include "lib/self_test.h"
#include "ps/Parser.h"
class TestParser : public CxxTest::TestSuite
{
public:
void test1()
{
CParser Parser;
Parser.InputTaskType("test", "_$ident_=_$value_");
std::string str;
int i;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "value=23"));
TS_ASSERT(Line.GetArgString(0, str) && str == "value");
TS_ASSERT(Line.GetArgInt(1, i) && i == 23);
}
void test2()
{
CParser Parser;
Parser.InputTaskType("test", "_$value_[$value]_");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "12 34"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
TS_ASSERT(Line.ParseString(Parser, "56"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
TS_ASSERT(Line.GetArgString(0, str) && str == "56");
TS_ASSERT(! Line.ParseString(Parser, " "));
}
void test3()
{
CParser Parser;
Parser.InputTaskType("test", "_[$value]_[$value]_[$value]_");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "12 34 56"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 3);
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
TS_ASSERT(Line.GetArgString(2, str) && str == "56");
TS_ASSERT(Line.ParseString(Parser, "78 90"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
TS_ASSERT(Line.GetArgString(0, str) && str == "78");
TS_ASSERT(Line.GetArgString(1, str) && str == "90");
TS_ASSERT(Line.ParseString(Parser, "ab"));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
TS_ASSERT(Line.GetArgString(0, str) && str == "ab");
TS_ASSERT(Line.ParseString(Parser, " "));
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 0);
}
void test4()
{
CParser Parser;
Parser.InputTaskType("test", "<[_a_][_b_]_x_>");
std::string str;
CParserLine Line;
TS_ASSERT(Line.ParseString(Parser, "a b x a b x"));
TS_ASSERT(Line.ParseString(Parser, "a x b x"));
TS_ASSERT(Line.ParseString(Parser, "a x"));
TS_ASSERT(Line.ParseString(Parser, "b x"));
TS_ASSERT(Line.ParseString(Parser, "x"));
TS_ASSERT(! Line.ParseString(Parser, "a x c x"));
TS_ASSERT(! Line.ParseString(Parser, "a b a x"));
TS_ASSERT(! Line.ParseString(Parser, "a"));
TS_ASSERT(! Line.ParseString(Parser, "a a x"));
TS_ASSERT(Line.ParseString(Parser, "a x a b x a x b x b x b x b x a x a x a b x a b x b x a x"));
}
};

View File

@ -1,32 +1,32 @@
/**
* File : Scene.cpp
* Project : graphics
* Description : This file contains default implementations and utilities
* : to be used together with the Scene interface and related
* : classes.
*
* @note This file would fit just as well into the graphics/ subdirectory.
**/
#include "precompiled.h"
#include "graphics/Model.h"
#include "renderer/Scene.h"
///////////////////////////////////////////////////////////
// Default implementation traverses the model recursively and uses
// SubmitNonRecursive for the actual work.
void SceneCollector::SubmitRecursive(CModel* model)
{
SubmitNonRecursive(model);
const std::vector<CModel::Prop>& props = model->GetProps();
for (size_t i=0;i<props.size();i++) {
SubmitRecursive(props[i].m_Model);
}
}
/**
* File : Scene.cpp
* Project : graphics
* Description : This file contains default implementations and utilities
* : to be used together with the Scene interface and related
* : classes.
*
* @note This file would fit just as well into the graphics/ subdirectory.
**/
#include "precompiled.h"
#include "graphics/Model.h"
#include "renderer/Scene.h"
///////////////////////////////////////////////////////////
// Default implementation traverses the model recursively and uses
// SubmitNonRecursive for the actual work.
void SceneCollector::SubmitRecursive(CModel* model)
{
SubmitNonRecursive(model);
const std::vector<CModel::Prop>& props = model->GetProps();
for (size_t i=0;i<props.size();i++) {
SubmitRecursive(props[i].m_Model);
}
}

View File

@ -1,67 +1,67 @@
/**
* File : Scene.h
* Project : graphics
* Description : This file contains the interfaces that are used to send a
* : scene to the renderer, and for the renderer to query objects
* : in that scene.
*
* @note This file would fit just as well into the graphics/ subdirectory.
**/
#ifndef INCLUDED_SCENE
#define INCLUDED_SCENE
class CFrustum;
class CModel;
class CPatch;
class SceneCollector;
/**
* This interface describes a scene to the renderer.
*
* @see CRenderer::RenderScene
*/
class Scene {
public:
/**
* Send all objects that can be seen when rendering the given frustum
* to the scene collector.
* @param frustum The frustum that will be used for rendering.
* @param c The scene collector that should receive objects inside the frustum
* that are visible.
*/
virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) = 0;
};
/**
* This interface accepts renderable objects.
*
* @see Scene::EnumerateObjects
*/
class SceneCollector {
public:
/**
* Submit a terrain patch that is part of the scene.
*/
virtual void Submit(CPatch* patch) = 0;
/**
* Submit a model that is part of the scene,
* without submitting attached models.
*/
virtual void SubmitNonRecursive(CModel* model) = 0;
/**
* Submit a model that is part of the scene,
* including attached sub-models.
*
* @note This function is implemented using SubmitNonRecursive,
* so you shouldn't have to reimplement it.
*/
virtual void SubmitRecursive(CModel* model);
};
#endif // INCLUDED_SCENE
/**
* File : Scene.h
* Project : graphics
* Description : This file contains the interfaces that are used to send a
* : scene to the renderer, and for the renderer to query objects
* : in that scene.
*
* @note This file would fit just as well into the graphics/ subdirectory.
**/
#ifndef INCLUDED_SCENE
#define INCLUDED_SCENE
class CFrustum;
class CModel;
class CPatch;
class SceneCollector;
/**
* This interface describes a scene to the renderer.
*
* @see CRenderer::RenderScene
*/
class Scene {
public:
/**
* Send all objects that can be seen when rendering the given frustum
* to the scene collector.
* @param frustum The frustum that will be used for rendering.
* @param c The scene collector that should receive objects inside the frustum
* that are visible.
*/
virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) = 0;
};
/**
* This interface accepts renderable objects.
*
* @see Scene::EnumerateObjects
*/
class SceneCollector {
public:
/**
* Submit a terrain patch that is part of the scene.
*/
virtual void Submit(CPatch* patch) = 0;
/**
* Submit a model that is part of the scene,
* without submitting attached models.
*/
virtual void SubmitNonRecursive(CModel* model) = 0;
/**
* Submit a model that is part of the scene,
* including attached sub-models.
*
* @note This function is implemented using SubmitNonRecursive,
* so you shouldn't have to reimplement it.
*/
virtual void SubmitRecursive(CModel* model);
};
#endif // INCLUDED_SCENE

View File

@ -1,15 +1,15 @@
#include "precompiled.h"
#include "SpiderMonkey.h"
jsval jsu_report_param_error(JSContext* cx, jsval* rval)
{
JS_ReportError(cx, "Invalid parameter(s) or count");
if(rval)
*rval = JSVAL_NULL;
// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
// to abort. that would be hard to debug.
return JS_TRUE;
}
#include "precompiled.h"
#include "SpiderMonkey.h"
jsval jsu_report_param_error(JSContext* cx, jsval* rval)
{
JS_ReportError(cx, "Invalid parameter(s) or count");
if(rval)
*rval = JSVAL_NULL;
// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
// to abort. that would be hard to debug.
return JS_TRUE;
}

View File

@ -1,44 +1,44 @@
// included from SpiderMonkey.h
extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
// consistent argc checking for normal function wrappers: reports an
// error via JS and returns if number of parameters is incorrect.
// .. require exact number (most common case)
#define JSU_REQUIRE_PARAMS(exact_number)\
if(argc != exact_number)\
return jsu_report_param_error(cx, rval);
// .. require 0 params (avoids L4 warning "unused argv param")
#define JSU_REQUIRE_NO_PARAMS()\
UNUSED2(argv);\
if(argc != 0)\
return jsu_report_param_error(cx, rval);
// .. require a certain range (e.g. due to optional params)
#define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
if(!(min_number <= argc && argc <= max_number))\
return jsu_report_param_error(cx, rval);
// .. require at least a certain count (rarely needed)
#define JSU_REQUIRE_MIN_PARAMS(min_number)\
if(argc < min_number)\
return jsu_report_param_error(cx, rval);
// same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
// a bit further removed from SpiderMonkey, i.e. return a
// C++ bool indicating success, and not taking an rval param.
#define JSU_REQUIRE_PARAMS_CPP(exact_number)\
if(argc != exact_number)\
{\
jsu_report_param_error(cx, 0);\
return false;\
}
#define JSU_ASSERT(expr, msg)\
STMT(\
if(!(expr))\
{\
JS_ReportError(cx, msg);\
return JS_FALSE;\
}\
)
// included from SpiderMonkey.h
extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
// consistent argc checking for normal function wrappers: reports an
// error via JS and returns if number of parameters is incorrect.
// .. require exact number (most common case)
#define JSU_REQUIRE_PARAMS(exact_number)\
if(argc != exact_number)\
return jsu_report_param_error(cx, rval);
// .. require 0 params (avoids L4 warning "unused argv param")
#define JSU_REQUIRE_NO_PARAMS()\
UNUSED2(argv);\
if(argc != 0)\
return jsu_report_param_error(cx, rval);
// .. require a certain range (e.g. due to optional params)
#define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
if(!(min_number <= argc && argc <= max_number))\
return jsu_report_param_error(cx, rval);
// .. require at least a certain count (rarely needed)
#define JSU_REQUIRE_MIN_PARAMS(min_number)\
if(argc < min_number)\
return jsu_report_param_error(cx, rval);
// same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
// a bit further removed from SpiderMonkey, i.e. return a
// C++ bool indicating success, and not taking an rval param.
#define JSU_REQUIRE_PARAMS_CPP(exact_number)\
if(argc != exact_number)\
{\
jsu_report_param_error(cx, 0);\
return false;\
}
#define JSU_ASSERT(expr, msg)\
STMT(\
if(!(expr))\
{\
JS_ReportError(cx, msg);\
return JS_FALSE;\
}\
)

View File

@ -1,23 +1,23 @@
#include "precompiled.h"
#include "TRAStarEngine.h"
#ifdef USE_DCDT
CTRAStarEngine::CTRAStarEngine(void)
{
mGoal = new AStarGoalLowLevel;
}
CTRAStarEngine::~CTRAStarEngine(void)
{
delete mGoal;
}
bool CTRAStarEngine::FindPath(const CVector2D &src, const CVector2D &dest, HEntity UNUSED(entity), SeDcdt& dcdtPathfinder, float radius )
{
bool found = dcdtPathfinder.SearchPathFast(src.x, src.y, dest.x, dest.y, radius);
return found;
}
#endif // USE_DCDT
#include "precompiled.h"
#include "TRAStarEngine.h"
#ifdef USE_DCDT
CTRAStarEngine::CTRAStarEngine(void)
{
mGoal = new AStarGoalLowLevel;
}
CTRAStarEngine::~CTRAStarEngine(void)
{
delete mGoal;
}
bool CTRAStarEngine::FindPath(const CVector2D &src, const CVector2D &dest, HEntity UNUSED(entity), SeDcdt& dcdtPathfinder, float radius )
{
bool found = dcdtPathfinder.SearchPathFast(src.x, src.y, dest.x, dest.y, radius);
return found;
}
#endif // USE_DCDT

View File

@ -1,22 +1,22 @@
#ifndef INCLUDED_TRASTARENGINE
#define INCLUDED_TRASTARENGINE
#ifdef USE_DCDT
#include "AStarEngine.h"
class CTRAStarEngine :
public CAStarEngine
{
public:
CTRAStarEngine(void);
~CTRAStarEngine(void);
SeDcdt dcdtPathfinder;;
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, SeDcdt& dcdtPathfinder,float radius=0.0f );
};
#endif // USE_DCDT
#endif
#ifndef INCLUDED_TRASTARENGINE
#define INCLUDED_TRASTARENGINE
#ifdef USE_DCDT
#include "AStarEngine.h"
class CTRAStarEngine :
public CAStarEngine
{
public:
CTRAStarEngine(void);
~CTRAStarEngine(void);
SeDcdt dcdtPathfinder;;
bool FindPath( const CVector2D& src, const CVector2D& dest, HEntity entity, SeDcdt& dcdtPathfinder,float radius=0.0f );
};
#endif // USE_DCDT
#endif

View File

@ -1,68 +1,68 @@
#include "precompiled.h"
#include "TechnologyCollection.h"
#include "ps/CLogger.h"
#include "ps/Player.h"
#define LOG_CATEGORY "tech"
void CTechnologyCollection::LoadFile( const VfsPath& pathname )
{
const CStrW basename(fs::basename(pathname));
m_techFilenames[basename] = pathname.string();
}
static LibError LoadTechThunk( const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData )
{
CTechnologyCollection* this_ = (CTechnologyCollection*)cbData;
this_->LoadFile(pathname);
return INFO::CB_CONTINUE;
}
int CTechnologyCollection::LoadTechnologies()
{
// Load all files in techs/ and subdirectories.
THROW_ERR( fs_ForEachFile(g_VFS, "technologies/", LoadTechThunk, (uintptr_t)this, "*.xml", DIR_RECURSIVE));
return 0;
}
CTechnology* CTechnologyCollection::GetTechnology( const CStrW& name, CPlayer* player )
{
// Find player ID
debug_assert( player != 0 );
const size_t id = player->GetPlayerID();
// Check whether this template has already been loaded.
//If previously loaded, all slots will be found, so any entry works.
TechMap::iterator it = m_techs[id].find( name );
if( it != m_techs[id].end() )
return( it->second );
// Find the filename corresponding to this template
TechFilenameMap::iterator filename_it = m_techFilenames.find( name );
if( filename_it == m_techFilenames.end() )
return( NULL );
CStr path( filename_it->second );
//Try to load to the tech
CTechnology* newTemplate = new CTechnology( name, player );
if( !newTemplate->LoadXml( path ) )
{
LOG(CLogger::Error, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Couldn't load tech \"%s\"", path.c_str());
delete newTemplate;
return( NULL );
}
m_techs[id][name] = newTemplate;
LOG(CLogger::Normal, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Loaded tech \"%s\"", path.c_str());
return newTemplate;
}
CTechnologyCollection::~CTechnologyCollection()
{
for( size_t id=0; id<PS_MAX_PLAYERS+1; id++ )
for( TechMap::iterator it = m_techs[id].begin(); it != m_techs[id].end(); ++it )
delete( it->second );
}
#include "precompiled.h"
#include "TechnologyCollection.h"
#include "ps/CLogger.h"
#include "ps/Player.h"
#define LOG_CATEGORY "tech"
void CTechnologyCollection::LoadFile( const VfsPath& pathname )
{
const CStrW basename(fs::basename(pathname));
m_techFilenames[basename] = pathname.string();
}
static LibError LoadTechThunk( const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData )
{
CTechnologyCollection* this_ = (CTechnologyCollection*)cbData;
this_->LoadFile(pathname);
return INFO::CB_CONTINUE;
}
int CTechnologyCollection::LoadTechnologies()
{
// Load all files in techs/ and subdirectories.
THROW_ERR( fs_ForEachFile(g_VFS, "technologies/", LoadTechThunk, (uintptr_t)this, "*.xml", DIR_RECURSIVE));
return 0;
}
CTechnology* CTechnologyCollection::GetTechnology( const CStrW& name, CPlayer* player )
{
// Find player ID
debug_assert( player != 0 );
const size_t id = player->GetPlayerID();
// Check whether this template has already been loaded.
//If previously loaded, all slots will be found, so any entry works.
TechMap::iterator it = m_techs[id].find( name );
if( it != m_techs[id].end() )
return( it->second );
// Find the filename corresponding to this template
TechFilenameMap::iterator filename_it = m_techFilenames.find( name );
if( filename_it == m_techFilenames.end() )
return( NULL );
CStr path( filename_it->second );
//Try to load to the tech
CTechnology* newTemplate = new CTechnology( name, player );
if( !newTemplate->LoadXml( path ) )
{
LOG(CLogger::Error, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Couldn't load tech \"%s\"", path.c_str());
delete newTemplate;
return( NULL );
}
m_techs[id][name] = newTemplate;
LOG(CLogger::Normal, LOG_CATEGORY, "CTechnologyCollection::GetTechnology(): Loaded tech \"%s\"", path.c_str());
return newTemplate;
}
CTechnologyCollection::~CTechnologyCollection()
{
for( size_t id=0; id<PS_MAX_PLAYERS+1; id++ )
for( TechMap::iterator it = m_techs[id].begin(); it != m_techs[id].end(); ++it )
delete( it->second );
}

View File

@ -1,35 +1,35 @@
//Manages the tech templates. More detail: see CFormation and CEntityTemplate (collections)
#ifndef INCLUDED_TECHNOLOGYCOLLECTION
#define INCLUDED_TECHNOLOGYCOLLECTION
#include "ps/CStr.h"
#include "ps/Singleton.h"
#include "Technology.h"
#include "ps/Game.h"
#include "ps/Filesystem.h"
#define g_TechnologyCollection CTechnologyCollection::GetSingleton()
class CTechnologyCollection : public Singleton<CTechnologyCollection>
{
typedef std::map<CStrW, CTechnology*> TechMap;
typedef std::map<CStrW, CStr> TechFilenameMap;
TechMap m_techs[PS_MAX_PLAYERS+1];
TechFilenameMap m_techFilenames;
public:
std::vector<CTechnology*> activeTechs[PS_MAX_PLAYERS+1];
CTechnology* GetTechnology( const CStrW& techType, CPlayer* player );
~CTechnologyCollection();
int LoadTechnologies();
// called by non-member trampoline via LoadTechnologies
void LoadFile( const VfsPath& path );
};
#endif
//Manages the tech templates. More detail: see CFormation and CEntityTemplate (collections)
#ifndef INCLUDED_TECHNOLOGYCOLLECTION
#define INCLUDED_TECHNOLOGYCOLLECTION
#include "ps/CStr.h"
#include "ps/Singleton.h"
#include "Technology.h"
#include "ps/Game.h"
#include "ps/Filesystem.h"
#define g_TechnologyCollection CTechnologyCollection::GetSingleton()
class CTechnologyCollection : public Singleton<CTechnologyCollection>
{
typedef std::map<CStrW, CTechnology*> TechMap;
typedef std::map<CStrW, CStr> TechFilenameMap;
TechMap m_techs[PS_MAX_PLAYERS+1];
TechFilenameMap m_techFilenames;
public:
std::vector<CTechnology*> activeTechs[PS_MAX_PLAYERS+1];
CTechnology* GetTechnology( const CStrW& techType, CPlayer* player );
~CTechnologyCollection();
int LoadTechnologies();
// called by non-member trampoline via LoadTechnologies
void LoadFile( const VfsPath& path );
};
#endif

View File

@ -1,487 +1,487 @@
#include "precompiled.h"
#include "TriggerManager.h"
#include "scripting/ScriptingHost.h"
#include "ps/XML/Xeromyces.h"
#include "ps/XML/XeroXMB.h"
#include "ps/CLogger.h"
#define LOG_CATEGORY "Triggers"
CTrigger::CTrigger()
{
m_timeLeft = m_timeDelay = m_maxRunCount = m_runCount = m_active = 0;
}
CTrigger::~CTrigger()
{
}
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
const CStrW& effectFunc)
{
m_name = name;
m_active = active;
m_timeLeft = m_timeDelay = delay;
m_runCount = 0;
m_maxRunCount = maxRuns;
CStrW validName = name;
validName.Replace(L" ", L"_");
m_conditionFuncString = condFunc;
m_effectFuncString = effectFunc;
m_conditionFunction.Compile( L"TriggerCondition_" + validName, condFunc );
m_effectFunction.Compile( L"TriggerEffect_" + validName, effectFunc );
}
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
CScriptObject& condFunc, CScriptObject& effectFunc)
{
m_name = name;
m_active = active;
m_timeLeft = m_timeDelay = delay;
m_runCount = 0;
m_maxRunCount = maxRuns;
m_conditionFunction = condFunc;
m_effectFunction = effectFunc;
}
JSBool CTrigger::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS_CPP(6);
CScriptObject condFunc( JS_ValueToFunction(cx, argv[4]) );
CScriptObject effectFunc( JS_ValueToFunction(cx, argv[5]) );
CTrigger* newTrigger = new CTrigger( ToPrimitive<CStr>( argv[0] ),
ToPrimitive<bool>( argv[1] ),
ToPrimitive<float>( argv[2] ),
ToPrimitive<int>( argv[3]),
condFunc, effectFunc );
g_TriggerManager.AddTrigger(newTrigger);
*rval = OBJECT_TO_JSVAL( newTrigger->GetScript() );
return JS_TRUE;
}
CTrigger& CTrigger::operator= (const CTrigger& trigger)
{
m_name = trigger.m_name;
m_active = trigger.m_active;
m_timeLeft = trigger.m_timeLeft;
m_timeDelay = trigger.m_timeDelay;
m_maxRunCount = trigger.m_maxRunCount;
m_conditionFunction = trigger.m_conditionFunction;
m_effectFunction = trigger.m_effectFunction;
return *this;
}
void CTrigger::ScriptingInit()
{
AddProperty<int>(L"runCount", &CTrigger::m_runCount, true);
AddProperty(L"name", &CTrigger::m_name, true);
AddProperty<int>(L"maxRunCount", &CTrigger::m_maxRunCount);
AddProperty<float>(L"timeDelay", &CTrigger::m_timeDelay);
AddMethod<void, &CTrigger::Activate>( "activate", 0 );
AddMethod<void, &CTrigger::Deactivate>( "deactivate", 0 );
CJSObject<CTrigger>::ScriptingInit("Trigger", CTrigger::Construct, 6);
}
bool CTrigger::ShouldFire()
{
if ( !m_active )
return false;
return m_conditionFunction.Run( this->GetScript() );
}
bool CTrigger::Fire()
{
m_effectFunction.Run( this->GetScript() );
++m_runCount;
m_timeLeft = m_timeDelay;
return (m_runCount < m_maxRunCount);
}
void CTrigger::Activate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
{
m_active = true;
}
void CTrigger::Deactivate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
{
m_active = false;
}
void TriggerParameter::SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize)
{
windowPosition.Remove( CStrW(L" ") );
windowSize.Remove( CStrW(L" ") );
xPos = windowPosition.BeforeFirst( CStrW(L",") ).ToInt();
yPos = windowPosition.AfterFirst( CStrW(L",") ).ToInt();
xSize = windowSize.BeforeFirst( CStrW(L",") ).ToInt();
ySize = windowSize.AfterFirst( CStrW(L",") ).ToInt();
windowType = _windowType;
}
bool TriggerParameter::operator< ( const TriggerParameter& rhs ) const
{
if ( row < rhs.row )
return true;
else if ( row == rhs.row)
return ( column < rhs.column );
return false;
}
//===========Trigger Manager===========
CTriggerManager::CTriggerManager() : m_UpdateRate(.20f), m_UpdateTime(.20f)
{
}
CTriggerManager::~CTriggerManager()
{
DestroyEngineTriggers();
}
void CTriggerManager::DestroyEngineTriggers()
{
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
{
SAFE_DELETE(it->second);
}
m_TriggerMap.clear();
}
std::vector<std::wstring> CTriggerManager::GetTriggerChoices(const std::wstring& name)
{
return m_TriggerChoices[name];
}
std::vector<std::wstring> CTriggerManager::GetTriggerTranslations(const std::wstring& name)
{
return m_TriggerTranslations[name];
}
void CTriggerManager::Update(float delta_ms)
{
float delta = delta_ms / 1000.f;
m_UpdateTime -= delta;
if ( m_UpdateTime < 0 )
m_UpdateTime += m_UpdateRate;
else
return;
std::list<TriggerIter> expired;
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
{
if ( it->second->ShouldFire() )
{
it->second->m_timeLeft -= m_UpdateRate;
if ( it->second->m_timeLeft < 0 )
{
if ( !it->second->Fire() )
expired.push_back(it);
}
}
}
//Remove all expired triggers
for ( std::list<TriggerIter>::iterator it = expired.begin(); it != expired.end(); ++it )
{
delete (*it)->second;
m_TriggerMap.erase(*it);
}
}
void CTriggerManager::AddTrigger(CTrigger* trigger)
{
m_TriggerMap[trigger->GetName()] = trigger;
}
void CTriggerManager::AddGroup(const MapTriggerGroup& group)
{
m_GroupList.push_back(group);
}
void CTriggerManager::SetAllGroups(const std::list<MapTriggerGroup>& groups)
{
m_GroupList = groups;
}
void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
{
CStrW conditionBody;
CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
size_t i=0;
bool allParameters = true;
if(trigger.conditions.size() == 0) {
conditionBody = CStrW(L"return ( true );");
}
else {
conditionBody = CStrW(L"return ( ");
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
it != trigger.conditions.end(); ++it, ++i )
{
//Opening parenthesis here?
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
{
if ( blockIt->negated )
conditionBody += CStrW(L"!");
conditionBody += CStrW(L" (");
}
if ( it->negated )
conditionBody += CStrW(L"!");
conditionBody += it->functionName;
conditionBody += CStrW(L"(");
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
it->parameters.end(); ++it2 )
{
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
size_t distance = std::distance(it->parameters.begin(), it2);
//Parameters end here, additional "parameters" are used directly as script
if ( distance == params )
{
conditionBody += CStrW(L") ");
allParameters = false;
}
//Take display parameter and translate into JS usable code...evilness
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
//Don't use specialized find, since we're searching for a different member
std::set<TriggerParameter>::const_iterator specParam = std::find(
specParameters.begin(), specParameters.end(), (int)distance);
std::wstring combined = std::wstring( it->functionName + specParam->name );
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
if ( m_TriggerTranslations[combined].empty() )
conditionBody += *it2;
else
conditionBody += m_TriggerTranslations[combined][translatedIndex];
if ( distance + 1 < params )
conditionBody += CStrW(L", ");
}
if ( allParameters ) //Otherwise, closed inside loop
conditionBody += CStrW(L")");
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
conditionBody += CStrW(L" )");
if ( std::distance(it, trigger.conditions.end()) != 1 )
conditionBody += linkLogic[it->linkLogic];
}
conditionBody += CStrW(L" );");
}
CStrW effectBody;
for ( std::list<MapTriggerEffect>::const_iterator it = trigger.effects.begin();
it != trigger.effects.end(); ++it )
{
effectBody += it->functionName;
effectBody += CStrW(L"(");
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
it->parameters.end(); ++it2 )
{
size_t distance = std::distance(it->parameters.begin(), it2);
//Take display parameter and translate into JS usable code...evilness
CTriggerSpec spec = *std::find( m_EffectSpecs.begin(), m_EffectSpecs.end(), it->displayName );
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
//Don't use specialized find, since we're searching for a different member
std::set<TriggerParameter>::const_iterator specParam = std::find(
specParameters.begin(), specParameters.end(), (int)distance);
std::wstring combined = std::wstring( it->functionName + specParam->name );
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
if ( m_TriggerTranslations[combined].empty() )
effectBody += *it2;
else
effectBody += m_TriggerTranslations[combined][translatedIndex];
std::list<CStrW>::const_iterator endIt = it->parameters.end();
if ( std::distance(it2, endIt) != 1 )
effectBody += CStrW(L", ");
}
effectBody += CStrW(L");");
}
group.triggers.push_back(trigger);
CTrigger* newTrigger = new CTrigger(trigger.name, trigger.active, trigger.timeValue,
trigger.maxRunCount, conditionBody, effectBody);
AddTrigger(newTrigger);
}
//XML stuff
bool CTriggerManager::LoadXml( const CStr& filename )
{
CXeromyces XeroFile;
if ( XeroFile.Load( filename.c_str() ) != PSRETURN_OK )
return false;
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(condition);
EL(effect);
EL(definitions);
#undef EL
#undef AT
//Return false on any error to be extra sure the point gets across (FIX IT)
XMBElement root = XeroFile.GetRoot();
if ( root.GetNodeName() != el_definitions )
return false;
XERO_ITER_EL(root, rootChild)
{
int name = rootChild.GetNodeName();
if ( name == el_condition )
{
if ( !LoadTriggerSpec(rootChild, XeroFile, true) )
{
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <condition> tag. File: %s", filename.c_str());
return false;
}
}
else if ( name == el_effect )
{
if ( !LoadTriggerSpec(rootChild, XeroFile, false) )
{
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <effect> tag. File: %s", filename.c_str());
return false;
}
}
else
{
LOG(CLogger::Error, LOG_CATEGORY, "Invalid tag in trigger XML. File: %s", filename.c_str());
return false;
}
}
return true;
}
bool CTriggerManager::LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition )
{
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(parameter);
EL(window);
EL(inputtype);
EL(parameterorder);
EL(windowrow);
EL(choices);
EL(choicetranslation);
AT(type);
AT(position);
AT(name);
AT(size);
AT(function);
AT(funcParameters);
#undef EL
#undef AT
CTriggerSpec specStore;
specStore.functionName = CStrW( condition.GetAttributes().GetNamedItem(at_function) );
specStore.displayName = CStrW( condition.GetAttributes().GetNamedItem(at_name) );
specStore.funcParameters = CStr( condition.GetAttributes().GetNamedItem(at_funcParameters) ).ToInt();
int row = -1, column = -1;
XERO_ITER_EL(condition, child)
{
int childID = child.GetNodeName();
if ( childID == el_windowrow )
{
++row;
column = -1;
XERO_ITER_EL(child, windowChild)
{
++column;
TriggerParameter specParam(row, column);
specParam.name = windowChild.GetAttributes().GetNamedItem(at_name);
childID = windowChild.GetNodeName();
if ( childID != el_parameter)
return false;
XERO_ITER_EL(windowChild, parameterChild)
{
childID = parameterChild.GetNodeName();
if ( childID == el_window )
{
CStrW type( parameterChild.GetAttributes().GetNamedItem(at_type) );
CStrW pos( parameterChild.GetAttributes().GetNamedItem(at_position) );
CStrW size( parameterChild.GetAttributes().GetNamedItem(at_size) );
specParam.SetWindowData(type, pos, size);
}
else if ( childID == el_inputtype )
specParam.inputType = CStrW( parameterChild.GetText() );
else if ( childID == el_parameterorder )
specParam.parameterOrder = CStrW( parameterChild.GetText() ).ToInt();
else if ( childID == el_choices )
{
std::vector<std::wstring> choices;
CStrW comma(L","), input(parameterChild.GetText());
CStrW substr;
while ( (substr = input.BeforeFirst(comma)) != input )
{
choices.push_back(substr);
input = input.AfterFirst(comma);
}
choices.push_back(substr); //Last element has no comma
m_TriggerChoices[specStore.functionName + specParam.name] = choices;
}
else if ( childID == el_choicetranslation )
{
std::vector<std::wstring> choices;
CStrW comma(L","), input(parameterChild.GetText());
CStrW substr;
while ( (substr = input.BeforeFirst(comma)) != input )
{
choices.push_back(substr);
input = input.AfterFirst(comma);
}
choices.push_back(substr); //Last element has no comma
m_TriggerTranslations[specStore.functionName + specParam.name] = choices;
}
else
return false;
}
specStore.AddParameter(specParam);
}
}
else
return false;
}
if ( isCondition )
m_ConditionSpecs.push_back(specStore);
else
m_EffectSpecs.push_back(specStore);
return true;
}
#include "precompiled.h"
#include "TriggerManager.h"
#include "scripting/ScriptingHost.h"
#include "ps/XML/Xeromyces.h"
#include "ps/XML/XeroXMB.h"
#include "ps/CLogger.h"
#define LOG_CATEGORY "Triggers"
CTrigger::CTrigger()
{
m_timeLeft = m_timeDelay = m_maxRunCount = m_runCount = m_active = 0;
}
CTrigger::~CTrigger()
{
}
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
const CStrW& effectFunc)
{
m_name = name;
m_active = active;
m_timeLeft = m_timeDelay = delay;
m_runCount = 0;
m_maxRunCount = maxRuns;
CStrW validName = name;
validName.Replace(L" ", L"_");
m_conditionFuncString = condFunc;
m_effectFuncString = effectFunc;
m_conditionFunction.Compile( L"TriggerCondition_" + validName, condFunc );
m_effectFunction.Compile( L"TriggerEffect_" + validName, effectFunc );
}
CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
CScriptObject& condFunc, CScriptObject& effectFunc)
{
m_name = name;
m_active = active;
m_timeLeft = m_timeDelay = delay;
m_runCount = 0;
m_maxRunCount = maxRuns;
m_conditionFunction = condFunc;
m_effectFunction = effectFunc;
}
JSBool CTrigger::Construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_PARAMS_CPP(6);
CScriptObject condFunc( JS_ValueToFunction(cx, argv[4]) );
CScriptObject effectFunc( JS_ValueToFunction(cx, argv[5]) );
CTrigger* newTrigger = new CTrigger( ToPrimitive<CStr>( argv[0] ),
ToPrimitive<bool>( argv[1] ),
ToPrimitive<float>( argv[2] ),
ToPrimitive<int>( argv[3]),
condFunc, effectFunc );
g_TriggerManager.AddTrigger(newTrigger);
*rval = OBJECT_TO_JSVAL( newTrigger->GetScript() );
return JS_TRUE;
}
CTrigger& CTrigger::operator= (const CTrigger& trigger)
{
m_name = trigger.m_name;
m_active = trigger.m_active;
m_timeLeft = trigger.m_timeLeft;
m_timeDelay = trigger.m_timeDelay;
m_maxRunCount = trigger.m_maxRunCount;
m_conditionFunction = trigger.m_conditionFunction;
m_effectFunction = trigger.m_effectFunction;
return *this;
}
void CTrigger::ScriptingInit()
{
AddProperty<int>(L"runCount", &CTrigger::m_runCount, true);
AddProperty(L"name", &CTrigger::m_name, true);
AddProperty<int>(L"maxRunCount", &CTrigger::m_maxRunCount);
AddProperty<float>(L"timeDelay", &CTrigger::m_timeDelay);
AddMethod<void, &CTrigger::Activate>( "activate", 0 );
AddMethod<void, &CTrigger::Deactivate>( "deactivate", 0 );
CJSObject<CTrigger>::ScriptingInit("Trigger", CTrigger::Construct, 6);
}
bool CTrigger::ShouldFire()
{
if ( !m_active )
return false;
return m_conditionFunction.Run( this->GetScript() );
}
bool CTrigger::Fire()
{
m_effectFunction.Run( this->GetScript() );
++m_runCount;
m_timeLeft = m_timeDelay;
return (m_runCount < m_maxRunCount);
}
void CTrigger::Activate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
{
m_active = true;
}
void CTrigger::Deactivate(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
{
m_active = false;
}
void TriggerParameter::SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize)
{
windowPosition.Remove( CStrW(L" ") );
windowSize.Remove( CStrW(L" ") );
xPos = windowPosition.BeforeFirst( CStrW(L",") ).ToInt();
yPos = windowPosition.AfterFirst( CStrW(L",") ).ToInt();
xSize = windowSize.BeforeFirst( CStrW(L",") ).ToInt();
ySize = windowSize.AfterFirst( CStrW(L",") ).ToInt();
windowType = _windowType;
}
bool TriggerParameter::operator< ( const TriggerParameter& rhs ) const
{
if ( row < rhs.row )
return true;
else if ( row == rhs.row)
return ( column < rhs.column );
return false;
}
//===========Trigger Manager===========
CTriggerManager::CTriggerManager() : m_UpdateRate(.20f), m_UpdateTime(.20f)
{
}
CTriggerManager::~CTriggerManager()
{
DestroyEngineTriggers();
}
void CTriggerManager::DestroyEngineTriggers()
{
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
{
SAFE_DELETE(it->second);
}
m_TriggerMap.clear();
}
std::vector<std::wstring> CTriggerManager::GetTriggerChoices(const std::wstring& name)
{
return m_TriggerChoices[name];
}
std::vector<std::wstring> CTriggerManager::GetTriggerTranslations(const std::wstring& name)
{
return m_TriggerTranslations[name];
}
void CTriggerManager::Update(float delta_ms)
{
float delta = delta_ms / 1000.f;
m_UpdateTime -= delta;
if ( m_UpdateTime < 0 )
m_UpdateTime += m_UpdateRate;
else
return;
std::list<TriggerIter> expired;
for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
{
if ( it->second->ShouldFire() )
{
it->second->m_timeLeft -= m_UpdateRate;
if ( it->second->m_timeLeft < 0 )
{
if ( !it->second->Fire() )
expired.push_back(it);
}
}
}
//Remove all expired triggers
for ( std::list<TriggerIter>::iterator it = expired.begin(); it != expired.end(); ++it )
{
delete (*it)->second;
m_TriggerMap.erase(*it);
}
}
void CTriggerManager::AddTrigger(CTrigger* trigger)
{
m_TriggerMap[trigger->GetName()] = trigger;
}
void CTriggerManager::AddGroup(const MapTriggerGroup& group)
{
m_GroupList.push_back(group);
}
void CTriggerManager::SetAllGroups(const std::list<MapTriggerGroup>& groups)
{
m_GroupList = groups;
}
void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
{
CStrW conditionBody;
CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
size_t i=0;
bool allParameters = true;
if(trigger.conditions.size() == 0) {
conditionBody = CStrW(L"return ( true );");
}
else {
conditionBody = CStrW(L"return ( ");
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
it != trigger.conditions.end(); ++it, ++i )
{
//Opening parenthesis here?
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
{
if ( blockIt->negated )
conditionBody += CStrW(L"!");
conditionBody += CStrW(L" (");
}
if ( it->negated )
conditionBody += CStrW(L"!");
conditionBody += it->functionName;
conditionBody += CStrW(L"(");
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
it->parameters.end(); ++it2 )
{
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
size_t distance = std::distance(it->parameters.begin(), it2);
//Parameters end here, additional "parameters" are used directly as script
if ( distance == params )
{
conditionBody += CStrW(L") ");
allParameters = false;
}
//Take display parameter and translate into JS usable code...evilness
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
//Don't use specialized find, since we're searching for a different member
std::set<TriggerParameter>::const_iterator specParam = std::find(
specParameters.begin(), specParameters.end(), (int)distance);
std::wstring combined = std::wstring( it->functionName + specParam->name );
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
if ( m_TriggerTranslations[combined].empty() )
conditionBody += *it2;
else
conditionBody += m_TriggerTranslations[combined][translatedIndex];
if ( distance + 1 < params )
conditionBody += CStrW(L", ");
}
if ( allParameters ) //Otherwise, closed inside loop
conditionBody += CStrW(L")");
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
conditionBody += CStrW(L" )");
if ( std::distance(it, trigger.conditions.end()) != 1 )
conditionBody += linkLogic[it->linkLogic];
}
conditionBody += CStrW(L" );");
}
CStrW effectBody;
for ( std::list<MapTriggerEffect>::const_iterator it = trigger.effects.begin();
it != trigger.effects.end(); ++it )
{
effectBody += it->functionName;
effectBody += CStrW(L"(");
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
it->parameters.end(); ++it2 )
{
size_t distance = std::distance(it->parameters.begin(), it2);
//Take display parameter and translate into JS usable code...evilness
CTriggerSpec spec = *std::find( m_EffectSpecs.begin(), m_EffectSpecs.end(), it->displayName );
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
//Don't use specialized find, since we're searching for a different member
std::set<TriggerParameter>::const_iterator specParam = std::find(
specParameters.begin(), specParameters.end(), (int)distance);
std::wstring combined = std::wstring( it->functionName + specParam->name );
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
if ( m_TriggerTranslations[combined].empty() )
effectBody += *it2;
else
effectBody += m_TriggerTranslations[combined][translatedIndex];
std::list<CStrW>::const_iterator endIt = it->parameters.end();
if ( std::distance(it2, endIt) != 1 )
effectBody += CStrW(L", ");
}
effectBody += CStrW(L");");
}
group.triggers.push_back(trigger);
CTrigger* newTrigger = new CTrigger(trigger.name, trigger.active, trigger.timeValue,
trigger.maxRunCount, conditionBody, effectBody);
AddTrigger(newTrigger);
}
//XML stuff
bool CTriggerManager::LoadXml( const CStr& filename )
{
CXeromyces XeroFile;
if ( XeroFile.Load( filename.c_str() ) != PSRETURN_OK )
return false;
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(condition);
EL(effect);
EL(definitions);
#undef EL
#undef AT
//Return false on any error to be extra sure the point gets across (FIX IT)
XMBElement root = XeroFile.GetRoot();
if ( root.GetNodeName() != el_definitions )
return false;
XERO_ITER_EL(root, rootChild)
{
int name = rootChild.GetNodeName();
if ( name == el_condition )
{
if ( !LoadTriggerSpec(rootChild, XeroFile, true) )
{
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <condition> tag. File: %s", filename.c_str());
return false;
}
}
else if ( name == el_effect )
{
if ( !LoadTriggerSpec(rootChild, XeroFile, false) )
{
LOG(CLogger::Error, LOG_CATEGORY, "Error detected in Trigger XML <effect> tag. File: %s", filename.c_str());
return false;
}
}
else
{
LOG(CLogger::Error, LOG_CATEGORY, "Invalid tag in trigger XML. File: %s", filename.c_str());
return false;
}
}
return true;
}
bool CTriggerManager::LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition )
{
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(parameter);
EL(window);
EL(inputtype);
EL(parameterorder);
EL(windowrow);
EL(choices);
EL(choicetranslation);
AT(type);
AT(position);
AT(name);
AT(size);
AT(function);
AT(funcParameters);
#undef EL
#undef AT
CTriggerSpec specStore;
specStore.functionName = CStrW( condition.GetAttributes().GetNamedItem(at_function) );
specStore.displayName = CStrW( condition.GetAttributes().GetNamedItem(at_name) );
specStore.funcParameters = CStr( condition.GetAttributes().GetNamedItem(at_funcParameters) ).ToInt();
int row = -1, column = -1;
XERO_ITER_EL(condition, child)
{
int childID = child.GetNodeName();
if ( childID == el_windowrow )
{
++row;
column = -1;
XERO_ITER_EL(child, windowChild)
{
++column;
TriggerParameter specParam(row, column);
specParam.name = windowChild.GetAttributes().GetNamedItem(at_name);
childID = windowChild.GetNodeName();
if ( childID != el_parameter)
return false;
XERO_ITER_EL(windowChild, parameterChild)
{
childID = parameterChild.GetNodeName();
if ( childID == el_window )
{
CStrW type( parameterChild.GetAttributes().GetNamedItem(at_type) );
CStrW pos( parameterChild.GetAttributes().GetNamedItem(at_position) );
CStrW size( parameterChild.GetAttributes().GetNamedItem(at_size) );
specParam.SetWindowData(type, pos, size);
}
else if ( childID == el_inputtype )
specParam.inputType = CStrW( parameterChild.GetText() );
else if ( childID == el_parameterorder )
specParam.parameterOrder = CStrW( parameterChild.GetText() ).ToInt();
else if ( childID == el_choices )
{
std::vector<std::wstring> choices;
CStrW comma(L","), input(parameterChild.GetText());
CStrW substr;
while ( (substr = input.BeforeFirst(comma)) != input )
{
choices.push_back(substr);
input = input.AfterFirst(comma);
}
choices.push_back(substr); //Last element has no comma
m_TriggerChoices[specStore.functionName + specParam.name] = choices;
}
else if ( childID == el_choicetranslation )
{
std::vector<std::wstring> choices;
CStrW comma(L","), input(parameterChild.GetText());
CStrW substr;
while ( (substr = input.BeforeFirst(comma)) != input )
{
choices.push_back(substr);
input = input.AfterFirst(comma);
}
choices.push_back(substr); //Last element has no comma
m_TriggerTranslations[specStore.functionName + specParam.name] = choices;
}
else
return false;
}
specStore.AddParameter(specParam);
}
}
else
return false;
}
if ( isCondition )
m_ConditionSpecs.push_back(specStore);
else
m_EffectSpecs.push_back(specStore);
return true;
}

View File

@ -1,221 +1,221 @@
//========================================================
//Description: Manages loading trigger specs (format in Atlas) and updating trigger objects
//=======================================================
#ifndef INCLUDED_TRIGGERMANAGER
#define INCLUDED_TRIGGERMANAGER
#include "ps/Singleton.h"
#include "scripting/ScriptableObject.h"
#include "simulation/ScriptObject.h"
#include <list>
#include <set>
class CXeromyces;
class XMBElement;
//Trigger storage - used be Atlas to keep track of different triggers
struct MapTriggerCondition
{
MapTriggerCondition() : linkLogic(0), negated(false) { }
CStrW name, functionName, displayName;
std::list<CStrW> parameters;
int linkLogic; //0 = NONE, 1 = AND, 2 = OR
bool negated;
};
struct MapTriggerEffect
{
CStrW name, functionName, displayName;
std::list<CStrW> parameters;
};
struct MapTriggerLogicBlock
{
MapTriggerLogicBlock(size_t i, bool _not=false) : index(i), negated(_not) { }
size_t index;
bool negated;
bool operator< (const MapTriggerLogicBlock& block) const { return (index < block.index); }
bool operator== (const MapTriggerLogicBlock& block) const { return (index == block.index); }
};
struct MapTrigger
{
MapTrigger() : active(false), maxRunCount(0), timeValue(0) { }
bool active;
int maxRunCount;
float timeValue;
CStrW name, groupName;
std::set<MapTriggerLogicBlock> logicBlocks; //Indices of where "(" 's go before
std::set<size_t> logicBlockEnds; //Indices of where ")" 's come after
std::list<MapTriggerCondition> conditions;
std::list<MapTriggerEffect> effects;
void AddLogicBlock(bool negated) { logicBlocks.insert( MapTriggerLogicBlock(conditions.size(), negated) ); }
void AddLogicBlockEnd() { logicBlockEnds.insert( effects.size() ); }
};
struct MapTriggerGroup
{
MapTriggerGroup() { }
MapTriggerGroup(const CStrW& _name, const CStrW& _parentName) : name(_name), parentName(_parentName) {}
std::list<MapTrigger> triggers;
std::list<CStrW> childGroups; //Indices of children
CStrW name, parentName;
bool operator== (const CStrW& _name) const { return (name == _name); }
bool operator== (const MapTriggerGroup& group) const { return (name == group.name); }
};
struct CopyIfRootChild
{
CopyIfRootChild(std::list<MapTriggerGroup>& groupList) : m_groupList(groupList) {}
void operator() ( const MapTriggerGroup& group )
{
if ( group.parentName == L"Triggers" )
m_groupList.push_back(group);
}
private:
void operator= (const CopyIfRootChild& UNUSED(group)) const {}
std::list<MapTriggerGroup>& m_groupList;
};
//Triggers used by engine
class CTrigger : public CJSObject<CTrigger>
{
int m_runCount;
CStrW m_conditionFuncString, m_effectFuncString, m_name, m_groupName;
CScriptObject m_effectFunction;
CScriptObject m_conditionFunction;
public:
CTrigger();
CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
const CStrW& effectFunc);
CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
CScriptObject& condFunc, CScriptObject& effectFunc);
CTrigger& operator= (const CTrigger& trigger);
~CTrigger();
void SetFunctionBody(const CStrW& body);
const CStrW& GetConditionString() { return m_conditionFuncString; }
const CStrW& GetEffectString() { return m_effectFuncString; }
const CStrW& GetName() { return m_name; }
const CStrW& GetGroupName() { return m_groupName; }
bool ShouldFire();
//Returns false if trigger exceeds run count
bool Fire();
void Activate(JSContext* cx, uintN argc, jsval* argv);
void Deactivate(JSContext* cx, uintN argc, jsval* argv);
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
static void ScriptingInit();
JSContext* m_cx;
bool m_active;
//Changeable by Atlas or needed by manager, no additional affects required
int m_maxRunCount;
float m_timeLeft, m_timeDelay;
};
//*****Holds information specifying how conditions and effects should look like in atlas******
struct TriggerParameter
{
TriggerParameter() {}
TriggerParameter(int _row, int _column) : row(_row), column(_column) {}
void SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize);
//Sort parameters in the order they will be added to a sizer in atlas
bool operator< ( const TriggerParameter& rhs ) const;
bool operator< ( const int parameter ) const { return parameterOrder < parameter; }
bool operator== ( const int parameter ) const { return parameterOrder == parameter; }
CStrW name, windowType, inputType;
int row, column, xPos, yPos, xSize, ySize, parameterOrder;
};
class CTriggerSpec
{
public:
CTriggerSpec() {}
~CTriggerSpec() {}
void AddParameter(const TriggerParameter& param) { parameters.insert(param); }
const std::set<TriggerParameter>& GetParameters() const { return parameters; }
int funcParameters;
CStrW displayName, functionName;
bool operator== (const std::wstring& display) const { return display == displayName; }
private:
//Sorted by parameter order to make things easy for Atlas
std::set<TriggerParameter> parameters;
};
typedef CTriggerSpec CTriggerEffect;
typedef CTriggerSpec CTriggerCondition;
/******************************Trigger manager******************************/
class CTriggerManager : public Singleton<CTriggerManager>
{
public:
typedef std::map<CStrW, CTrigger*>::iterator TriggerIter ;
CTriggerManager();
~CTriggerManager();
//Returns false on detection of error
bool LoadXml( const CStr& filename );
void Update(float delta);
//Add simulation trigger (probably only called from JS)
void AddTrigger(CTrigger* trigger);
void AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger);
void AddGroup(const MapTriggerGroup& group);
void SetAllGroups(const std::list<MapTriggerGroup>& groups);
void DestroyEngineTriggers();
const std::list<CTriggerCondition>& GetAllConditions() const { return m_ConditionSpecs; }
const std::list<CTriggerEffect>& GetAllEffects() const { return m_EffectSpecs; }
const std::list<MapTriggerGroup>& GetAllTriggerGroups() const { return m_GroupList; }
std::vector<std::wstring> GetTriggerChoices(const std::wstring& name);
std::vector<std::wstring> GetTriggerTranslations(const std::wstring& name);
std::map<CStrW, CTrigger*> m_TriggerMap; //Simulation triggers - used in engine
private:
bool LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition );
//Contains choices for trigger choice box parameters, with key = spec.funcName+paramName
std::map<std::wstring, std::vector<std::wstring> > m_TriggerChoices;
std::map<std::wstring, std::vector<std::wstring> > m_TriggerTranslations;
//Holds information which descibes trigger layout in atlas
std::list<MapTriggerGroup> m_GroupList;
std::list<CTriggerCondition> m_ConditionSpecs;
std::list<CTriggerEffect> m_EffectSpecs;
float m_UpdateRate; //TODO: Get this from a config setting
float m_UpdateTime;
};
#define g_TriggerManager CTriggerManager::GetSingleton()
#endif //ifndef INCLUDED_TRIGGERMANAGER
//========================================================
//Description: Manages loading trigger specs (format in Atlas) and updating trigger objects
//=======================================================
#ifndef INCLUDED_TRIGGERMANAGER
#define INCLUDED_TRIGGERMANAGER
#include "ps/Singleton.h"
#include "scripting/ScriptableObject.h"
#include "simulation/ScriptObject.h"
#include <list>
#include <set>
class CXeromyces;
class XMBElement;
//Trigger storage - used be Atlas to keep track of different triggers
struct MapTriggerCondition
{
MapTriggerCondition() : linkLogic(0), negated(false) { }
CStrW name, functionName, displayName;
std::list<CStrW> parameters;
int linkLogic; //0 = NONE, 1 = AND, 2 = OR
bool negated;
};
struct MapTriggerEffect
{
CStrW name, functionName, displayName;
std::list<CStrW> parameters;
};
struct MapTriggerLogicBlock
{
MapTriggerLogicBlock(size_t i, bool _not=false) : index(i), negated(_not) { }
size_t index;
bool negated;
bool operator< (const MapTriggerLogicBlock& block) const { return (index < block.index); }
bool operator== (const MapTriggerLogicBlock& block) const { return (index == block.index); }
};
struct MapTrigger
{
MapTrigger() : active(false), maxRunCount(0), timeValue(0) { }
bool active;
int maxRunCount;
float timeValue;
CStrW name, groupName;
std::set<MapTriggerLogicBlock> logicBlocks; //Indices of where "(" 's go before
std::set<size_t> logicBlockEnds; //Indices of where ")" 's come after
std::list<MapTriggerCondition> conditions;
std::list<MapTriggerEffect> effects;
void AddLogicBlock(bool negated) { logicBlocks.insert( MapTriggerLogicBlock(conditions.size(), negated) ); }
void AddLogicBlockEnd() { logicBlockEnds.insert( effects.size() ); }
};
struct MapTriggerGroup
{
MapTriggerGroup() { }
MapTriggerGroup(const CStrW& _name, const CStrW& _parentName) : name(_name), parentName(_parentName) {}
std::list<MapTrigger> triggers;
std::list<CStrW> childGroups; //Indices of children
CStrW name, parentName;
bool operator== (const CStrW& _name) const { return (name == _name); }
bool operator== (const MapTriggerGroup& group) const { return (name == group.name); }
};
struct CopyIfRootChild
{
CopyIfRootChild(std::list<MapTriggerGroup>& groupList) : m_groupList(groupList) {}
void operator() ( const MapTriggerGroup& group )
{
if ( group.parentName == L"Triggers" )
m_groupList.push_back(group);
}
private:
void operator= (const CopyIfRootChild& UNUSED(group)) const {}
std::list<MapTriggerGroup>& m_groupList;
};
//Triggers used by engine
class CTrigger : public CJSObject<CTrigger>
{
int m_runCount;
CStrW m_conditionFuncString, m_effectFuncString, m_name, m_groupName;
CScriptObject m_effectFunction;
CScriptObject m_conditionFunction;
public:
CTrigger();
CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
const CStrW& effectFunc);
CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
CScriptObject& condFunc, CScriptObject& effectFunc);
CTrigger& operator= (const CTrigger& trigger);
~CTrigger();
void SetFunctionBody(const CStrW& body);
const CStrW& GetConditionString() { return m_conditionFuncString; }
const CStrW& GetEffectString() { return m_effectFuncString; }
const CStrW& GetName() { return m_name; }
const CStrW& GetGroupName() { return m_groupName; }
bool ShouldFire();
//Returns false if trigger exceeds run count
bool Fire();
void Activate(JSContext* cx, uintN argc, jsval* argv);
void Deactivate(JSContext* cx, uintN argc, jsval* argv);
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
static void ScriptingInit();
JSContext* m_cx;
bool m_active;
//Changeable by Atlas or needed by manager, no additional affects required
int m_maxRunCount;
float m_timeLeft, m_timeDelay;
};
//*****Holds information specifying how conditions and effects should look like in atlas******
struct TriggerParameter
{
TriggerParameter() {}
TriggerParameter(int _row, int _column) : row(_row), column(_column) {}
void SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize);
//Sort parameters in the order they will be added to a sizer in atlas
bool operator< ( const TriggerParameter& rhs ) const;
bool operator< ( const int parameter ) const { return parameterOrder < parameter; }
bool operator== ( const int parameter ) const { return parameterOrder == parameter; }
CStrW name, windowType, inputType;
int row, column, xPos, yPos, xSize, ySize, parameterOrder;
};
class CTriggerSpec
{
public:
CTriggerSpec() {}
~CTriggerSpec() {}
void AddParameter(const TriggerParameter& param) { parameters.insert(param); }
const std::set<TriggerParameter>& GetParameters() const { return parameters; }
int funcParameters;
CStrW displayName, functionName;
bool operator== (const std::wstring& display) const { return display == displayName; }
private:
//Sorted by parameter order to make things easy for Atlas
std::set<TriggerParameter> parameters;
};
typedef CTriggerSpec CTriggerEffect;
typedef CTriggerSpec CTriggerCondition;
/******************************Trigger manager******************************/
class CTriggerManager : public Singleton<CTriggerManager>
{
public:
typedef std::map<CStrW, CTrigger*>::iterator TriggerIter ;
CTriggerManager();
~CTriggerManager();
//Returns false on detection of error
bool LoadXml( const CStr& filename );
void Update(float delta);
//Add simulation trigger (probably only called from JS)
void AddTrigger(CTrigger* trigger);
void AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger);
void AddGroup(const MapTriggerGroup& group);
void SetAllGroups(const std::list<MapTriggerGroup>& groups);
void DestroyEngineTriggers();
const std::list<CTriggerCondition>& GetAllConditions() const { return m_ConditionSpecs; }
const std::list<CTriggerEffect>& GetAllEffects() const { return m_EffectSpecs; }
const std::list<MapTriggerGroup>& GetAllTriggerGroups() const { return m_GroupList; }
std::vector<std::wstring> GetTriggerChoices(const std::wstring& name);
std::vector<std::wstring> GetTriggerTranslations(const std::wstring& name);
std::map<CStrW, CTrigger*> m_TriggerMap; //Simulation triggers - used in engine
private:
bool LoadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition );
//Contains choices for trigger choice box parameters, with key = spec.funcName+paramName
std::map<std::wstring, std::vector<std::wstring> > m_TriggerChoices;
std::map<std::wstring, std::vector<std::wstring> > m_TriggerTranslations;
//Holds information which descibes trigger layout in atlas
std::list<MapTriggerGroup> m_GroupList;
std::list<CTriggerCondition> m_ConditionSpecs;
std::list<CTriggerEffect> m_EffectSpecs;
float m_UpdateRate; //TODO: Get this from a config setting
float m_UpdateTime;
};
#define g_TriggerManager CTriggerManager::GetSingleton()
#endif //ifndef INCLUDED_TRIGGERMANAGER

View File

@ -1,96 +1,96 @@
#include "precompiled.h"
#include "lib/timer.h"
#include "simulation/Scheduler.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/Entity.h"
#include "simulation/Projectile.h"
#include "simulation/EventHandlers.h"
#include "simulation/TriggerManager.h"
#include "simulation/FormationManager.h"
#include "simulation/FormationCollection.h"
#include "simulation/ProductionQueue.h"
#include "simulation/Technology.h"
#include "simulation/TechnologyCollection.h"
#include "simulation/PathfindEngine.h"
void SimulationScriptInit()
{
CJSProgressTimer::ScriptingInit();
CEntityTemplate::ScriptingInit();
CEntity::ScriptingInit();
CProjectile::ScriptingInit();
CTrigger::ScriptingInit();
CProductionItem::ScriptingInit();
CProductionQueue::ScriptingInit();
CTechnology::ScriptingInit();
EntityCollection::Init( "EntityCollection" );
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
g_ScriptingHost.DefineConstant( "NOTIFY_ATTACK", CEntityListener::NOTIFY_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_DAMAGE", CEntityListener::NOTIFY_DAMAGE );
g_ScriptingHost.DefineConstant( "NOTIFY_COMBAT", CEntityListener::NOTIFY_COMBAT );
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
g_ScriptingHost.DefineConstant( "ORDER_RUN", CEntityOrder::ORDER_RUN );
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
g_ScriptingHost.DefineConstant( "ORDER_CONTACT_ACTION", CEntityOrder::ORDER_CONTACT_ACTION );
g_ScriptingHost.DefineConstant( "ORDER_PRODUCE", CEntityOrder::ORDER_PRODUCE );
g_ScriptingHost.DefineConstant( "ORDER_SET_RALLY_POINT", CEntityOrder::ORDER_SET_RALLY_POINT );
g_ScriptingHost.DefineConstant( "ORDER_SET_STANCE", CEntityOrder::ORDER_SET_STANCE );
g_ScriptingHost.DefineConstant( "ORDER_START_CONSTRUCTION", CEntityOrder::ORDER_START_CONSTRUCTION );
}
void SimulationInit()
{
TIMER("SimulationInit");
new CEntityTemplateCollection;
new CFormationCollection;
new CTechnologyCollection;
g_EntityFormationCollection.LoadTemplates();
g_TechnologyCollection.LoadTechnologies();
new CFormationManager;
new CTriggerManager;
g_TriggerManager.LoadXml(CStr("scripts/TriggerSpecs.xml"));
g_ScriptingHost.RunScript("scripts/trigger_functions.js");
// CEntityManager is managed by CWorld
//new CEntityManager;
new CPathfindEngine;
}
void SimulationShutdown()
{
TIMER_BEGIN("shutdown Pathfinder");
delete &g_Pathfinder;
TIMER_END("shutdown Pathfinder");
// Managed by CWorld
// delete &g_EntityManager;
delete &g_TriggerManager;
delete &g_FormationManager;
delete &g_TechnologyCollection;
delete &g_EntityFormationCollection;
delete &g_EntityTemplateCollection;
}
#include "precompiled.h"
#include "lib/timer.h"
#include "simulation/Scheduler.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/Entity.h"
#include "simulation/Projectile.h"
#include "simulation/EventHandlers.h"
#include "simulation/TriggerManager.h"
#include "simulation/FormationManager.h"
#include "simulation/FormationCollection.h"
#include "simulation/ProductionQueue.h"
#include "simulation/Technology.h"
#include "simulation/TechnologyCollection.h"
#include "simulation/PathfindEngine.h"
void SimulationScriptInit()
{
CJSProgressTimer::ScriptingInit();
CEntityTemplate::ScriptingInit();
CEntity::ScriptingInit();
CProjectile::ScriptingInit();
CTrigger::ScriptingInit();
CProductionItem::ScriptingInit();
CProductionQueue::ScriptingInit();
CTechnology::ScriptingInit();
EntityCollection::Init( "EntityCollection" );
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
g_ScriptingHost.DefineConstant( "NOTIFY_ATTACK", CEntityListener::NOTIFY_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_DAMAGE", CEntityListener::NOTIFY_DAMAGE );
g_ScriptingHost.DefineConstant( "NOTIFY_COMBAT", CEntityListener::NOTIFY_COMBAT );
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
g_ScriptingHost.DefineConstant( "ORDER_RUN", CEntityOrder::ORDER_RUN );
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
g_ScriptingHost.DefineConstant( "ORDER_CONTACT_ACTION", CEntityOrder::ORDER_CONTACT_ACTION );
g_ScriptingHost.DefineConstant( "ORDER_PRODUCE", CEntityOrder::ORDER_PRODUCE );
g_ScriptingHost.DefineConstant( "ORDER_SET_RALLY_POINT", CEntityOrder::ORDER_SET_RALLY_POINT );
g_ScriptingHost.DefineConstant( "ORDER_SET_STANCE", CEntityOrder::ORDER_SET_STANCE );
g_ScriptingHost.DefineConstant( "ORDER_START_CONSTRUCTION", CEntityOrder::ORDER_START_CONSTRUCTION );
}
void SimulationInit()
{
TIMER("SimulationInit");
new CEntityTemplateCollection;
new CFormationCollection;
new CTechnologyCollection;
g_EntityFormationCollection.LoadTemplates();
g_TechnologyCollection.LoadTechnologies();
new CFormationManager;
new CTriggerManager;
g_TriggerManager.LoadXml(CStr("scripts/TriggerSpecs.xml"));
g_ScriptingHost.RunScript("scripts/trigger_functions.js");
// CEntityManager is managed by CWorld
//new CEntityManager;
new CPathfindEngine;
}
void SimulationShutdown()
{
TIMER_BEGIN("shutdown Pathfinder");
delete &g_Pathfinder;
TIMER_END("shutdown Pathfinder");
// Managed by CWorld
// delete &g_EntityManager;
delete &g_TriggerManager;
delete &g_FormationManager;
delete &g_TechnologyCollection;
delete &g_EntityFormationCollection;
delete &g_EntityTemplateCollection;
}

View File

@ -1,4 +1,4 @@
extern void SimulationScriptInit();
extern void SimulationInit();
extern void SimulationShutdown();
extern void SimulationScriptInit();
extern void SimulationInit();
extern void SimulationShutdown();

View File

@ -1,360 +1,360 @@
/**
* =========================================================================
* File : SoundGroup.cpp
* Project : 0 A.D.
* Description : Loads up a group of sound files with shared properties,
* and provides a simple interface for playing them.
* =========================================================================
*/
// license: GPL; see sound/license.txt
#include "precompiled.h"
#include "SoundGroup.h"
#include <algorithm>
#include "ps/XML/Xeromyces.h"
#include "ps/CLogger.h"
#include "lib/rand.h"
#define LOG_CATEGORY "audio"
void CSoundGroup::SetGain(float gain)
{
gain = std::min(gain, 1.0f);
m_Gain = gain;
}
void CSoundGroup::SetDefaultValues()
{
m_index = 0;
m_Flags = 0;
m_Intensity = 0;
m_CurTime = 0.0f;
// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
SetGain(0.5f);
m_Pitch = 1.0f;
m_Priority = 60;
m_PitchUpper = 1.1f;
m_PitchLower = 0.9f;
m_GainUpper = 1.0f;
m_GainLower = 0.8f;
m_ConeOuterGain = 0.0f;
m_ConeInnerAngle = 360.0f;
m_ConeOuterAngle = 360.0f;
m_Decay = 3.0f;
m_IntensityThreshold = 3;
// WARNING: m_TimeWindow is currently unused and uninitialized
}
CSoundGroup::CSoundGroup()
{
SetDefaultValues();
}
CSoundGroup::CSoundGroup(const char *XMLfile)
{
SetDefaultValues();
LoadSoundGroup(XMLfile);
}
CSoundGroup::~CSoundGroup()
{
// clean up all the handles from this group.
ReleaseGroup();
}
static float RandFloat(float min, float max)
{
return float(rand(min*100.0f, max*100.0f) / 100.0f);
}
void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
{
// interface/UI sounds should always be played at the listener's
// position, which is achieved by setting position to 0 and
// having that treated as relative to the listener.
float x = 0.0f, y = 0.0f, z = 0.0f;
bool relative = true;
if(!TestFlag(eOmnipresent))
{
x = position.X;
y = position.Y;
z = position.Z;
relative = false;
}
snd_set_pos(hSound, x, y, z, relative);
float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
gain = std::min(gain, 1.0f); // guard against roundoff error in RandFloat or too high m_GainUpper
snd_set_gain(hSound, gain);
const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
snd_set_pitch(hSound, pitch);
snd_play(hSound, m_Priority);
}
void CSoundGroup::PlayNext(const CVector3D& position)
{
if(m_Intensity >= m_IntensityThreshold)
{
if(!is_playing(m_hReplacement))
{
// load up replacement file
m_hReplacement = snd_open(m_filepath + m_intensity_file);
if(m_hReplacement < 0) // one cause: sound is disabled
return;
UploadPropertiesAndPlay(m_hReplacement, position);
}
}
else
{
// if no sounds, return
if (filenames.size() == 0)
return;
// try loading on the fly only when we need the sound to see if that fixes release problems...
if(TestFlag(eRandOrder))
m_index = (size_t)rand(0, (size_t)filenames.size());
// (note: previously snd_group[m_index] was used in place of hs)
Handle hs = snd_open(m_filepath + filenames[m_index]);
if(hs < 0) // one cause: sound is disabled
return;
UploadPropertiesAndPlay(hs, position);
}
playtimes[m_index] = 0.0f;
m_index++;
m_Intensity++;
if(m_Intensity > m_IntensityThreshold)
m_Intensity = m_IntensityThreshold;
if(m_index >= filenames.size())
Reload();
}
void CSoundGroup::Reload()
{
m_index = 0; // reset our index
// get rid of the used handles
snd_group.clear();
// clear out the old timers
playtimes.clear();
//Reload the sounds
/*for(size_t i = 0; i < filenames.size(); i++)
{
string szTemp = m_filepath + filenames[i];
Handle temp = snd_open(m_filepath + filenames[i]);
snd_set_gain(temp, m_Gain);
snd_set_pitch(temp, m_Pitch);
snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
snd_group.push_back(temp);
}*/
while(playtimes.size() < filenames.size())
playtimes.push_back(-1.0f);
//if(TestFlag(eRandOrder))
//random_shuffle(snd_group.begin(), snd_group.end());
}
void CSoundGroup::ReleaseGroup()
{
for(size_t i = m_index; i<snd_group.size(); i++)
{
//if(!is_playing(snd_group[i]))
snd_free(snd_group[i]);
}
snd_group.clear();
playtimes.clear();
//if(is_playing(m_hReplacement))
// snd_free(m_hReplacement);
m_index = 0;
}
void CSoundGroup::Update(float TimeSinceLastFrame)
{
for(size_t i = 0; i < playtimes.size(); i++)
{
if(playtimes[i] >= 0.0f)
playtimes[i] += TimeSinceLastFrame;
if(playtimes[i] >= m_Decay)
{
playtimes[i] = -1.0f;
m_Intensity--;
}
}
}
bool CSoundGroup::LoadSoundGroup(const char *XMLfile)
{
CXeromyces XeroFile;
if (XeroFile.Load(XMLfile) != PSRETURN_OK)
return false;
// adjust the path name for resources if necessary
//m_Name = XMLfile + directorypath;
//Define elements used in XML file
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(soundgroup);
EL(gain);
EL(looping);
EL(omnipresent);
EL(pitch);
EL(priority);
EL(randorder);
EL(randgain);
EL(randpitch);
EL(conegain);
EL(coneinner);
EL(coneouter);
EL(sound);
EL(gainupper);
EL(gainlower);
EL(pitchupper);
EL(pitchlower);
EL(path);
EL(threshold);
EL(decay);
EL(replacement);
#undef AT
#undef EL
XMBElement root = XeroFile.GetRoot();
if (root.GetNodeName() != el_soundgroup)
{
LOG(CLogger::Error, LOG_CATEGORY, "Invalid SoundGroup format (unrecognised root element '%s')", XeroFile.GetElementString(root.GetNodeName()).c_str());
return false;
}
XERO_ITER_EL(root, child)
{
int child_name = child.GetNodeName();
if(child_name == el_gain)
{
SetGain(CStr(child.GetText()).ToFloat());
}
if(child_name == el_looping)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eLoop);
}
if(child_name == el_omnipresent)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eOmnipresent);
}
if(child_name == el_pitch)
{
this->m_Pitch = CStr(child.GetText()).ToFloat();
}
if(child_name == el_priority)
{
this->m_Priority = CStr(child.GetText()).ToFloat();
}
if(child_name == el_randorder)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandOrder);
}
if(child_name == el_randgain)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandGain);
}
if(child_name == el_gainupper)
{
this->m_GainUpper = CStr(child.GetText()).ToFloat();
}
if(child_name == el_gainlower)
{
this->m_GainLower = CStr(child.GetText()).ToFloat();
}
if(child_name == el_randpitch)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandPitch);
}
if(child_name == el_pitchupper)
{
this->m_PitchUpper = CStr(child.GetText()).ToFloat();
}
if(child_name == el_pitchlower)
{
this->m_PitchLower = CStr(child.GetText()).ToFloat();
}
if(child_name == el_conegain)
{
this->m_ConeOuterGain = CStr(child.GetText()).ToFloat();
}
if(child_name == el_coneinner)
{
this->m_ConeInnerAngle = CStr(child.GetText()).ToFloat();
}
if(child_name == el_coneouter)
{
this->m_ConeOuterAngle = CStr(child.GetText()).ToFloat();
}
if(child_name == el_sound)
{
CStr szTemp(child.GetText());
this->filenames.push_back(szTemp);
}
if(child_name == el_path)
{
m_filepath = child.GetText();
}
if(child_name == el_threshold)
{
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
m_IntensityThreshold = CStr(child.GetText()).ToFloat();
}
if(child_name == el_decay)
{
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
m_Decay = CStr(child.GetText()).ToFloat();
}
if(child_name == el_replacement)
{
m_intensity_file = child.GetText();
}
}
Reload();
return true;
}
/**
* =========================================================================
* File : SoundGroup.cpp
* Project : 0 A.D.
* Description : Loads up a group of sound files with shared properties,
* and provides a simple interface for playing them.
* =========================================================================
*/
// license: GPL; see sound/license.txt
#include "precompiled.h"
#include "SoundGroup.h"
#include <algorithm>
#include "ps/XML/Xeromyces.h"
#include "ps/CLogger.h"
#include "lib/rand.h"
#define LOG_CATEGORY "audio"
void CSoundGroup::SetGain(float gain)
{
gain = std::min(gain, 1.0f);
m_Gain = gain;
}
void CSoundGroup::SetDefaultValues()
{
m_index = 0;
m_Flags = 0;
m_Intensity = 0;
m_CurTime = 0.0f;
// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
SetGain(0.5f);
m_Pitch = 1.0f;
m_Priority = 60;
m_PitchUpper = 1.1f;
m_PitchLower = 0.9f;
m_GainUpper = 1.0f;
m_GainLower = 0.8f;
m_ConeOuterGain = 0.0f;
m_ConeInnerAngle = 360.0f;
m_ConeOuterAngle = 360.0f;
m_Decay = 3.0f;
m_IntensityThreshold = 3;
// WARNING: m_TimeWindow is currently unused and uninitialized
}
CSoundGroup::CSoundGroup()
{
SetDefaultValues();
}
CSoundGroup::CSoundGroup(const char *XMLfile)
{
SetDefaultValues();
LoadSoundGroup(XMLfile);
}
CSoundGroup::~CSoundGroup()
{
// clean up all the handles from this group.
ReleaseGroup();
}
static float RandFloat(float min, float max)
{
return float(rand(min*100.0f, max*100.0f) / 100.0f);
}
void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
{
// interface/UI sounds should always be played at the listener's
// position, which is achieved by setting position to 0 and
// having that treated as relative to the listener.
float x = 0.0f, y = 0.0f, z = 0.0f;
bool relative = true;
if(!TestFlag(eOmnipresent))
{
x = position.X;
y = position.Y;
z = position.Z;
relative = false;
}
snd_set_pos(hSound, x, y, z, relative);
float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
gain = std::min(gain, 1.0f); // guard against roundoff error in RandFloat or too high m_GainUpper
snd_set_gain(hSound, gain);
const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
snd_set_pitch(hSound, pitch);
snd_play(hSound, m_Priority);
}
void CSoundGroup::PlayNext(const CVector3D& position)
{
if(m_Intensity >= m_IntensityThreshold)
{
if(!is_playing(m_hReplacement))
{
// load up replacement file
m_hReplacement = snd_open(m_filepath + m_intensity_file);
if(m_hReplacement < 0) // one cause: sound is disabled
return;
UploadPropertiesAndPlay(m_hReplacement, position);
}
}
else
{
// if no sounds, return
if (filenames.size() == 0)
return;
// try loading on the fly only when we need the sound to see if that fixes release problems...
if(TestFlag(eRandOrder))
m_index = (size_t)rand(0, (size_t)filenames.size());
// (note: previously snd_group[m_index] was used in place of hs)
Handle hs = snd_open(m_filepath + filenames[m_index]);
if(hs < 0) // one cause: sound is disabled
return;
UploadPropertiesAndPlay(hs, position);
}
playtimes[m_index] = 0.0f;
m_index++;
m_Intensity++;
if(m_Intensity > m_IntensityThreshold)
m_Intensity = m_IntensityThreshold;
if(m_index >= filenames.size())
Reload();
}
void CSoundGroup::Reload()
{
m_index = 0; // reset our index
// get rid of the used handles
snd_group.clear();
// clear out the old timers
playtimes.clear();
//Reload the sounds
/*for(size_t i = 0; i < filenames.size(); i++)
{
string szTemp = m_filepath + filenames[i];
Handle temp = snd_open(m_filepath + filenames[i]);
snd_set_gain(temp, m_Gain);
snd_set_pitch(temp, m_Pitch);
snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
snd_group.push_back(temp);
}*/
while(playtimes.size() < filenames.size())
playtimes.push_back(-1.0f);
//if(TestFlag(eRandOrder))
//random_shuffle(snd_group.begin(), snd_group.end());
}
void CSoundGroup::ReleaseGroup()
{
for(size_t i = m_index; i<snd_group.size(); i++)
{
//if(!is_playing(snd_group[i]))
snd_free(snd_group[i]);
}
snd_group.clear();
playtimes.clear();
//if(is_playing(m_hReplacement))
// snd_free(m_hReplacement);
m_index = 0;
}
void CSoundGroup::Update(float TimeSinceLastFrame)
{
for(size_t i = 0; i < playtimes.size(); i++)
{
if(playtimes[i] >= 0.0f)
playtimes[i] += TimeSinceLastFrame;
if(playtimes[i] >= m_Decay)
{
playtimes[i] = -1.0f;
m_Intensity--;
}
}
}
bool CSoundGroup::LoadSoundGroup(const char *XMLfile)
{
CXeromyces XeroFile;
if (XeroFile.Load(XMLfile) != PSRETURN_OK)
return false;
// adjust the path name for resources if necessary
//m_Name = XMLfile + directorypath;
//Define elements used in XML file
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(soundgroup);
EL(gain);
EL(looping);
EL(omnipresent);
EL(pitch);
EL(priority);
EL(randorder);
EL(randgain);
EL(randpitch);
EL(conegain);
EL(coneinner);
EL(coneouter);
EL(sound);
EL(gainupper);
EL(gainlower);
EL(pitchupper);
EL(pitchlower);
EL(path);
EL(threshold);
EL(decay);
EL(replacement);
#undef AT
#undef EL
XMBElement root = XeroFile.GetRoot();
if (root.GetNodeName() != el_soundgroup)
{
LOG(CLogger::Error, LOG_CATEGORY, "Invalid SoundGroup format (unrecognised root element '%s')", XeroFile.GetElementString(root.GetNodeName()).c_str());
return false;
}
XERO_ITER_EL(root, child)
{
int child_name = child.GetNodeName();
if(child_name == el_gain)
{
SetGain(CStr(child.GetText()).ToFloat());
}
if(child_name == el_looping)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eLoop);
}
if(child_name == el_omnipresent)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eOmnipresent);
}
if(child_name == el_pitch)
{
this->m_Pitch = CStr(child.GetText()).ToFloat();
}
if(child_name == el_priority)
{
this->m_Priority = CStr(child.GetText()).ToFloat();
}
if(child_name == el_randorder)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandOrder);
}
if(child_name == el_randgain)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandGain);
}
if(child_name == el_gainupper)
{
this->m_GainUpper = CStr(child.GetText()).ToFloat();
}
if(child_name == el_gainlower)
{
this->m_GainLower = CStr(child.GetText()).ToFloat();
}
if(child_name == el_randpitch)
{
if(CStr(child.GetText()).ToInt() == 1)
SetFlag(eRandPitch);
}
if(child_name == el_pitchupper)
{
this->m_PitchUpper = CStr(child.GetText()).ToFloat();
}
if(child_name == el_pitchlower)
{
this->m_PitchLower = CStr(child.GetText()).ToFloat();
}
if(child_name == el_conegain)
{
this->m_ConeOuterGain = CStr(child.GetText()).ToFloat();
}
if(child_name == el_coneinner)
{
this->m_ConeInnerAngle = CStr(child.GetText()).ToFloat();
}
if(child_name == el_coneouter)
{
this->m_ConeOuterAngle = CStr(child.GetText()).ToFloat();
}
if(child_name == el_sound)
{
CStr szTemp(child.GetText());
this->filenames.push_back(szTemp);
}
if(child_name == el_path)
{
m_filepath = child.GetText();
}
if(child_name == el_threshold)
{
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
m_IntensityThreshold = CStr(child.GetText()).ToFloat();
}
if(child_name == el_decay)
{
//m_intensity_threshold = CStr(child.GetText()).ToFloat();
m_Decay = CStr(child.GetText()).ToFloat();
}
if(child_name == el_replacement)
{
m_intensity_file = child.GetText();
}
}
Reload();
return true;
}

View File

@ -1,120 +1,120 @@
/**
* =========================================================================
* File : SoundGroup.h
* Project : 0 A.D.
* Description : Loads up a group of sound files with shared properties,
* and provides a simple interface for playing them.
* =========================================================================
*/
// license: GPL; see sound/license.txt
/*
Example usage: (SEE SOUNDGROUPMGR.H)
Example SoundGroup.xml
<?xml version="1.0" encoding="utf-8"?>
<SoundGroup>
<Gain>1.0</Gain>
<Looping>0</Looping>
<Pitch>1.0</Pitch>
<Priority>100</Priority>
<RandOrder>0</RandOrder>
<RandGain>0</RandGain>
<RandPitch>0</RandPitch>
<ConeGain>1.0</ConeGain>
<ConeInner>360</ConeInner>
<ConeOuter>360</ConeOuter>
<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
</SoundGroup>
*/
#ifndef INCLUDED_SOUNDGROUP
#define INCLUDED_SOUNDGROUP
#include "lib/res/handle.h"
#include "ps/CStr.h"
#include "maths/Vector3D.h"
#include "lib/res/sound/snd_mgr.h"
#include <vector>
enum eSndGrpFlags
{
eRandOrder = 0x01,
eRandGain = 0x02,
eRandPitch = 0x04,
eLoop = 0x08,
eOmnipresent = 0x10
};
class CSoundGroup
{
public:
CSoundGroup(const char *XMLfile);
CSoundGroup(void);
~CSoundGroup(void);
// Play next sound in group
// @param position world position of the entity generating the sound
// (ignored if the eOmnipresent flag is set)
void PlayNext(const CVector3D& position);
// Load a group
bool LoadSoundGroup(const char *XMLfile);
void Reload();
// Release all remaining loaded handles
void ReleaseGroup();
// Update SoundGroup, remove dead sounds from intensity count
void Update(float TimeSinceLastFrame);
// Set a flag using a value from eSndGrpFlags
inline void SetFlag(int flag){ m_Flags |= flag; }
// Test flag, returns true if flag is set.
inline bool TestFlag(int flag) { return (m_Flags & flag) != 0;}
private:
void SetGain(float gain);
void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
void SetDefaultValues();
size_t m_index; // index of the next sound to play
Handle m_hReplacement;
std::vector<Handle> snd_group; // we store the handles so we can load now and play later
std::vector<CStr> filenames; // we need the filenames so we can reload when necessary.
std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
CStr m_filepath; // the file path for the list of sound file resources
CStr m_intensity_file; // the replacement aggregate 'intense' sound
float m_CurTime; // Time elapsed since soundgroup was created
float m_TimeWindow; // The Intensity Threshold Window
size_t m_IntensityThreshold; // the allowable intensity before a sound switch
size_t m_Intensity; // our current intensity(number of sounds played since m_CurTime - m_TimeWindow)
float m_Decay; //
unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
float m_Gain;
float m_Pitch;
float m_Priority;
float m_ConeOuterGain;
float m_PitchUpper;
float m_PitchLower;
float m_GainUpper;
float m_GainLower;
float m_ConeInnerAngle;
float m_ConeOuterAngle;
};
#endif //#ifndef INCLUDED_SOUNDGROUP
/**
* =========================================================================
* File : SoundGroup.h
* Project : 0 A.D.
* Description : Loads up a group of sound files with shared properties,
* and provides a simple interface for playing them.
* =========================================================================
*/
// license: GPL; see sound/license.txt
/*
Example usage: (SEE SOUNDGROUPMGR.H)
Example SoundGroup.xml
<?xml version="1.0" encoding="utf-8"?>
<SoundGroup>
<Gain>1.0</Gain>
<Looping>0</Looping>
<Pitch>1.0</Pitch>
<Priority>100</Priority>
<RandOrder>0</RandOrder>
<RandGain>0</RandGain>
<RandPitch>0</RandPitch>
<ConeGain>1.0</ConeGain>
<ConeInner>360</ConeInner>
<ConeOuter>360</ConeOuter>
<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
</SoundGroup>
*/
#ifndef INCLUDED_SOUNDGROUP
#define INCLUDED_SOUNDGROUP
#include "lib/res/handle.h"
#include "ps/CStr.h"
#include "maths/Vector3D.h"
#include "lib/res/sound/snd_mgr.h"
#include <vector>
enum eSndGrpFlags
{
eRandOrder = 0x01,
eRandGain = 0x02,
eRandPitch = 0x04,
eLoop = 0x08,
eOmnipresent = 0x10
};
class CSoundGroup
{
public:
CSoundGroup(const char *XMLfile);
CSoundGroup(void);
~CSoundGroup(void);
// Play next sound in group
// @param position world position of the entity generating the sound
// (ignored if the eOmnipresent flag is set)
void PlayNext(const CVector3D& position);
// Load a group
bool LoadSoundGroup(const char *XMLfile);
void Reload();
// Release all remaining loaded handles
void ReleaseGroup();
// Update SoundGroup, remove dead sounds from intensity count
void Update(float TimeSinceLastFrame);
// Set a flag using a value from eSndGrpFlags
inline void SetFlag(int flag){ m_Flags |= flag; }
// Test flag, returns true if flag is set.
inline bool TestFlag(int flag) { return (m_Flags & flag) != 0;}
private:
void SetGain(float gain);
void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
void SetDefaultValues();
size_t m_index; // index of the next sound to play
Handle m_hReplacement;
std::vector<Handle> snd_group; // we store the handles so we can load now and play later
std::vector<CStr> filenames; // we need the filenames so we can reload when necessary.
std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
CStr m_filepath; // the file path for the list of sound file resources
CStr m_intensity_file; // the replacement aggregate 'intense' sound
float m_CurTime; // Time elapsed since soundgroup was created
float m_TimeWindow; // The Intensity Threshold Window
size_t m_IntensityThreshold; // the allowable intensity before a sound switch
size_t m_Intensity; // our current intensity(number of sounds played since m_CurTime - m_TimeWindow)
float m_Decay; //
unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
float m_Gain;
float m_Pitch;
float m_Priority;
float m_ConeOuterGain;
float m_PitchUpper;
float m_PitchLower;
float m_GainUpper;
float m_GainLower;
float m_ConeInnerAngle;
float m_ConeOuterAngle;
};
#endif //#ifndef INCLUDED_SOUNDGROUP

View File

@ -1,146 +1,146 @@
/**
* =========================================================================
* File : SoundGroupMgr.h
* Project : 0 A.D.
* Description : Manages and updates SoundGroups
* =========================================================================
*/
// license: GPL; see sound/license.txt
// Example usage:
// size_t index;
// CSoundGroupMgr *sgm = CSoundGroupMgr::GetInstance();
// index = sgm->AddGroup("SoundGroup.xml");
// sgm->UpdateSoundGroups(TimeSinceLastFrame); // call in Frame()
// sgm->PlayNext(index); // wash-rinse-repeat
// sgm->RemoveGroup(index); // Remove the group if you like
// sgm->DeleteInstance(); // Delete instance in shutdown
#include "precompiled.h"
#include "SoundGroupMgr.h"
typedef std::vector<CSoundGroup*> SoundGroups;
typedef SoundGroups::iterator SoundGroupIt;
CSoundGroupMgr *CSoundGroupMgr::m_pInstance = 0;
CSoundGroupMgr::CSoundGroupMgr()
{
}
CSoundGroupMgr *CSoundGroupMgr::GetInstance()
{
if(!m_pInstance)
m_pInstance = new CSoundGroupMgr();
return m_pInstance;
}
void CSoundGroupMgr::DeleteInstance()
{
if(m_pInstance)
{
SoundGroupIt vIter = m_pInstance->m_Groups.begin();
while(vIter != m_pInstance->m_Groups.end())
vIter = m_pInstance->RemoveGroup(vIter);
delete m_pInstance;
}
m_pInstance = 0;
}
///////////////////////////////////////////
// AddGroup()
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
// out: size_t index into m_Groups
// Loads the given XML file and returns an index for later use
///////////////////////////////////////////
size_t CSoundGroupMgr::AddGroup(const char *XMLFile)
{
CSoundGroup* newGroup = new CSoundGroup(XMLFile);
m_Groups.push_back(newGroup);
return m_Groups.size() - 1;
}
///////////////////////////////////////////
// RemoveGroup()
// in: size_t index into m_Groups
// out: SoundGroupIt - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
SoundGroupIt CSoundGroupMgr::RemoveGroup(size_t index)
{
SoundGroupIt vIter = m_Groups.begin();
if(index >= m_Groups.size())
return vIter;
CSoundGroup *temp = (*vIter);
(*vIter)->ReleaseGroup();
vIter = m_Groups.erase(vIter+index);
delete temp;
return vIter;
}
///////////////////////////////////////////
// RemoveGroup()
// in: SoundGroupIt - item to remove
// out: SoundGroupIt - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
SoundGroupIt CSoundGroupMgr::RemoveGroup(SoundGroupIt iter)
{
(*iter)->ReleaseGroup();
CSoundGroup *temp = (*iter);
iter = m_Groups.erase(iter);
delete temp;
return iter;
}
///////////////////////////////////////////
// UpdateSoundGroups()
// updates all soundgroups, call in Frame()
///////////////////////////////////////////
void CSoundGroupMgr::UpdateSoundGroups(float TimeSinceLastFrame)
{
SoundGroupIt vIter = m_Groups.begin();
while(vIter != m_Groups.end())
{
(*vIter)->Update(TimeSinceLastFrame);
vIter++;
}
}
///////////////////////////////////////////
// PlayNext()
// in: size_t index - index into m_Groups
// Plays the next queued sound in an indexed group
///////////////////////////////////////////
void CSoundGroupMgr::PlayNext(size_t index, const CVector3D& position)
{
if(index < m_Groups.size())
m_Groups[index]->PlayNext(position);
else
debug_printf("SND: PlayNext(%d) invalid, %d groups defined\n", index, m_Groups.size());
}
/**
* =========================================================================
* File : SoundGroupMgr.h
* Project : 0 A.D.
* Description : Manages and updates SoundGroups
* =========================================================================
*/
// license: GPL; see sound/license.txt
// Example usage:
// size_t index;
// CSoundGroupMgr *sgm = CSoundGroupMgr::GetInstance();
// index = sgm->AddGroup("SoundGroup.xml");
// sgm->UpdateSoundGroups(TimeSinceLastFrame); // call in Frame()
// sgm->PlayNext(index); // wash-rinse-repeat
// sgm->RemoveGroup(index); // Remove the group if you like
// sgm->DeleteInstance(); // Delete instance in shutdown
#include "precompiled.h"
#include "SoundGroupMgr.h"
typedef std::vector<CSoundGroup*> SoundGroups;
typedef SoundGroups::iterator SoundGroupIt;
CSoundGroupMgr *CSoundGroupMgr::m_pInstance = 0;
CSoundGroupMgr::CSoundGroupMgr()
{
}
CSoundGroupMgr *CSoundGroupMgr::GetInstance()
{
if(!m_pInstance)
m_pInstance = new CSoundGroupMgr();
return m_pInstance;
}
void CSoundGroupMgr::DeleteInstance()
{
if(m_pInstance)
{
SoundGroupIt vIter = m_pInstance->m_Groups.begin();
while(vIter != m_pInstance->m_Groups.end())
vIter = m_pInstance->RemoveGroup(vIter);
delete m_pInstance;
}
m_pInstance = 0;
}
///////////////////////////////////////////
// AddGroup()
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
// out: size_t index into m_Groups
// Loads the given XML file and returns an index for later use
///////////////////////////////////////////
size_t CSoundGroupMgr::AddGroup(const char *XMLFile)
{
CSoundGroup* newGroup = new CSoundGroup(XMLFile);
m_Groups.push_back(newGroup);
return m_Groups.size() - 1;
}
///////////////////////////////////////////
// RemoveGroup()
// in: size_t index into m_Groups
// out: SoundGroupIt - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
SoundGroupIt CSoundGroupMgr::RemoveGroup(size_t index)
{
SoundGroupIt vIter = m_Groups.begin();
if(index >= m_Groups.size())
return vIter;
CSoundGroup *temp = (*vIter);
(*vIter)->ReleaseGroup();
vIter = m_Groups.erase(vIter+index);
delete temp;
return vIter;
}
///////////////////////////////////////////
// RemoveGroup()
// in: SoundGroupIt - item to remove
// out: SoundGroupIt - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
SoundGroupIt CSoundGroupMgr::RemoveGroup(SoundGroupIt iter)
{
(*iter)->ReleaseGroup();
CSoundGroup *temp = (*iter);
iter = m_Groups.erase(iter);
delete temp;
return iter;
}
///////////////////////////////////////////
// UpdateSoundGroups()
// updates all soundgroups, call in Frame()
///////////////////////////////////////////
void CSoundGroupMgr::UpdateSoundGroups(float TimeSinceLastFrame)
{
SoundGroupIt vIter = m_Groups.begin();
while(vIter != m_Groups.end())
{
(*vIter)->Update(TimeSinceLastFrame);
vIter++;
}
}
///////////////////////////////////////////
// PlayNext()
// in: size_t index - index into m_Groups
// Plays the next queued sound in an indexed group
///////////////////////////////////////////
void CSoundGroupMgr::PlayNext(size_t index, const CVector3D& position)
{
if(index < m_Groups.size())
m_Groups[index]->PlayNext(position);
else
debug_printf("SND: PlayNext(%d) invalid, %d groups defined\n", index, m_Groups.size());
}

View File

@ -1,67 +1,67 @@
/**
* =========================================================================
* File : SoundGroupMgr.h
* Project : 0 A.D.
* Description : Manages and updates SoundGroups
* =========================================================================
*/
// license: GPL; see sound/license.txt
#include "SoundGroup.h"
#include <vector>
class CSoundGroupMgr
{
public:
std::vector <CSoundGroup *> m_Groups; // a collection of sound groups
static CSoundGroupMgr *m_pInstance; // our static instance of the manager
static CSoundGroupMgr *GetInstance();
static void DeleteInstance();
///////////////////////////////////////////
// UpdateSoundGroups()
// updates all soundgroups, call in Frame()
///////////////////////////////////////////
void UpdateSoundGroups(float TimeSinceLastFrame);
///////////////////////////////////////////
// PlayNext()
// in: size_t index - index into m_Groups
// Plays the next queued sound in an indexed group
///////////////////////////////////////////
void PlayNext(size_t index, const CVector3D& position);
///////////////////////////////////////////
// AddGroup()
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
// out: size_t index into m_Groups
// Loads the given XML file and returns an index for later use
///////////////////////////////////////////
size_t AddGroup(const char *XMLFile);
///////////////////////////////////////////
// RemoveGroup()
// in: size_t index into m_Groups
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
std::vector<CSoundGroup *>::iterator RemoveGroup(size_t index);
///////////////////////////////////////////
// RemoveGroup()
// in: std::vector<CSoundGroup *>::iterator - item to remove
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
std::vector<CSoundGroup *>::iterator RemoveGroup(std::vector<CSoundGroup *>::iterator iter);
private:
CSoundGroupMgr();
CSoundGroupMgr(const CSoundGroupMgr &ref);
CSoundGroupMgr &operator=(const CSoundGroupMgr &ref);
};
#define g_soundGroupMgr CSoundGroupMgr::GetInstance()
/**
* =========================================================================
* File : SoundGroupMgr.h
* Project : 0 A.D.
* Description : Manages and updates SoundGroups
* =========================================================================
*/
// license: GPL; see sound/license.txt
#include "SoundGroup.h"
#include <vector>
class CSoundGroupMgr
{
public:
std::vector <CSoundGroup *> m_Groups; // a collection of sound groups
static CSoundGroupMgr *m_pInstance; // our static instance of the manager
static CSoundGroupMgr *GetInstance();
static void DeleteInstance();
///////////////////////////////////////////
// UpdateSoundGroups()
// updates all soundgroups, call in Frame()
///////////////////////////////////////////
void UpdateSoundGroups(float TimeSinceLastFrame);
///////////////////////////////////////////
// PlayNext()
// in: size_t index - index into m_Groups
// Plays the next queued sound in an indexed group
///////////////////////////////////////////
void PlayNext(size_t index, const CVector3D& position);
///////////////////////////////////////////
// AddGroup()
// in: const char *XMLFile - the filename of the SoundGroup.xml to open
// out: size_t index into m_Groups
// Loads the given XML file and returns an index for later use
///////////////////////////////////////////
size_t AddGroup(const char *XMLFile);
///////////////////////////////////////////
// RemoveGroup()
// in: size_t index into m_Groups
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
std::vector<CSoundGroup *>::iterator RemoveGroup(size_t index);
///////////////////////////////////////////
// RemoveGroup()
// in: std::vector<CSoundGroup *>::iterator - item to remove
// out: std::vector<CSoundGroup *>::iterator - one past the index removed (sometimes useful)
// Removes and Releases a given soundgroup
///////////////////////////////////////////
std::vector<CSoundGroup *>::iterator RemoveGroup(std::vector<CSoundGroup *>::iterator iter);
private:
CSoundGroupMgr();
CSoundGroupMgr(const CSoundGroupMgr &ref);
CSoundGroupMgr &operator=(const CSoundGroupMgr &ref);
};
#define g_soundGroupMgr CSoundGroupMgr::GetInstance()