1
0
forked from 0ad/0ad

First draft of a GPG3-style profiler (including tracing into scripts, after a fashion)

This was SVN commit r2090.
This commit is contained in:
MarkT 2005-03-30 16:14:19 +00:00
parent 9ce31a5c5c
commit bb7a22f32a
32 changed files with 1262 additions and 165 deletions

BIN
binaries/data/crashlog.dmp Normal file

Binary file not shown.

BIN
binaries/data/crashlog.txt Normal file

Binary file not shown.

View File

@ -17,8 +17,10 @@
#include "Hotkey.h"
#include "ConfigDB.h"
#include "Loader.h"
#include "Profile.h"
#include "LoaderThunks.h"
#include "Quaternion.h"
#include "Unit.h"
#include "Model.h"
@ -121,9 +123,13 @@ void CGameView::Render()
g_Renderer.SetCamera(m_Camera);
MICROLOG(L"render terrain");
PROFILE_START( "render terrain" );
RenderTerrain(m_pWorld->GetTerrain());
PROFILE_END( "render terrain" );
MICROLOG(L"render models");
PROFILE_START( "render models" );
RenderModels(m_pWorld->GetUnitManager());
PROFILE_END( "render models" );
}
void CGameView::RenderTerrain(CTerrain *pTerrain)

View File

@ -191,6 +191,12 @@ void CMapReader::ApplyData()
// }
}
// MT: Testing:
if( i == 170 )
{
CStrW tom( "dick, harry" );
}
CUnit* unit = g_UnitMan.CreateUnit(m_ObjectTypes.at(m_Objects[i].m_ObjectIndex), NULL);
if (unit)

View File

@ -453,6 +453,7 @@ void IGUIObject::ScriptEvent(const CStr& Action)
paramData[0] = OBJECT_TO_JSVAL(mouseObj);
jsval result;
JSBool ok = JS_CallFunction(g_ScriptingHost.getContext(), jsGuiObject, it->second, 1, paramData, &result);
if (!ok)
{

View File

@ -26,6 +26,8 @@
#endif
#include "lib/res/cursor.h"
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "ps/Loader.h"
#include "ps/Font.h"
#include "ps/CConsole.h"
@ -489,7 +491,9 @@ static void Render()
oglCheck();
MICROLOG(L"flush frame");
PROFILE_START( "flush frame" );
g_Renderer.FlushFrame();
PROFILE_END( "flush frame" );
glPushAttrib( GL_ENABLE_BIT );
glDisable( GL_LIGHTING );
@ -498,22 +502,30 @@ static void Render()
if( g_EntGraph )
{
PROFILE( "render entity overlays" );
glColor3f( 1.0f, 0.0f, 1.0f );
MICROLOG(L"render entities");
g_EntityManager.renderAll(); // <-- collision outlines, pathing routes
}
PROFILE_START( "render selection" );
g_Mouseover.renderSelectionOutlines();
g_Selection.renderSelectionOutlines();
PROFILE_END( "render selection" );
glPopAttrib();
}
else
{
PROFILE_START( "flush frame" );
g_Renderer.FlushFrame();
PROFILE_END( "flush frame" );
}
oglCheck();
PROFILE_START( "render fonts" );
MICROLOG(L"render fonts");
// overlay mode
glPushAttrib(GL_ENABLE_BIT);
@ -529,13 +541,17 @@ static void Render()
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
PROFILE_END( "render fonts" );
oglCheck();
#ifndef NO_GUI
// Temp GUI message GeeTODO
glLoadIdentity();
MICROLOG(L"render GUI");
PROFILE_START( "render gui" );
g_GUI.Draw();
PROFILE_END( "render gui" );
#endif
oglCheck();
@ -552,6 +568,7 @@ static void Render()
oglCheck();
{
PROFILE( "render console" );
glLoadIdentity();
MICROLOG(L"render console");
@ -562,8 +579,18 @@ static void Render()
oglCheck();
// Profile information
PROFILE_START( "render profiling" );
RenderProfile();
PROFILE_END( "render profiling" );
oglCheck();
if (g_Game && g_Game->IsGameStarted())
{
PROFILE( "render selection overlays" );
g_Mouseover.renderOverlays();
g_Selection.renderOverlays();
}
@ -730,6 +757,7 @@ TIMER(InitScripting)
CEntity::ScriptingInit();
CBaseEntity::ScriptingInit();
JSI_Sound::ScriptingInit();
CProfileNode::ScriptingInit();
#ifndef NO_GUI
JSI_IGUIObject::init();
@ -745,7 +773,6 @@ TIMER(InitScripting)
CJSPropertyAccessor<CEntity>::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor<T> is already being compiled for T = CEntity.
CScriptEvent::ScriptingInit();
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
@ -1223,7 +1250,9 @@ TIMER(init_after_InitRenderer);
in_add_handler(conInputHandler);
in_add_handler(hotkeyInputHandler); // <- Leave this one until after all the others.
in_add_handler(profilehandler);
in_add_handler(hotkeyInputHandler);
// I don't know how much this screws up, but the gui_handler needs
// to be after the hotkey, so that input boxes can be typed in
@ -1279,7 +1308,10 @@ static void Frame()
{
MICROLOG(L"In frame");
PROFILE_START( "update music" );
MusicPlayer.update();
PROFILE_END( "update music" );
static double last_time;
const double time = get_time();
@ -1289,31 +1321,47 @@ static void Frame()
// first call: set last_time and return
assert(TimeSinceLastFrame >= 0.0f);
PROFILE_START( "reload changed files" );
MICROLOG(L"reload files");
res_reload_changed_files();
PROFILE_END( "reload changed files" );
PROFILE_START( "progressive load" );
ProgressiveLoad();
PROFILE_END( "progressive load" );
PROFILE_START( "input" );
MICROLOG(L"input");
in_get_events();
g_SessionManager.Poll();
PROFILE_END( "input" );
PROFILE_START( "gui tick" );
#ifndef NO_GUI
g_GUI.TickObjects();
#endif
PROFILE_END( "gui tick" );
PROFILE_START( "game logic" );
if (g_Game && g_Game->IsGameStarted())
{
PROFILE_START( "simulation update" );
g_Game->Update(TimeSinceLastFrame);
PROFILE_END( "simulation update" );
if (!g_FixedFrameTiming)
{
PROFILE( "camera update" );
g_Game->GetView()->Update(float(TimeSinceLastFrame));
}
PROFILE_START( "selection and interaction ui" );
// TODO Where does GameView end and other things begin?
g_Mouseover.update( TimeSinceLastFrame );
g_Selection.update();
PROFILE_END( "selection and interaction ui" );
PROFILE_START( "sound update" );
CCamera* camera = g_Game->GetView()->GetCamera();
CMatrix3D& orientation = camera->m_Orientation;
@ -1322,6 +1370,7 @@ static void Frame()
float* up = &orientation._data[4];
if(snd_update(pos, dir, up) < 0)
debug_out("snd_update failed\n");
PROFILE_END( "sound update" );
}
else
{
@ -1332,7 +1381,11 @@ static void Frame()
debug_out("snd_update (pos=0 version) failed\n");
}
PROFILE_END( "game logic" );
PROFILE_START( "update console" );
g_Console->Update(TimeSinceLastFrame);
PROFILE_END( "update console" );
// ugly, but necessary. these are one-shot events, have to be reset.
@ -1349,6 +1402,7 @@ static void Frame()
mouseButtons[SDL_BUTTON_WHEELUP] = false;
mouseButtons[SDL_BUTTON_WHEELDOWN] = false;
PROFILE_START( "render" );
if(g_active)
{
MICROLOG(L"render");
@ -1361,6 +1415,10 @@ static void Frame()
else
SDL_Delay(10);
PROFILE_END( "render" );
g_Profiler.Frame();
calc_fps();
if (g_FixedFrameTiming && frameCount==100) quit=true;
}
@ -1371,6 +1429,8 @@ static void Frame()
int main(int argc, char* argv[])
{
new CProfileManager;
MICROLOG(L"In main");
MICROLOG(L"Init");
@ -1393,6 +1453,8 @@ int main(int argc, char* argv[])
MICROLOG(L"Shutdown");
Shutdown();
delete &g_Profiler;
exit(0);
}

View File

@ -6,10 +6,182 @@
#include "gui/CGUI.h"
#endif
#include "timer.h"
#include "Profile.h"
#include "Loader.h"
CGame *g_Game=NULL;
/*
<<<<<<< .mine
namespace PlayerArray_JS
{
JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
CGameAttributes *pInstance=(CGameAttributes *)JS_GetPrivate(cx, obj);
if (!JSVAL_IS_INT(id))
return JS_FALSE;
uint index=g_ScriptingHost.ValueToInt(id);
// Clamp to a preset upper bound.
// FIXME I guess we'll ultimately have max players as a config variable
if (pInstance->m_NumPlayers > PS_MAX_PLAYERS)
pInstance->m_NumPlayers = PS_MAX_PLAYERS;
// Resize array according to new number of players (note that the array
// size will go up to PS_MAX_PLAYERS, but will never be made smaller -
// this to avoid losing player pointers and make sure they are all
// reclaimed in the end - it's just simpler that way ;-) )
if (pInstance->m_NumPlayers+1 > pInstance->m_Players.size())
{
for (size_t i=pInstance->m_Players.size();i<=index;i++)
{
CPlayer *pNewPlayer=new CPlayer((uint)i);
pNewPlayer->SetUpdateCallback(pInstance->m_PlayerUpdateCB, pInstance->m_PlayerUpdateCBData);
pInstance->m_Players.push_back(pNewPlayer);
}
}
if (index > pInstance->m_NumPlayers)
return JS_FALSE;
*vp=OBJECT_TO_JSVAL(pInstance->m_Players[index]->GetScript());
return JS_TRUE;
}
JSBool SetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
return JS_FALSE;
}
JSClass Class = {
"PlayerArray", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
GetProperty, SetProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub
};
JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval )
{
if (argc != 0)
return JS_FALSE;
JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
*rval=OBJECT_TO_JSVAL(newObj);
return JS_TRUE;
}
};
CGameAttributes::CGameAttributes():
m_UpdateCB(NULL),
m_MapFile("test01.pmp"),
m_NumPlayers(2)
{
ONCE(
g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class,
PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
ScriptingInit();
);
m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray");
JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this);
AddSynchedProperty(L"mapFile", &m_MapFile);
AddSynchedProperty(L"numPlayers", &m_NumPlayers);
m_Players.resize(4);
for (int i=0;i<4;i++)
m_Players[i]=new CPlayer(i);
m_Players[0]->SetName(L"Gaia");
m_Players[0]->SetColour(SPlayerColour(0.2f, 0.7f, 0.2f));
m_Players[1]->SetName(L"Acumen");
m_Players[1]->SetColour(SPlayerColour(1.0f, 0.0f, 0.0f));
m_Players[2]->SetName(L"Boco the Insignificant");
m_Players[2]->SetColour(SPlayerColour(0.0f, 0.0f, 1.0f));
m_Players[3]->SetName(L"NoMonkey");
m_Players[3]->SetColour(SPlayerColour(0.5f, 0.0f, 1.0f));
}
CGameAttributes::~CGameAttributes()
{
std::vector<CPlayer *>::iterator it=m_Players.begin();
while (it != m_Players.end())
{
delete *it;
++it;
}
}
jsval CGameAttributes::JSGetPlayers()
{
return OBJECT_TO_JSVAL(m_PlayerArrayJS);
}
void CGameAttributes::SetValue(CStrW name, CStrW value)
{
ISynchedJSProperty *prop=GetSynchedProperty(name);
if (prop)
{
prop->FromString(value);
}
}
void CGameAttributes::Update(CStrW name, ISynchedJSProperty *attrib)
{
if (m_UpdateCB)
m_UpdateCB(name, attrib->ToString(), m_UpdateCBData);
}
void CGameAttributes::SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata)
{
m_PlayerUpdateCB=cb;
m_PlayerUpdateCBData=userdata;
for (size_t i=0;i<m_Players.size();i++)
{
m_Players[i]->SetUpdateCallback(cb, userdata);
}
}
void CGameAttributes::ScriptingInit()
{
AddClassProperty(L"players", (GetFn)&CGameAttributes::JSGetPlayers);
CJSObject<CGameAttributes>::ScriptingInit( "Game" );
}
/*void CGameAttributes::CreateJSObject()
{
CAttributeMap::CreateJSObject();
ONCE(
g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class,
PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
);
m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray");
JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this);
int flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
JS_DefineProperty(g_ScriptingHost.GetContext(), m_JSObject, "players",
OBJECT_TO_JSVAL(m_PlayerArrayJS), NULL, NULL, flags);
}
JSBool CGameAttributes::GetJSProperty(jsval id, jsval *ret)
{
CStr name=g_ScriptingHost.ValueToString(id);
if (name == CStr("players"))
return JS_TRUE;
return CAttributeMap::GetJSProperty(id, ret);
}*//*
=======
>>>>>>> .r2037
*/
// Disable "warning C4355: 'this' : used in base member initializer list".
// "The base-class constructors and class member constructors are called before
// this constructor. In effect, you've passed a pointer to an unconstructed
@ -37,6 +209,8 @@ CGame::CGame():
CGame::~CGame()
{
// Again, the in-game call tree is going to be different to the main menu one.
g_Profiler.StructuralReset();
debug_out("CGame::~CGame(): Game object DESTROYED\n");
}
@ -63,14 +237,19 @@ PSRETURN CGame::ReallyStartGame()
{
#ifndef NO_GUI
jsval rval;
JSBool ok = JS_CallFunctionName(g_ScriptingHost.getContext(),
g_GUI.GetScriptObject(), "reallyStartGame", 0, NULL, &rval);
assert(ok);
#endif
debug_out("GAME STARTED, ALL INIT COMPLETE\n");
m_GameStarted=true;
// The call tree we've built for pregame probably isn't useful in-game.
g_Profiler.StructuralReset();
#ifndef NO_GUI
g_GUI.SendEventToAll("sessionstart");
#endif

View File

@ -18,6 +18,59 @@ ERROR_GROUP(Game);
// This may be overriden by system.cfg ("max_players")
#define PS_MAX_PLAYERS 6
/*
<<<<<<< .mine
namespace PlayerArray_JS
{
JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
};
#define g_GameAttributes CGameAttributes::GetSingleton()
class CGameAttributes:
public CSynchedJSObject<CGameAttributes>,
public Singleton<CGameAttributes>
{
public:
typedef void (UpdateCallback)(CStrW name, CStrW newValue, void *data);
private:
friend JSBool PlayerArray_JS::GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
virtual void Update(CStrW name, ISynchedJSProperty *attrib);
UpdateCallback *m_UpdateCB;
void *m_UpdateCBData;
CPlayer::UpdateCallback *m_PlayerUpdateCB;
void *m_PlayerUpdateCBData;
jsval JSGetPlayers();
public:
CStrW m_MapFile;
uint m_NumPlayers;
CGameAttributes();
virtual ~CGameAttributes();
void SetValue(CStrW name, CStrW value);
inline void SetUpdateCallback(UpdateCallback *cb, void *userdata)
{
m_UpdateCB=cb;
m_UpdateCBData=userdata;
}
void SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata);
std::vector <CPlayer *> m_Players;
JSObject *m_PlayerArrayJS;
static void ScriptingInit();
};
=======
>>>>>>> .r2037
*/
class CGame
{
CWorld m_World;

View File

@ -22,7 +22,6 @@ CPlayerSlot::CPlayerSlot(int slotID, CPlayer *pPlayer):
//AddProperty(L"session", (GetFn)&CPlayerSlot::JSI_GetSession);
AddReadOnlyProperty(L"session", &m_pSession);
AddProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment);
AddReadOnlyProperty(L"player", &m_pPlayer);
}
@ -34,6 +33,7 @@ void CPlayerSlot::ScriptingInit()
AddMethod<bool, &CPlayerSlot::JSI_AssignClosed>("assignClosed", 0);
AddMethod<bool, &CPlayerSlot::JSI_AssignToSession>("assignToSession", 1);
AddMethod<bool, &CPlayerSlot::JSI_AssignOpen>("assignOpen", 0);
AddClassProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment);
// AddMethod<bool, &CPlayerSlot::JSI_AssignAI>("assignAI", <num_args>);
CJSObject<CPlayerSlot>::ScriptingInit("PlayerSlot");
@ -182,8 +182,6 @@ CGameAttributes::CGameAttributes():
AddSynchedProperty(L"mapFile", &m_MapFile);
AddSynchedProperty(L"numSlots", &m_NumSlots, &CGameAttributes::OnNumSlotsUpdate);
AddProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots);
m_Players.resize(9);
for (int i=0;i<9;i++)
m_Players[i]=new CPlayer(i);
@ -248,6 +246,7 @@ void CGameAttributes::ScriptingInit()
PlayerSlotArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
AddMethod<jsval, &CGameAttributes::JSI_GetOpenSlot>("getOpenSlot", 0);
AddClassProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots);
CJSObject<CGameAttributes>::ScriptingInit("GameAttributes");
}

View File

@ -534,7 +534,8 @@ void CSelectedEntities::contextOrder( bool pushQueue )
for( it = m_selected.begin(); it < m_selected.end(); it++ )
if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) )
if( ( (*it)->GetPlayer() == g_Game->GetLocalPlayer() ) &&
( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) )
{
contextRandomized = context;
do
@ -605,7 +606,7 @@ void CMouseoverEntities::update( float timestep )
std::vector<HEntity>::iterator it;
for( it = onscreen->begin(); it < onscreen->end(); it++ )
if( (*it)->m_extant )
if( (*it)->m_extant && ( (*it)->GetPlayer() == g_Game->GetLocalPlayer() ) )
m_mouseover.push_back( SMouseoverFader( *it, m_fademaximum, false ) );
delete( onscreen );
@ -634,6 +635,10 @@ void CMouseoverEntities::update( float timestep )
if( !(*it)->m_extant )
continue;
// Can only bandbox units the local player controls.
if( (*it)->GetPlayer() != g_Game->GetLocalPlayer() )
continue;
CVector3D worldspace = (*it)->m_graphics_position;
float x, y;
@ -723,6 +728,23 @@ void CMouseoverEntities::update( float timestep )
void CMouseoverEntities::addSelection()
{
// Rules for shift-click selection:
// If selecting a non-allied unit, you can only select one. You can't
// select a mix of allied and non-allied units. Therefore:
// Forbid shift-click of enemy units unless the selection is empty
// Forbid shift-click of allied units if the selection contains one
// or more enemy units.
if( ( m_mouseover.size() != 0 ) &&
( m_mouseover.front().entity->GetPlayer() != g_Game->GetLocalPlayer() ) &&
( g_Selection.m_selected.size() != 0 ) )
return;
if( ( g_Selection.m_selected.size() != 0 ) &&
( g_Selection.m_selected.front()->GetPlayer() != g_Game->GetLocalPlayer() ) )
return;
std::vector<SMouseoverFader>::iterator it;
for( it = m_mouseover.begin(); it < m_mouseover.end(); it++ )
if( it->isActive && !g_Selection.isSelected( it->entity ) )
@ -745,7 +767,8 @@ void CMouseoverEntities::setSelection()
void CMouseoverEntities::expandAcrossScreen()
{
std::vector<HEntity>* activeset = g_EntityManager.matches( isMouseoverType, isOnScreen );
std::vector<HEntity>* activeset = g_EntityManager.matches(
CEntityManager::EntityPredicateLogicalAnd<isMouseoverType,isOnScreen> );
m_mouseover.clear();
std::vector<HEntity>::iterator it;
for( it = activeset->begin(); it < activeset->end(); it++ )
@ -987,7 +1010,7 @@ int interactInputHandler( const SDL_Event* ev )
return( EV_PASS );
}
bool isOnScreen( CEntity* ev )
bool isOnScreen( CEntity* ev, void* userdata )
{
CCamera *pCamera=g_Game->GetView()->GetCamera();
@ -1000,7 +1023,7 @@ bool isOnScreen( CEntity* ev )
return( frustum.IsBoxVisible( ev->m_graphics_position, CBound() ) );
}
bool isMouseoverType( CEntity* ev )
bool isMouseoverType( CEntity* ev, void* userdata )
{
std::vector<SMouseoverFader>::iterator it;
for( it = g_Mouseover.m_mouseover.begin(); it < g_Mouseover.m_mouseover.end(); it++ )
@ -1010,29 +1033,3 @@ bool isMouseoverType( CEntity* ev )
}
return( false );
}
/*
void pushCameraTarget( const CVector3D& target )
{
// Save the current position
cameraTargets.push_back( g_Camera.m_Orientation.GetTranslation() );
// And set the camera
setCameraTarget( target );
}
void setCameraTarget( const CVector3D& target )
{
// Maintain the same orientation and level of zoom, if we can
// (do this by working out the point the camera is looking at, saving
// the difference beteen that position and the camera point, and restoring
// that difference to our new target)
cameraDelta = target - g_Camera.GetFocus();
}
void popCameraTarget()
{
cameraDelta = cameraTargets.back() - g_Camera.m_Orientation.GetTranslation();
cameraTargets.pop_back();
}
*/

View File

@ -118,8 +118,8 @@ struct CMouseoverEntities : public Singleton<CMouseoverEntities>
void stopBandbox();
};
bool isMouseoverType( CEntity* ev );
bool isOnScreen( CEntity* ev );
bool isMouseoverType( CEntity* ev, void* userdata );
bool isOnScreen( CEntity* ev, void* userdata );
int interactInputHandler( const SDL_Event* ev );

View File

@ -43,17 +43,6 @@ CNetClient::CNetClient(CGame *pGame, CGameAttributes *pGameAttribs):
m_pGame->GetSimulation()->SetTurnManager(this);
AddProperty(L"onStartGame", &m_OnStartGame);
AddProperty(L"onChat", &m_OnChat);
AddProperty(L"onConnectComplete", &m_OnConnectComplete);
AddProperty(L"onDisconnect", &m_OnDisconnect);
AddProperty(L"onClientConnect", &m_OnClientConnect);
AddProperty(L"onClientDisconnect", &m_OnClientDisconnect);
AddProperty(L"password", &m_Password);
AddProperty(L"playerName", &m_Name);
AddProperty(L"sessions", &m_JSI_ServerSessions);
g_ScriptingHost.SetGlobal("g_NetClient", OBJECT_TO_JSVAL(GetScript()));
}
@ -66,6 +55,20 @@ void CNetClient::ScriptingInit()
{
AddMethod<bool, &CNetClient::JSI_BeginConnect>("beginConnect", 1);
AddClassProperty(L"onStartGame", &CNetClient::m_OnStartGame);
AddClassProperty(L"onChat", &CNetClient::m_OnChat);
AddClassProperty(L"onConnectComplete", &CNetClient::m_OnConnectComplete);
AddClassProperty(L"onDisconnect", &CNetClient::m_OnDisconnect);
AddClassProperty(L"onClientConnect", &CNetClient::m_OnClientConnect);
AddClassProperty(L"onClientDisconnect", &CNetClient::m_OnClientDisconnect);
AddClassProperty(L"password", &CNetClient::m_Password);
AddClassProperty<CStrW>(L"playerName", &CNetClient::m_Name);
AddClassProperty(L"sessions", &CNetClient::m_JSI_ServerSessions);
CJSMap<SessionMap>::ScriptingInit("NetClient_SessionMap");
CJSObject<CNetClient>::ScriptingInit("NetClient");
}

View File

@ -13,6 +13,7 @@
*/
class CNetSession: public CMessageSocket
{
friend class CNetClient;
protected:
/*
The MessageHandler callback follows the contract of HandleMessage, see

View File

@ -12,8 +12,6 @@ CPlayer::CPlayer(uint playerID):
m_Colour(0.7f, 0.7f, 0.7f),
m_UpdateCB(0)
{
AddReadOnlyProperty( L"id", &m_PlayerID );
AddProperty( L"controlled", (GetFn)&CPlayer::JSI_GetControlledEntities);
AddSynchedProperty( L"name", &m_Name );
// HACK - since we have to use setColour to update this, we don't want to
// expose a colour property. Meanwhile, we want to have a property "colour"
@ -22,6 +20,7 @@ CPlayer::CPlayer(uint playerID):
// to CJSObject's list
ISynchedJSProperty *prop=new CSynchedJSProperty<SPlayerColour>(L"colour", &m_Colour, this);
m_SynchedProperties[L"colour"]=prop;
}
CPlayer::~CPlayer()
@ -35,6 +34,14 @@ void CPlayer::ScriptingInit()
{
AddMethod<jsval, &CPlayer::JSI_ToString>( "toString", 0 );
AddMethod<jsval, &CPlayer::JSI_SetColour>( "setColour", 1);
AddReadOnlyClassProperty( L"id", &CPlayer::m_PlayerID );
// MT: Work out how this fits with the Synched stuff...
// AddClassProperty( L"name", &CPlayer::m_Name );
// AddClassProperty( L"colour", &CPlayer::m_Colour );
AddClassProperty( L"controlled", (IJSObject::GetFn)JSI_GetControlledEntities );
CJSObject<CPlayer>::ScriptingInit( "Player" );
}

250
source/ps/Profile.cpp Normal file
View File

@ -0,0 +1,250 @@
#include "precompiled.h"
#include "Profile.h"
// Note: As with the GPG profiler, name is assumed to be a pointer to a constant string; only pointer equality is checked.
CProfileNode::CProfileNode( const char* _name, CProfileNode* _parent )
{
name = _name;
recursion = 0;
calls_total = 0;
calls_frame_current = 0;
#ifdef PROFILE_AMORTIZE
int i;
for( i = 0; i < PROFILE_AMORTIZE_FRAMES; i++ )
{
calls_frame_buffer[i] = 0;
time_frame_buffer[i] = 0.0;
}
calls_frame_last = calls_frame_buffer;
calls_frame_amortized = 0.0f;
#else
calls_frame_last = 0;
#endif
time_total = 0.0;
time_frame_current = 0.0;
#ifdef PROFILE_AMORTIZE
time_frame_last = time_frame_buffer;
time_frame_amortized = 0.0;
#else
time_frame_last = 0.0;
#endif
parent = _parent;
Reset();
}
CProfileNode::~CProfileNode()
{
profile_iterator it;
for( it = children.begin(); it != children.end(); it++ )
delete( *it );
for( it = script_children.begin(); it != script_children.end(); it++ )
delete( *it );
}
const CProfileNode* CProfileNode::GetChild( const char* childName ) const
{
const_profile_iterator it;
for( it = children.begin(); it != children.end(); it++ )
if( (*it)->name == childName )
return( *it );
return( NULL );
}
const CProfileNode* CProfileNode::GetScriptChild( const char* childName ) const
{
const_profile_iterator it;
for( it = script_children.begin(); it != script_children.end(); it++ )
if( (*it)->name == childName )
return( *it );
return( NULL );
}
CProfileNode* CProfileNode::GetChild( const char* childName )
{
profile_iterator it;
for( it = children.begin(); it != children.end(); it++ )
if( (*it)->name == childName )
return( *it );
CProfileNode* newNode = new CProfileNode( childName, this );
children.push_back( newNode );
return( newNode );
}
CProfileNode* CProfileNode::GetScriptChild( const char* childName )
{
profile_iterator it;
for( it = script_children.begin(); it != script_children.end(); it++ )
if( (*it)->name == childName )
return( *it );
CProfileNode* newNode = new CProfileNode( childName, this );
script_children.push_back( newNode );
return( newNode );
}
bool CProfileNode::CanExpand()
{
return( !( children.empty() && script_children.empty() ) );
}
void CProfileNode::Reset()
{
calls_total = 0;
calls_frame_current = 0;
#ifdef PROFILE_AMORTIZE
int i;
for( i = 0; i < PROFILE_AMORTIZE_FRAMES; i++ )
{
calls_frame_buffer[i] = 0;
time_frame_buffer[i] = 0.0;
}
calls_frame_last = calls_frame_buffer;
calls_frame_amortized = 0.0f;
#else
calls_frame_last = 0;
#endif
time_total = 0.0;
time_frame_current = 0.0;
#ifdef PROFILE_AMORTIZE
time_frame_last = time_frame_buffer;
time_frame_amortized = 0.0;
#else
time_frame_last = 0.0;
#endif
profile_iterator it;
for( it = children.begin(); it != children.end(); it++ )
(*it)->Reset();
for( it = script_children.begin(); it != script_children.end(); it++ )
(*it)->Reset();
}
void CProfileNode::Frame()
{
calls_total += calls_frame_current;
time_total += time_frame_current;
#ifdef PROFILE_AMORTIZE
calls_frame_amortized -= *calls_frame_last;
*calls_frame_last = calls_frame_current;
calls_frame_amortized += calls_frame_current;
time_frame_amortized -= *time_frame_last;
*time_frame_last = time_frame_current;
time_frame_amortized += time_frame_current;
if( ++calls_frame_last == ( calls_frame_buffer + PROFILE_AMORTIZE_FRAMES ) )
calls_frame_last = calls_frame_buffer;
if( ++time_frame_last == ( time_frame_buffer + PROFILE_AMORTIZE_FRAMES ) )
time_frame_last = time_frame_buffer;
#else
calls_frame_last = calls_frame_current;
time_frame_last = time_frame_current;
#endif
calls_frame_current = 0;
time_frame_current = 0.0;
profile_iterator it;
for( it = children.begin(); it != children.end(); it++ )
(*it)->Frame();
for( it = script_children.begin(); it != script_children.end(); it++ )
(*it)->Frame();
}
void CProfileNode::Call()
{
calls_frame_current++;
if( recursion++ == 0 )
start = get_time();
}
bool CProfileNode::Return()
{
if( !parent ) return( false );
if( ( --recursion == 0 ) && ( calls_frame_current != 0 ) )
time_frame_current += ( get_time() - start );
return( recursion == 0 );
}
void CProfileNode::ScriptingInit()
{
AddClassProperty( L"name", (IJSObject::GetFn)CProfileNode::JS_GetName );
/*
AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total );
AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last );
AddReadOnlyClassProperty( L"timeTotal", &CProfileNode::time_total );
AddReadOnlyClassProperty( L"timePerFrame", &CProfileNode::time_frame_last );
*/
CJSObject<CProfileNode, true>::ScriptingInit( "ProfilerNode" );
}
CProfileManager::CProfileManager()
{
root = new CProfileNode( "root", NULL );
current = root;
frame_start = 0.0;
}
CProfileManager::~CProfileManager()
{
delete( root );
}
void CProfileManager::Start( const char* name )
{
if( name != current->GetName() )
current = current->GetChild( name );
current->Call();
}
void CProfileManager::StartScript( const char* name )
{
if( name != current->GetName() )
current = current->GetScriptChild( name );
current->Call();
}
void CProfileManager::Stop()
{
if( current->Return() )
current = current->GetParent();
}
void CProfileManager::Reset()
{
root->Reset();
start = get_time();
frame_start = get_time();
}
void CProfileManager::Frame()
{
root->time_frame_current = ( get_time() - frame_start );
root->Frame();
frame_start = get_time();
}
void CProfileManager::StructuralReset()
{
delete( root );
root = new CProfileNode( "root", NULL );
current = root;
ResetProfileViewer();
}
double CProfileManager::GetTime()
{
return( get_time() - start );
}
double CProfileManager::GetFrameTime()
{
return( get_time() - frame_start );
}

147
source/ps/Profile.h Normal file
View File

@ -0,0 +1,147 @@
// Profile.h
//
// GPG3-style hierarchical profiler
//
// Mark Thompson (mark@wildfiregames.com / mot20@cam.ac.uk)
#include <vector>
#include "Singleton.h"
#include "scripting/ScriptableObject.h"
#include "timer.h"
// TODO: Shouldn't depend on this.
#include "ProfileViewer.h"
#define PROFILE_AMORTIZE
#define PROFILE_AMORTIZE_FRAMES 50
class CProfileManager;
class CProfileNode : public CJSObject<CProfileNode, true>
{
friend class CProfileManager;
const char* name;
int calls_total;
int calls_frame_current;
#ifdef PROFILE_AMORTIZE
int calls_frame_buffer[PROFILE_AMORTIZE_FRAMES];
int* calls_frame_last;
float calls_frame_amortized;
#else
int calls_frame_last;
#endif
double time_total;
double time_frame_current;
#ifdef PROFILE_AMORTIZE
double time_frame_buffer[PROFILE_AMORTIZE_FRAMES];
double* time_frame_last;
double time_frame_amortized;
#else
double time_frame_last;
#endif
double start;
int recursion;
CProfileNode* parent;
std::vector<CProfileNode*> children;
std::vector<CProfileNode*> script_children;
public:
typedef std::vector<CProfileNode*>::iterator profile_iterator;
typedef std::vector<CProfileNode*>::const_iterator const_profile_iterator;
CProfileNode( const char* name, CProfileNode* parent );
~CProfileNode();
const char* GetName() const { return( name ); }
int GetCalls() const { return( calls_total ); }
double GetTime() const { return( time_total ); }
#ifdef PROFILE_AMORTIZE
float GetFrameCalls() const { return( calls_frame_amortized / PROFILE_AMORTIZE_FRAMES ); }
double GetFrameTime() const { return( time_frame_amortized / PROFILE_AMORTIZE_FRAMES ); }
#else
int GetFrameCalls() const { return( calls_frame_last ); }
double GetFrameTime() const { return( time_frame_last ); }
#endif
const CProfileNode* GetChild( const char* name ) const;
const CProfileNode* GetScriptChild( const char* name ) const;
const std::vector<CProfileNode*>* GetChildren() const { return( &children ); }
const std::vector<CProfileNode*>* GetScriptChildren() const { return( &script_children ); }
bool CanExpand();
CProfileNode* GetChild( const char* name );
CProfileNode* GetScriptChild( const char* name );
CProfileNode* GetParent() const { return( parent ); }
// Resets timing information for this node and all its children
void Reset();
// Resets frame timings for this node and all its children
void Frame();
// Enters the node
void Call();
// Leaves the node. Returns true if the node has actually been left
bool Return();
// Javascript stuff...
static void ScriptingInit();
jsval JS_GetName() { return( ToJSVal( CStrW( name ) ) ); }
};
class CProfileManager : public Singleton<CProfileManager>
{
CProfileNode* root;
CProfileNode* current;
double start;
double frame_start;
public:
CProfileManager();
~CProfileManager();
// Begins timing for a named subsection
void Start( const char* name );
void StartScript( const char* name );
// Ends timing for the current subsection
void Stop();
// Resets all timing information
void Reset();
// Resets frame timing information
void Frame();
// Resets absolutely everything
void StructuralReset();
inline const CProfileNode* GetCurrent() { return( current ); }
inline const CProfileNode* GetRoot() { return( root ); }
double GetTime();
double GetFrameTime();
};
#define g_Profiler CProfileManager::GetSingleton()
class CProfileSample
{
public:
CProfileSample( const char* name )
{
g_Profiler.Start( name );
}
~CProfileSample()
{
g_Profiler.Stop();
}
};
// Put a PROFILE( xyz ) block at the start of all code to be profiled.
// Profile blocks last until the end of the containing scope.
#define PROFILE( name ) CProfileSample __profile( name )
// Cheat a bit to make things slightly easier on the user
#define PROFILE_START( name ) { CProfileSample __profile( name )
#define PROFILE_END( name ) }

196
source/ps/ProfileViewer.cpp Normal file
View File

@ -0,0 +1,196 @@
#include "precompiled.h"
#include "ProfileViewer.h"
#include "Profile.h"
#include "Renderer.h"
#include "res/unifont.h"
#include "Hotkey.h"
bool profileVisible = true;
extern int g_xres, g_yres;
const CProfileNode* currentNode = NULL;
void ResetProfileViewer()
{
currentNode = NULL;
}
void RenderProfileNode( CProfileNode* node, int currentNodeid )
{
glPushMatrix();
if( node->CanExpand() )
{
glPushMatrix();
glTranslatef( -15.0f, 0.0f, 0.0f );
glwprintf( L"%d", currentNodeid );
glPopMatrix();
}
glPushMatrix();
glwprintf( L"%hs", node->GetName() );
glPopMatrix();
glTranslatef( 230.0f, 0.0f, 0.0f );
glPushMatrix();
#ifdef PROFILE_AMORTIZE
glwprintf( L"%.3f", node->GetFrameCalls() );
#else
glwprintf( L"%d", node->GetFrameCalls() );
#endif
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.3f", node->GetFrameTime() * 1000.0f );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.1f", node->GetFrameTime() * 100.0 / g_Profiler.GetRoot()->GetFrameTime() );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.1f", node->GetFrameTime() * 100.0 / currentNode->GetFrameTime() );
glPopMatrix();
glPopMatrix();
glTranslatef( 0.0f, 20.0f, 0.0f );
}
void RenderProfile()
{
if( !profileVisible ) return;
if( !currentNode ) currentNode = g_Profiler.GetRoot();
glPushMatrix();
glColor3f(1.0f, 1.0f, 1.0f);
glTranslatef(2.0f, g_yres - 20.0f, 0.0f );
glScalef(1.0f, -1.0f, 1.0f);
glPushMatrix();
glwprintf( L"Profiling Information for: %hs (Time in node: %.3f msec/frame)", currentNode->GetName(), currentNode->GetFrameTime() * 1000.0f );
glPopMatrix();
glTranslatef( 20.0f, 20.0f, 0.0f );
glPushMatrix();
glPushMatrix();
glwprintf( L"Name" );
glPopMatrix();
glTranslatef( 230.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"calls/frame" );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"msec/frame" );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%%/frame" );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%%/parent" );
glPopMatrix();
glPopMatrix();
CProfileNode::const_profile_iterator it;
glTranslatef( 0.0f, 20.0f, 0.0f );
float unlogged = currentNode->GetFrameTime();
int currentNodeid = 1;
for( it = currentNode->GetChildren()->begin(); it != currentNode->GetChildren()->end(); it++, currentNodeid++ )
{
unlogged -= (*it)->GetFrameTime();
RenderProfileNode( *it, currentNodeid );
}
glColor3f( 1.0f, 0.5f, 0.5f );
for( it = currentNode->GetScriptChildren()->begin(); it != currentNode->GetScriptChildren()->end(); it++, currentNodeid++ )
{
unlogged -= (*it)->GetFrameTime();
RenderProfileNode( *it, currentNodeid );
}
glColor3f( 1.0f, 1.0f, 1.0f );
glTranslatef( 0.0f, 20.0f, 0.0f );
glPushMatrix();
glPushMatrix();
glwprintf( L"unlogged" );
glPopMatrix();
glTranslatef( 330.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.3f", unlogged * 1000.0f );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.1f", ( unlogged / g_Profiler.GetRoot()->GetFrameTime() ) * 100.0f );
glPopMatrix();
glTranslatef( 100.0f, 0.0f, 0.0f );
glPushMatrix();
glwprintf( L"%.1f", ( unlogged / currentNode->GetFrameTime() ) * 100.0f );
glPopMatrix();
glPopMatrix();
if( currentNode->GetParent() )
{
glTranslatef( 0.0f, 20.0f, 0.0f );
glPushMatrix();
glPushMatrix();
glTranslatef( -15.0f, 0.0f, 0.0f );
glwprintf( L"0" );
glPopMatrix();
glwprintf( L"back to parent" );
glPopMatrix();
}
glPopMatrix();
}
int profilehandler( const SDL_Event* ev )
{
switch( ev->type )
{
case SDL_KEYDOWN:
{
if( profileVisible )
{
int k = ev->key.keysym.sym - SDLK_0;
if( k == 0 )
{
if( currentNode->GetParent() )
currentNode = currentNode->GetParent();
}
else if( ( k >= 1 ) && ( k <= 9 ) )
{
k--;
CProfileNode::const_profile_iterator it;
for( it = currentNode->GetChildren()->begin(); it != currentNode->GetChildren()->end(); it++, k-- )
if( (*it)->CanExpand() && !k )
{
currentNode = (*it);
return( EV_HANDLED );
}
for( it = currentNode->GetScriptChildren()->begin(); it != currentNode->GetScriptChildren()->end(); it++, k-- )
if( (*it)->CanExpand() && !k )
{
currentNode = (*it);
return( EV_HANDLED );
}
return( EV_HANDLED );
}
}
break;
}
case SDL_HOTKEYDOWN:
if( ev->user.code == HOTKEY_PROFILE_TOGGLE )
{
profileVisible = !profileVisible;
return( EV_HANDLED );
}
break;
}
return( EV_PASS );
}

14
source/ps/ProfileViewer.h Normal file
View File

@ -0,0 +1,14 @@
// ProfileViewer.h
//
// A temporary interface for viewing profile information
#ifndef PROFILE_VIEWER_INCLUDED
#define PROFILE_VIEWER_INCLUDED
#include "input.h"
void ResetProfileViewer();
void RenderProfile();
int profilehandler( const SDL_Event* ev );
#endif

View File

@ -32,6 +32,7 @@ void CWorld::Initialize(CGameAttributes *pAttribs)
mapfilename += (CStr)pAttribs->m_MapFile;
CMapReader* reader = 0;
try {
reader = new CMapReader;
reader->LoadMap(mapfilename, &m_Terrain, &m_UnitManager, &g_LightEnv);

View File

@ -140,6 +140,13 @@ template<> bool ToPrimitive<bool>( JSContext* cx, jsval v, bool& Storage );
template<> jsval ToJSVal<bool>( const bool& Native );
template<> jsval ToJSVal<bool>( bool& Native );
/*
// char*
template<> bool ToPrimitive<char*>( JSContext* cx, jsval v, char*& Storage );
template<> jsval ToJSVal<char*>( const char* Native );
template<> jsval ToJSVal<char*>( char* Native );
*/
// CStrW
template<> bool ToPrimitive<CStrW>( JSContext* cx, jsval v, CStrW& Storage );
template<> jsval ToJSVal<CStrW>( const CStrW& Native );

View File

@ -42,17 +42,17 @@ JSBool Point2d_Constructor(JSContext* UNUSEDPARAM(cx), JSObject* obj, uintN argc
void SColour::SColourInit( float _r, float _g, float _b, float _a )
{
AddProperty( L"r", &r );
AddProperty( L"g", &g );
AddProperty( L"b", &b );
AddProperty( L"a", &a );
r = _r; g = _g; b = _b; a = _a;
}
void SColour::ScriptingInit()
{
AddMethod<jsval, &SColour::ToString>( "toString", 0 );
AddClassProperty<float>( L"r", (float IJSObject::*)&SColour::r );
AddClassProperty<float>( L"g", (float IJSObject::*)&SColour::g );
AddClassProperty<float>( L"b", (float IJSObject::*)&SColour::b );
AddClassProperty<float>( L"a", (float IJSObject::*)&SColour::a );
CJSObject<SColour>::ScriptingInit( "Colour", SColour::Construct, 3 );
}

View File

@ -95,7 +95,8 @@ JSPropertySpec ScriptGlobalTable[] =
{ "console", GLOBAL_CONSOLE, JSPROP_PERMANENT | JSPROP_READONLY, JSI_Console::getConsole, NULL },
{ "entities", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetEntitySet, NULL },
{ "players", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetPlayerSet, NULL },
{ "localPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetLocalPlayer, NULL },
{ "localPlayer", 0, JSPROP_PERMANENT, GetLocalPlayer, SetLocalPlayer },
{ "gaiaPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetGaiaPlayer, NULL },
{ 0, 0, 0, 0, 0 },
};
@ -191,7 +192,7 @@ JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval argv, jsv
return( JS_TRUE );
}
JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval argv, jsval* vp )
JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp )
{
std::vector<CPlayer*>* players = g_Game->GetPlayers();
@ -200,10 +201,29 @@ JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval argv, jsval* v
return( JS_TRUE );
}
JSBool GetLocalPlayer( JSContext* cx, JSObject* globalObject, jsval argv, jsval* vp )
JSBool GetLocalPlayer( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp )
{
*vp = OBJECT_TO_JSVAL( g_Game->GetLocalPlayer()->GetScript() );
return( JS_TRUE );
}
JSBool GetGaiaPlayer( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp )
{
*vp = OBJECT_TO_JSVAL( g_Game->GetPlayer( 0 )->GetScript() );
return( JS_TRUE );
}
JSBool SetLocalPlayer( JSContext* context, JSObject* obj, jsval id, jsval* vp )
{
CPlayer* newLocalPlayer = ToNative<CPlayer>( *vp );
if( !newLocalPlayer )
{
JS_ReportError( context, "Not a valid Player." );
return( JS_TRUE );
}
g_Game->SetLocalPlayer( newLocalPlayer );
return( JS_TRUE );
}

View File

@ -13,10 +13,13 @@ JSFunc WriteLog;
// Entity
JSFunc getEntityByHandle;
JSFunc getEntityTemplate;
JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
// Player
JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
JSBool SetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
JSBool GetGaiaPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
// Camera

View File

@ -41,6 +41,8 @@
#ifndef SCRIPTABLE_INCLUDED
#define SCRIPTABLE_INCLUDED
class IJSObject;
class IJSProperty
{
public:
@ -56,15 +58,15 @@ public:
m_Intrinsic(true)
{}
virtual jsval Get( JSContext* cx ) = 0;
virtual void Set( JSContext* cx, jsval Value ) = 0;
virtual jsval Get( JSContext* cx, IJSObject* owner ) = 0;
virtual void Set( JSContext* cx, IJSObject* owner, jsval Value ) = 0;
// Copies the data directly out of a parent property
// Warning: Don't use if you're not certain the properties are not of the same type.
virtual void ImmediateCopy( IJSProperty* Copy ) = 0;
virtual void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) = 0;
jsval Get() { return( Get( g_ScriptingHost.GetContext() ) ); }
void Set( jsval Value ) { return( Set( g_ScriptingHost.GetContext(), Value ) ); }
jsval Get( IJSObject* owner ) { return( Get( g_ScriptingHost.GetContext(), owner ) ); }
void Set( IJSObject* owner, jsval Value ) { return( Set( g_ScriptingHost.GetContext(), owner, Value ) ); }
virtual ~IJSProperty() {}
};
@ -175,7 +177,7 @@ public:
Property = Target->HasProperty( Instance->m_PropertyRoot );
if( Property )
{
*rval = Property->Get( cx );
*rval = Property->Get( cx, Target );
break;
}
Target = Target->m_Parent;
@ -199,7 +201,7 @@ public:
Property = Target->HasProperty( Instance->m_PropertyRoot );
if( Property )
{
str = JS_ValueToString( cx, Property->Get( cx ) );
str = JS_ValueToString( cx, Property->Get( cx, Target ) );
break;
}
Target = Target->m_Parent;
@ -228,11 +230,10 @@ template<typename T> JSClass CJSPropertyAccessor<T>::JSI_Class = {
NULL, NULL, NULL, NULL
};
template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
{
T* m_Data;
IJSObject* m_Owner;
template<typename T, bool ReadOnly> class CJSSharedProperty : public IJSProperty
{
T IJSObject::*m_Data;
// Function on Owner to call after value is changed
IJSObject::NotifyFn m_Update;
@ -241,32 +242,71 @@ template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
IJSObject::NotifyFn m_Freshen;
public:
CJSProperty( T* Data, IJSObject* Owner = NULL, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL )
CJSSharedProperty( T IJSObject::*Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL )
{
m_Data = Data;
m_AllowsInheritance = AllowsInheritance;
m_Update = Update;
m_Freshen = Freshen;
m_Intrinsic = true;
m_Inherited = true;
}
jsval Get( JSContext* cx, IJSObject* owner )
{
if( m_Freshen ) (owner->*m_Freshen)();
return( ToJSVal( owner->*m_Data ) );
}
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
{
assert( "Inheritance not supported for CJSSharedProperties" );
}
void Set( JSContext* cx, IJSObject* owner, jsval Value )
{
if( !ReadOnly )
{
if( m_Freshen ) (owner->*m_Freshen)();
if( ToPrimitive( cx, Value, owner->*m_Data ) )
if( m_Update ) (owner->*m_Update)();
}
}
};
template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
{
T* m_Data;
// Function on Owner to call after value is changed
IJSObject::NotifyFn m_Update;
// Function on Owner to call before reading or writing the value
IJSObject::NotifyFn m_Freshen;
public:
CJSProperty( T* Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL )
{
assert( !( !Owner && ( Freshen || Update ) ) ); // Bad programmer.
m_Data = Data;
m_Owner = Owner;
m_AllowsInheritance = AllowsInheritance;
m_Update = Update;
m_Freshen = Freshen;
m_Intrinsic = true;
}
jsval Get( JSContext* cx )
jsval Get( JSContext* cx, IJSObject* owner )
{
if( m_Freshen ) (m_Owner->*m_Freshen)();
if( m_Freshen ) (owner->*m_Freshen)();
return( ToJSVal( *m_Data ) );
}
void ImmediateCopy( IJSProperty* Copy )
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
{
*m_Data = *( ((CJSProperty<T, ReadOnly>*)Copy)->m_Data );
*m_Data = *( ( (CJSProperty*)CopyProperty )->m_Data );
}
void Set( JSContext* cx, jsval Value )
void Set( JSContext* cx, IJSObject* owner, jsval Value )
{
if( !ReadOnly )
{
if( m_Freshen ) (m_Owner->*m_Freshen)();
if( m_Freshen ) (owner->*m_Freshen)();
if( ToPrimitive( cx, Value, *m_Data ) )
if( m_Update ) (m_Owner->*m_Update)();
if( m_Update ) (owner->*m_Update)();
}
}
@ -288,6 +328,7 @@ public:
{
m_JSAccessor = NULL;
m_Intrinsic = false;
m_Inherited = false;
}
};
@ -322,28 +363,24 @@ public:
if( JSVAL_IS_GCTHING( m_Data ) )
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
}
jsval Get( JSContext* cx )
jsval Get( JSContext* cx, IJSObject* owner )
{
return( m_Data );
}
void Set( JSContext* cx, jsval Value )
void Set( JSContext* cx, IJSObject* owner, jsval Value )
{
Uproot();
m_Data = Value;
Root();
}
void ImmediateCopy( IJSProperty* Copy )
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
{
Uproot();
m_Data = ((CJSValProperty*)Copy)->m_Data;
Root();
assert( 0 && "ImmediateCopy called on a CJSValProperty (something's gone wrong with the inheritance on this object)" );
}
};
class CJSFunctionProperty : public IJSProperty
{
IJSObject* m_Owner;
// Function on Owner to get the value
IJSObject::GetFn m_Getter;
@ -351,28 +388,27 @@ class CJSFunctionProperty : public IJSProperty
IJSObject::SetFn m_Setter;
public:
CJSFunctionProperty( IJSObject* Owner, IJSObject::GetFn Getter, IJSObject::SetFn Setter )
CJSFunctionProperty( IJSObject::GetFn Getter, IJSObject::SetFn Setter )
{
m_Inherited = false;
m_Intrinsic = true;
m_Owner = Owner;
m_Getter = Getter;
m_Setter = Setter;
// Must at least be able to read
assert( m_Owner && m_Getter );
assert( m_Getter );
}
jsval Get( JSContext* cx )
jsval Get( JSContext* cx, IJSObject* owner )
{
return( (m_Owner->*m_Getter)() );
return( (owner->*m_Getter)() );
}
void Set( JSContext* cx, jsval Value )
void Set( JSContext* cx, IJSObject* owner, jsval Value )
{
if( m_Setter )
(m_Owner->*m_Setter)( Value );
(owner->*m_Setter)( Value );
}
void ImmediateCopy( IJSProperty* Copy )
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
{
assert( 0 && "ImmediateCopy called on a property wrapping getter/setter functions" );
assert( 0 && "ImmediateCopy called on a property wrapping getter/setter functions (something's gone wrong with the inheritance for this object)" );
}
};
@ -419,7 +455,9 @@ public:
if( prop )
{
// Already exists
prop->Set( cx, *vp );
prop->Set( cx, this, *vp );
prop->m_Inherited = false;
// If it's a C++ property, reflect this change in objects that inherit this.
if( prop->m_AllowsInheritance && prop->m_Intrinsic )
@ -430,11 +468,11 @@ public:
{
IJSObject* UpdateObj = UpdateSet.back();
UpdateSet.pop_back();
IJSProperty* UpdateProp = UpdateObj->m_Properties[PropertyName];
IJSProperty* UpdateProp = UpdateObj->HasProperty( PropertyName );
// Property must exist, also be a C++ property, and not have its value specified.
if( UpdateProp && UpdateProp->m_Intrinsic && UpdateProp->m_Inherited )
{
UpdateProp->Set( cx, *vp );
UpdateProp->Set( cx, this, *vp );
InheritorsList::iterator it2;
for( it2 = UpdateObj->m_Inheritors.begin(); it2 != UpdateObj->m_Inheritors.end(); it2++ )
UpdateSet.push_back( *it2 );
@ -491,7 +529,12 @@ public:
delete[]( JSI_methods );
}
static void ScriptingShutdown()
{
PropertyTable::iterator it;
for( it = m_SharedProperties.begin(); it != m_SharedProperties.end(); it++ )
delete( it->second );
}
static void DefaultFinalize( JSContext *cx, JSObject *obj )
{
T* Instance = ToNative<T>( cx, obj );
@ -541,6 +584,8 @@ public:
private:
static JSPropertySpec JSI_props[];
static std::vector<JSFunctionSpec> m_Methods;
static PropertyTable m_IntrinsicProperties;
public:
CJSObject()
@ -587,7 +632,7 @@ public:
ReleaseScriptObject();
}
void SetBase( IJSObject* Parent )
{
{
if( m_Parent )
{
// Remove this from the list of our parent's inheritors
@ -627,7 +672,21 @@ public:
if( cp && cp->m_AllowsInheritance )
{
assert( cp->m_Intrinsic );
it->second->ImmediateCopy( cp );
it->second->ImmediateCopy( this, m_Parent, cp );
}
}
// Do the same for the shared properties table, too
for( it = m_IntrinsicProperties.begin(); it != m_IntrinsicProperties.end(); it++ )
{
if( !it->second->m_Inherited )
continue;
IJSProperty* cp = m_Parent->HasProperty( it->first );
if( cp && cp->m_AllowsInheritance )
{
assert( cp->m_Intrinsic );
it->second->ImmediateCopy( this, m_Parent, cp );
}
}
@ -640,10 +699,15 @@ public:
IJSProperty* HasProperty( CStrW PropertyName )
{
PropertyTable::iterator it;
it = m_Properties.find( PropertyName );
if( it == m_Properties.end() )
return( NULL );
it = T::m_IntrinsicProperties.find( PropertyName );
if( it != T::m_IntrinsicProperties.end() )
return( it->second );
it = m_Properties.find( PropertyName );
if( it != m_Properties.end() )
return( it->second );
return( NULL );
}
void AddProperty( CStrW PropertyName, jsval Value )
@ -669,9 +733,9 @@ public:
{
AddProperty( PropertyName, JSParseString( Value ) );
}
void AddProperty( CStrW PropertyName, GetFn Getter, SetFn Setter = NULL )
static void AddClassProperty( CStrW PropertyName, GetFn Getter, SetFn Setter = NULL )
{
m_Properties[PropertyName] = new CJSFunctionProperty( this, Getter, Setter );
T::m_IntrinsicProperties[PropertyName] = new CJSFunctionProperty( Getter, Setter );
}
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
static void AddMethod( const char* Name, uintN MinArgs )
@ -679,13 +743,21 @@ public:
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, MinArgs, 0, 0 };
T::m_Methods.push_back( FnInfo );
}
template<typename PropType> static void AddClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty<PropType, ReadOnly>( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh );
}
template<typename PropType> static void AddReadOnlyClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty<PropType, true>( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh );
}
template<typename PropType> void AddProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
m_Properties[PropertyName] = new CJSProperty<PropType, ReadOnly>( Native, this, PropAllowInheritance, Update, Refresh );
m_Properties[PropertyName] = new CJSProperty<PropType, ReadOnly>( Native, PropAllowInheritance, Update, Refresh );
}
template<typename PropType> void AddReadOnlyProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
m_Properties[PropertyName] = new CJSProperty<PropType, true>( Native, this, PropAllowInheritance, Update, Refresh );
m_Properties[PropertyName] = new CJSProperty<PropType, true>( Native, PropAllowInheritance, Update, Refresh );
}
};
@ -703,13 +775,14 @@ template<typename T, bool ReadOnly> JSPropertySpec CJSObject<T, ReadOnly>::JSI_p
};
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSObject<T, ReadOnly>::m_Methods;
template<typename T, bool ReadOnly> typename CJSObject<typename T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_IntrinsicProperties;
template<typename T, bool ReadOnly> void CJSObject<T, ReadOnly>::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
{
IJSProperty* Property = HasProperty( PropertyName );
if( Property && Property->m_Intrinsic )
{
*vp = Property->Get( cx );
*vp = Property->Get( cx, this );
}
else
{

View File

@ -3,6 +3,7 @@
#include "ScriptingHost.h"
#include "ScriptGlue.h"
#include "CConsole.h"
#include "Profile.h"
#include <sstream>
#include "res/res.h"
@ -53,6 +54,13 @@ ScriptingHost::ScriptingHost() : m_RunTime(NULL), m_Context(NULL), m_GlobalObjec
m_GlobalObject = JS_NewObject(m_Context, &GlobalClass, NULL, NULL);
#ifndef NDEBUG
// Register our script and function handlers - note: docs say they don't like
// nulls passed as closures, nor should they return nulls.
JS_SetExecuteHook( m_RunTime, jshook_script, this );
JS_SetCallHook( m_RunTime, jshook_function, this );
#endif
if (m_GlobalObject == NULL)
throw PSERROR_Scripting_GlobalObjectCreationFailed();
@ -379,3 +387,37 @@ void ScriptingHost::_CollectGarbage()
{
JS_GC(m_Context);
}
#ifndef NDEBUG
void* ScriptingHost::jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure )
{
if( before )
{
g_Profiler.StartScript( "script invocation" );
}
else
g_Profiler.Stop();
return( closure );
}
void* ScriptingHost::jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure )
{
JSFunction* fn = JS_GetFrameFunction( cx, fp );
if( before )
{
if( fn )
{
g_Profiler.StartScript( JS_GetFunctionName( fn ) );
}
else
g_Profiler.StartScript( "function invokation" );
}
else
g_Profiler.Stop();
return( closure );
}
#endif

View File

@ -28,6 +28,10 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
#include <jsapi.h>
#ifndef NDEBUG
#include <jsdbgapi.h>
#endif
// Make JS debugging a little easier by automatically naming GC roots
#ifndef NDEBUG
// Don't simply #define NAME_ALL_GC_ROOTS, because jsapi.h is horridly broken
@ -78,7 +82,12 @@ private:
std::map < std::string, CustomType > m_CustomObjectTypes;
void _CollectGarbage();
#ifndef NDEBUG
// A hook to capture script calls
static void* jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
// A hook to capture function calls
static void* jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
#endif
public:
ScriptingHost();

View File

@ -73,7 +73,7 @@ struct CSynchedJSObjectBase
CSynchedJSObjectBase *m_Owner;
UpdateFn m_Update;
virtual void Set(JSContext *cx, jsval value)
virtual void Set(JSContext *cx, IJSObject* owner, jsval value)
{
if (!ReadOnly)
{
@ -85,12 +85,12 @@ struct CSynchedJSObjectBase
}
}
}
virtual jsval Get(JSContext *cx)
virtual jsval Get(JSContext *cx, IJSObject* owner)
{
return ToJSVal(*m_Data);
}
virtual void ImmediateCopy(IJSProperty *other)
virtual void ImmediateCopy(IJSObject* CopyFrom, IJSObject* CopyTo, IJSProperty *other)
{
*m_Data = *( ((CSynchedJSProperty<PropType, ReadOnly>*)other)->m_Data );
}

View File

@ -11,8 +11,10 @@
CBaseEntity::CBaseEntity()
{
m_base = NULL;
AddProperty( L"tag", &m_Tag, false );
AddProperty( L"parent", (CBaseEntity**)&m_base, false );
AddProperty( L"parent", &m_base, false );
AddProperty( L"actions.move.speed", &m_speed );
AddProperty( L"actions.move.turningradius", &m_turningRadius );
AddProperty( L"actions.attack.range", &m_meleeRange );
@ -24,8 +26,6 @@ CBaseEntity::CBaseEntity()
for( int t = 0; t < EVENT_LAST; t++ )
AddProperty( EventNames[t], &m_EventHandlers[t] );
m_base = NULL;
// Initialize, make life a little easier on the scriptors
m_speed = m_turningRadius = m_meleeRange = m_meleeRangeMin = 0.0f;
m_extant = true; m_corpse = CStrW();
@ -193,7 +193,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement&
{
if( !Existing->m_Intrinsic )
LOG( WARNING, LOG_CATEGORY, "CBaseEntity::XMLAddProperty: %s already defined for %s. Property trees will be merged.", PropertyName.c_str(), m_Tag.c_str() );
Existing->Set( JSParseString( Source.getText() ) );
Existing->Set( this, JSParseString( Source.getText() ) );
Existing->m_Inherited = false;
}
else
@ -221,7 +221,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement&
if( Existing )
{
Existing->Set( JSParseString( Attribute.Value ) );
Existing->Set( this, JSParseString( Attribute.Value ) );
Existing->m_Inherited = false;
}
else
@ -247,6 +247,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement&
void CBaseEntity::ScriptingInit()
{
AddMethod<jsval, &CBaseEntity::ToString>( "toString", 0 );
CJSObject<CBaseEntity>::ScriptingInit( "EntityTemplate" );
}

View File

@ -2,6 +2,8 @@
#include "precompiled.h"
#include "Profile.h"
#include "Entity.h"
#include "EntityManager.h"
#include "BaseEntityCollection.h"
@ -26,7 +28,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
m_ahead.x = sin( m_orientation );
m_ahead.y = cos( m_orientation );
AddProperty( L"template", (CBaseEntity**)&m_base, false, (NotifyFn)&CEntity::loadBase );
AddProperty( L"actions.move.speed", &m_speed );
AddProperty( L"selected", &m_selected, false, (NotifyFn)&CEntity::checkSelection );
AddProperty( L"group", &m_grouped, false, (NotifyFn)&CEntity::checkGroup );
@ -172,6 +173,8 @@ void CEntity::update( size_t timestep )
// still needs to be (re-)evaluated; else 'false' to terminate the processing of
// this entity in this timestep.
PROFILE_START( "state processing" );
while( !m_orderQueue.empty() )
{
CEntityOrder* current = &m_orderQueue.front();
@ -180,6 +183,8 @@ void CEntity::update( size_t timestep )
if( m_transition )
{
PROFILE( "state transition / order" );
CEntity* target = NULL;
if( current->m_data[0].entity )
target = &( *( current->m_data[0].entity ) );
@ -229,8 +234,11 @@ void CEntity::update( size_t timestep )
}
}
PROFILE_END( "state processing" );
if( m_actor )
{
PROFILE( "animation updates" );
if( m_extant )
{
if( ( m_lastState != -1 ) || !m_actor->GetModel()->GetAnimation() )
@ -242,6 +250,7 @@ void CEntity::update( size_t timestep )
if( m_lastState != -1 )
{
PROFILE( "state transition event" );
CEntity* d0;
CVector3D d1;
CEventOrderTransition evt( m_lastState, -1, d0, d1 );
@ -313,7 +322,29 @@ void CEntity::dispatch( const CMessage* msg )
bool CEntity::DispatchEvent( CScriptEvent* evt )
{
return( m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt ) );
// MT: HACK. And it leaks.
static std::map<CStrW, char*> evMap;
char* data;
std::map<CStrW, char*>::iterator it = evMap.find( evt->m_Type );
if( it != evMap.end() )
{
data = it->second;
}
else
{
CStr8 short_string( evt->m_Type );
int length = short_string.length();
data = new char[length + 9];
strcpy( data, "script: " );
strcpy( data + 8, short_string.c_str() );
data[length + 8] = 0;
evMap.insert( std::pair<CStrW, char*>( evt->m_Type, data ) );
}
g_Profiler.StartScript( data );
bool rval = m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt );
g_Profiler.Stop();
return( rval );
}
void CEntity::clearOrders()
@ -613,6 +644,10 @@ void CEntity::ScriptingInit()
AddMethod<bool, &CEntity::Kill>( "kill", 0 );
AddMethod<bool, &CEntity::Damage>( "damage", 1 );
AddMethod<bool, &CEntity::IsIdle>( "isIdle", 0 );
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
CJSObject<CEntity>::ScriptingInit( "Entity", Construct, 2 );
}

View File

@ -54,17 +54,7 @@ HEntity* CEntityManager::getByHandle( u16 index )
return( new HEntity( index ) );
}
std::vector<HEntity>* CEntityManager::matches( EntityPredicate predicate )
{
std::vector<HEntity>* matchlist = new std::vector<HEntity>;
for( int i = 0; i < MAX_HANDLES; i++ )
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
if( predicate( m_entities[i].m_entity ) )
matchlist->push_back( HEntity( i ) );
return( matchlist );
}
std::vector<HEntity>* CEntityManager::matches( EntityPredicateUD predicate, void* userdata )
std::vector<HEntity>* CEntityManager::matches( EntityPredicate predicate, void* userdata )
{
std::vector<HEntity>* matchlist = new std::vector<HEntity>;
for( int i = 0; i < MAX_HANDLES; i++ )
@ -74,26 +64,6 @@ std::vector<HEntity>* CEntityManager::matches( EntityPredicateUD predicate, void
return( matchlist );
}
std::vector<HEntity>* CEntityManager::matches( EntityPredicate predicate1, EntityPredicate predicate2 )
{
std::vector<HEntity>* matchlist = new std::vector<HEntity>;
for( int i = 0; i < MAX_HANDLES; i++ )
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
if( predicate1( m_entities[i].m_entity ) && predicate2( m_entities[i].m_entity ) )
matchlist->push_back( HEntity( i ) );
return( matchlist );
}
std::vector<HEntity>* CEntityManager::matches( EntityPredicateUD predicate1, EntityPredicateUD predicate2, void* userdata )
{
std::vector<HEntity>* matchlist = new std::vector<HEntity>;
for( int i = 0; i < MAX_HANDLES; i++ )
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
if( predicate1( m_entities[i].m_entity, userdata ) && predicate2( m_entities[i].m_entity, userdata ) )
matchlist->push_back( HEntity( i ) );
return( matchlist );
}
std::vector<HEntity>* CEntityManager::getExtant()
{
std::vector<HEntity>* activelist = new std::vector<HEntity>;

View File

@ -79,7 +79,9 @@ void CScheduler::update(size_t simElapsed)
timeFunction.pop();
jsval rval;
m_abortInterval = false;
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
if( top.isRecurrent && !m_abortInterval )
pushInterval( top.delay, top.delay, top.function, top.operateOn );
}
@ -90,6 +92,8 @@ void CScheduler::update(size_t simElapsed)
break;
frameFunction.pop();
jsval rval;
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
}
}

View File

@ -1,6 +1,7 @@
#include "precompiled.h"
#include <timer.h>
#include "Profile.h"
#include "Simulation.h"
#include "TurnManager.h"
@ -53,6 +54,7 @@ void CSimulation::Update(double frameTime)
if( m_DeltaTime >= 0.0 )
{
PROFILE( "simulation turn" );
// A new simulation frame is required.
MICROLOG( L"calculate simulation" );
Simulate();
@ -65,7 +67,9 @@ void CSimulation::Update(double frameTime)
}
}
PROFILE_START( "simulation interpolation" );
Interpolate(frameTime, ((1000.0*m_DeltaTime) / (float)m_pTurnManager->GetTurnLength()) + 1.0);
PROFILE_END( "simulation interpolation" );
}
void CSimulation::Interpolate(double frameTime, double offset)
@ -79,11 +83,18 @@ void CSimulation::Interpolate(double frameTime, double offset)
void CSimulation::Simulate()
{
PROFILE_START( "scheduler tick" );
g_Scheduler.update(m_pTurnManager->GetTurnLength());
g_EntityManager.updateAll( m_pTurnManager->GetTurnLength() );
PROFILE_END( "scheduler tick" );
PROFILE_START( "entity updates" );
g_EntityManager.updateAll( m_pTurnManager->GetTurnLength() );
PROFILE_END( "entity updates" );
PROFILE_START( "turn manager update" );
m_pTurnManager->NewTurn();
m_pTurnManager->IterateBatch(0, TranslateMessage, this);
PROFILE_END( "turn manager update" );
}
uint CSimulation::TranslateMessage(CNetMessage *pMsg, uint clientMask, void *userdata)