1
0
forked from 0ad/0ad

JS Interface to entities. It even partially works now.

This was SVN commit r469.
This commit is contained in:
MarkT 2004-06-10 22:24:03 +00:00
parent 663f25f6b6
commit e4fe4ed602
58 changed files with 3454 additions and 3046 deletions

View File

@ -1,5 +1,4 @@
#include "precompiled.h"
#include "ogl.h"
#include "res/tex.h"
#include "TextureEntry.h"

View File

@ -28,6 +28,7 @@
#include <vector>
#include <algorithm>
#include <string>
// block := power-of-two sized chunk of a file.

View File

@ -42,10 +42,14 @@
#include "PathfindEngine.h"
#include "XML.h"
#include "ConfigDB.h"
#include "scripting/JSInterface_Entity.h"
#include "scripting/JSInterface_BaseEntity.h"
#include "scripting/JSInterface_Vector3D.h"
#include "ConfigDB.h"
#include "CLogger.h"
#ifndef NO_GUI
#include "gui/GUI.h"
#endif
@ -431,7 +435,7 @@ void ParseArgs(int argc, char* argv[])
}
break;
case 'e':
g_EntGraph = true;
g_EntGraph = true; break;
case 'v':
g_VSync = true;
break;
@ -622,7 +626,7 @@ PREVTSC=TSC;
font = font_load("fonts/verdana.fnt");
g_Console = new CConsole(0, g_yres-600.f, 800.f, 600.f);
g_Console = new CConsole(0, g_yres-600.f, g_xres, 600.f);
// create renderer
new CRenderer;
@ -653,6 +657,10 @@ PREVTSC=TSC;
g_EntityTemplateCollection.loadTemplates();
// Register the JavaScript interfaces with the runtime
JSI_Entity::init();
JSI_BaseEntity::init();
JSI_Vector3D::init();
// if no map name specified, load test01.pmp (for convenience during
// development. that means loading no map at all is currently impossible.

View File

@ -22,7 +22,7 @@ class CVector3D
float X, Y, Z;
public:
CVector3D () { }
CVector3D () { X = 0.0f; Y = 0.0f; Z = 0.0f; }
CVector3D (float x, float y, float z);
int operator ! () const ;

View File

@ -0,0 +1,138 @@
#include "precompiled.h"
#include "JSInterface_Vector3D.h"
JSClass JSI_Vector3D::JSI_class = {
"Vector3D", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSI_Vector3D::getProperty, JSI_Vector3D::setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JSI_Vector3D::finalize,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_Vector3D::JSI_props[] =
{
{ "x", JSI_Vector3D::component_x, JSPROP_ENUMERATE },
{ "y", JSI_Vector3D::component_y, JSPROP_ENUMERATE },
{ "z", JSI_Vector3D::component_z, JSPROP_ENUMERATE },
{ 0 }
};
JSFunctionSpec JSI_Vector3D::JSI_methods[] =
{
{ "toString", JSI_Vector3D::toString, 0, 0, 0 },
{ 0 }
};
void JSI_Vector3D::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Vector3D::construct, 0, JSI_props, JSI_methods, NULL, NULL );
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info()
{
owner = NULL;
vector = new CVector3D();
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( float x, float y, float z )
{
owner = NULL;
vector = new CVector3D( x, y, z );
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner )
{
owner = _owner;
updateFn = NULL;
vector = copy;
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void) )
{
owner = _owner;
updateFn = _updateFn;
vector = copy;
}
JSI_Vector3D::Vector3D_Info::~Vector3D_Info()
{
if( !owner ) delete( vector );
}
JSBool JSI_Vector3D::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
if( !vectorInfo ) return( JS_TRUE );
CVector3D* vectorData = vectorInfo->vector;
switch( g_ScriptingHost.ValueToInt( id ) )
{
case component_x: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->X ) ); return( JS_TRUE );
case component_y: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Y ) ); return( JS_TRUE );
case component_z: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Z ) ); return( JS_TRUE );
}
return( JS_FALSE );
}
JSBool JSI_Vector3D::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
if( !vectorInfo ) return( JS_TRUE );
CVector3D* vectorData = vectorInfo->vector;
switch( g_ScriptingHost.ValueToInt( id ) )
{
case component_x: vectorData->X = (float)g_ScriptingHost.ValueToDouble( *vp ); break;
case component_y: vectorData->Y = (float)g_ScriptingHost.ValueToDouble( *vp ); break;
case component_z: vectorData->Z = (float)g_ScriptingHost.ValueToDouble( *vp ); break;
}
if( vectorInfo->owner && vectorInfo->updateFn ) ( (vectorInfo->owner)->*(vectorInfo->updateFn) )();
return( JS_TRUE );
return( JS_FALSE );
}
JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
if( ( argc != 0 ) && ( argc != 3 ) ) return( JS_FALSE );
if( argc == 0 )
{
JS_SetPrivate( cx, obj, new Vector3D_Info() );
return( JS_TRUE );
}
else if( argc == 3 )
{
float x = (float)g_ScriptingHost.ValueToDouble( argv[0] );
float y = (float)g_ScriptingHost.ValueToDouble( argv[1] );
float z = (float)g_ScriptingHost.ValueToDouble( argv[2] );
JS_SetPrivate( cx, obj, new Vector3D_Info( x, y, z ) );
}
return( JS_TRUE );
}
void JSI_Vector3D::finalize( JSContext* cx, JSObject* obj )
{
delete( JS_GetPrivate( cx, obj ) );
}
JSBool JSI_Vector3D::toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
char buffer[256];
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
if( !vectorInfo ) return( JS_TRUE );
CVector3D* vectorData = vectorInfo->vector;
snprintf( buffer, 256, "[object Vector3D: ( %f, %f, %f )]", vectorData->X, vectorData->Y, vectorData->Z );
buffer[255] = 0;
*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
return( JS_TRUE );
}

View File

@ -0,0 +1,49 @@
// JSInterface_Entity.h
//
// Last modified: 03 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
//
// A JavaScript class representing a Prometheus CVector3D object.
//
// Usage: Used when manipulating objects of class 'Vector3D' in JavaScript.
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#include "scripting/ScriptingHost.h"
#include "Vector3D.h"
#ifndef JSI_VECTOR3_INCLUDED
#define JSI_VECTOR3_INCLUDED
class IPropertyOwner;
namespace JSI_Vector3D
{
enum
{
component_x,
component_y,
component_z
};
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
struct Vector3D_Info
{
IPropertyOwner* owner;
void ( IPropertyOwner::*updateFn )();
CVector3D* vector;
Vector3D_Info();
Vector3D_Info( float x, float y, float z );
Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner );
Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)() );
~Vector3D_Info();
};
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
void finalize( JSContext* cx, JSObject* obj );
JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
void init();
};
#endif

View File

@ -5,6 +5,8 @@
#include "Prometheus.h"
#include "sysdep/sysdep.h"
#include "scripting/ScriptingHost.h"
CConsole::CConsole(float X, float Y, float W, float H)
: m_fX(X), m_fY(Y), m_fWidth(W), m_fHeight(H)
{
@ -242,7 +244,7 @@ void CConsole::DrawCursor(void)
//Inserts a character into the buffer.
void CConsole::InsertChar(const int szChar)
void CConsole::InsertChar(const int szChar, const int cooked )
{
static int iHistoryPos = -1;
@ -321,15 +323,16 @@ void CConsole::InsertChar(const int szChar)
default: //Insert a character
if (IsFull()) return;
if (!isprint(szChar)) return;
if( cooked >= 255 ) return;
if (!isprint( cooked )) return;
if (IsEOB()) //are we at the end of the buffer?
m_szBuffer[m_iBufferPos] = szChar; //cat char onto end
m_szBuffer[m_iBufferPos] = cooked; //cat char onto end
else{ //we need to insert
int i;
for(i=m_iBufferLength; i>m_iBufferPos; i--)
m_szBuffer[i] = m_szBuffer[i-1]; // move chars to right
m_szBuffer[i] = szChar;
m_szBuffer[i] = cooked;
}
m_iBufferPos++;
@ -410,6 +413,18 @@ void CConsole::ProcessBuffer(const char* szLine){
}
}
}
else if( szLine[0] == ':' )
{
// Process it as JavaScript
g_ScriptingHost.ExecuteScript( szLine + 1 );
}
else if( szLine[0] == '?' )
{
// Process it as JavaScript and display the result
jsval rval = g_ScriptingHost.ExecuteScript( szLine + 1 );
if( rval )
InsertMessage( g_ScriptingHost.ValueToString( rval ).c_str() );
}
else InsertMessage("<say>: %s", szLine);
delete[] szCommand;
@ -425,6 +440,6 @@ bool conInputHandler(const SDL_Event& ev)
if(ev.type != SDL_KEYDOWN)
return false;
g_Console->InsertChar(ev.key.keysym.sym);
g_Console->InsertChar(ev.key.keysym.sym, ev.key.keysym.unicode );
return g_Console->IsActive();
}

View File

@ -12,7 +12,7 @@
#ifndef CCONSOLE_H
#define CCONSOLE_H
#define BUFFER_SIZE 50
#define BUFFER_SIZE 100
#define FONT_HEIGHT 18
typedef void(*fptr)(void);
@ -70,7 +70,7 @@ public:
void Render();
void InsertMessage(const char* szMessage, ...);
void InsertChar(const int szChar);
void InsertChar(const int szChar, const int cooked);
void SetBuffer(const char* szMessage, ...);
void FlushBuffer();
@ -80,4 +80,7 @@ public:
bool IsActive() { return m_bVisible; }
};
// TODO MT: Better solution to character translation than 'const int cooked'? Anyone?
#endif

View File

@ -193,7 +193,7 @@ public:
virtual u8 *Serialize(u8 *buffer) const;
virtual const u8 *Deserialize(const u8 *buffer, const u8 *bufferend);
private:
protected:
tstring m_String;
TCHAR m_ConversionBuffer[CONVERSION_BUFFER_SIZE];
};

View File

@ -5,6 +5,7 @@
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "precompiled.h"
#include "ogl.h"
#include "Renderer.h"

View File

@ -5,6 +5,7 @@
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "precompiled.h"
#include <assert.h>
#include "ogl.h"

View File

@ -1,6 +1,17 @@
#include "precompiled.h"
#include "ScriptGlue.h"
#include "CConsole.h"
#include "CStr.h"
#include "EntityHandles.h"
#include "Entity.h"
#include "EntityManager.h"
#include "BaseEntityCollection.h"
#include "scripting/JSInterface_Entity.h"
#include "scripting/JSInterface_BaseEntity.h"
#include "scripting/JSInterface_Vector3D.h"
extern CConsole* g_Console;
// Parameters for the table are:
@ -12,7 +23,9 @@
JSFunctionSpec ScriptFunctionTable[] =
{
{"WriteLog", WriteLog, 1, 0, 0},
{"writeConsole", writeConsole, 1, 0, 0 },
{"getEntityByHandle", getEntityByHandle, 1, 0, 0 },
{"getEntityTemplate", getEntityTemplate, 1, 0, 0 },
{0, 0, 0, 0, 0},
};
@ -47,3 +60,62 @@ JSBool WriteLog(JSContext * context, JSObject * globalObject, unsigned int argc,
return JS_TRUE;
}
JSBool writeConsole( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval )
{
assert( argc >= 1 );
CStr output = g_ScriptingHost.ValueToString( argv[0] );
g_Console->InsertMessage( output );
return( JS_TRUE );
}
JSBool getEntityByHandle( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval )
{
assert( argc >= 1 );
i32 handle;
try
{
handle = g_ScriptingHost.ValueToInt( argv[0] );
}
catch( ... )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
HEntity* v = g_EntityManager.getByHandle( (u16)handle );
if( !v )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
JSObject* entity = JS_NewObject( context, &JSI_Entity::JSI_class, NULL, NULL );
JS_SetPrivate( context, entity, v );
*rval = OBJECT_TO_JSVAL( entity );
return( JS_TRUE );
}
JSBool getEntityTemplate( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval )
{
assert( argc >= 1 );
CStr templateName;
try
{
templateName = g_ScriptingHost.ValueToString( argv[0] );
}
catch( ... )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
CBaseEntity* v = g_EntityTemplateCollection.getTemplate( templateName );
if( !v )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
JSObject* baseEntity = JS_NewObject( context, &JSI_BaseEntity::JSI_class, NULL, NULL );
JS_SetPrivate( context, baseEntity, v );
*rval = OBJECT_TO_JSVAL( baseEntity );
return( JS_TRUE );
}

View File

@ -6,6 +6,10 @@
JSBool WriteLog(JSContext * context, JSObject * globalObject, unsigned int argc, jsval *argv, jsval *rval);
JSBool writeConsole( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval );
JSBool getEntityByHandle( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval );
JSBool getEntityTemplate( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval );
extern JSFunctionSpec ScriptFunctionTable[];
#endif

View File

@ -2,12 +2,16 @@
#include "ScriptingHost.h"
#include "ScriptGlue.h"
#include "CConsole.h"
#include <sstream>
#include <fstream>
#include <iostream>
#include "float.h" // <- MT: Just for _finite(), converting certain strings was causing wierd bugs.
#pragma comment (lib, "js32.lib")
extern CConsole* g_Console;
namespace
{
const int RUNTIME_MEMORY_ALLOWANCE = 16 * 1024 * 1024;
@ -76,6 +80,11 @@ ScriptingHost::~ScriptingHost()
}
}
JSContext* ScriptingHost::getContext()
{
return( m_Context );
}
void ScriptingHost::LoadScriptFromDisk(const std::string & fileName)
{
std::string script;
@ -124,6 +133,8 @@ jsval ScriptingHost::ExecuteScript(const std::string & script)
JSBool ok = JS_EvaluateScript(m_Context, m_GlobalObject, script.c_str(), (int)script.length(), "Console", 0, &rval);
if( !ok ) return( NULL );
return rval;
}
@ -223,6 +234,13 @@ void ScriptingHost::SetObjectProperty(JSObject * object, const std::string & pro
JS_SetProperty(m_Context, object, propertyName.c_str(), &value);
}
jsval ScriptingHost::GetObjectProperty( JSObject* object, const std::string& propertyName )
{
jsval vp;
JS_GetProperty( m_Context, object, propertyName.c_str(), &vp );
return( vp );
}
int ScriptingHost::ValueToInt(const jsval value)
{
int32 i = 0;
@ -264,7 +282,7 @@ double ScriptingHost::ValueToDouble(const jsval value)
JSBool ok = JS_ValueToNumber(m_Context, value, &d);
if (ok == JS_FALSE)
if (ok == JS_FALSE || !_finite( d ) )
{
throw (std::string("Convert to double failed"));
}
@ -274,6 +292,14 @@ double ScriptingHost::ValueToDouble(const jsval value)
void ScriptingHost::ErrorReporter(JSContext * context, const char * message, JSErrorReport * report)
{
g_Console->InsertMessage( "%s ( %d )", report->filename, report->lineno );
if( message )
{
g_Console->InsertMessage( message );
}
else
g_Console->InsertMessage( "No error message available" );
if (report->filename != NULL)
{
std::cout << report->filename << " (" << report->lineno << ") ";

View File

@ -49,6 +49,8 @@ public:
ScriptingHost();
~ScriptingHost();
JSContext* getContext();
void LoadScriptFromDisk(const std::string & fileName);
jsval CallFunction(const std::string & functionName, jsval * params, int numParams);
@ -65,6 +67,7 @@ public:
JSObject * CreateCustomObject(const std::string & typeName);
void SetObjectProperty(JSObject * object, const std::string & propertyName, jsval value);
jsval GetObjectProperty( JSObject* object, const std::string& propertyName );
int ValueToInt(const jsval value);
bool ValueToBool(const jsval value);

View File

@ -9,21 +9,16 @@
// automatically use namespace ..
XERCES_CPP_NAMESPACE_USE
CBaseEntity::CBaseEntity( const CBaseEntity& copy )
CBaseEntity::CBaseEntity()
{
m_actorObject = copy.m_actorObject;
m_name = copy.m_name;
m_bound_type = copy.m_bound_type;
m_speed = copy.m_speed;
m_turningRadius = copy.m_turningRadius;
m_base = NULL;
m_base.associate( this, "super" );
m_name.associate( this, "name" );
m_speed.associate( this, "speed" );
m_turningRadius.associate( this, "turningRadius" );
m_bound_circle = NULL;
m_bound_box = NULL;
if( copy.m_bound_circle )
m_bound_circle = new CBoundingCircle( 0.0f, 0.0f, copy.m_bound_circle );
if( copy.m_bound_box )
m_bound_box = new CBoundingBox( 0.0f, 0.0f, 0.0f, copy.m_bound_box );
}
CBaseEntity::~CBaseEntity()
@ -95,8 +90,6 @@ bool CBaseEntity::loadXML( CStr filename )
DOMNode *value_node= child_element->getChildNodes()->item(0);
CStr element_value=value_node ? XMLString::transcode(value_node->getNodeValue()) : "";
//m_properties[element_name] = element_value;
if( element_name == CStr( "Name" ) )
{
m_name = element_value;

View File

@ -24,32 +24,25 @@
#include "EntityProperties.h"
#include "BoundingObjects.h"
class CBaseEntity
class CBaseEntity : public IPropertyOwner
{
public:
CBaseEntity() { m_bound_circle = NULL; m_bound_box = NULL; }
CBaseEntity( const CBaseEntity& copy );
CBaseEntity();
~CBaseEntity();
// Load from XML
bool loadXML( CStr filename );
// Base stats
CObjectEntry* m_actorObject;
CStr m_name;
CProperty_CStr m_name;
CBoundingCircle* m_bound_circle;
CBoundingBox* m_bound_box;
CBoundingObject::EBoundingType m_bound_type;
float m_speed;
float m_turningRadius;
// Extended properties table
STL_HASH_MAP<CStr,CGenericProperty,CStr_hash_compare> m_properties;
CProperty_float m_speed;
CProperty_float m_turningRadius;
};
#endif

View File

@ -18,8 +18,8 @@ void CBaseEntityCollection::loadTemplates()
{
while (vfs_next_dirent(handle, &dent, ".xml") == 0)
{
CBaseEntity newTemplate;
if( newTemplate.loadXML( pathname + dent.name ) )
CBaseEntity* newTemplate = new CBaseEntity();
if( newTemplate->loadXML( pathname + dent.name ) )
{
addTemplate( newTemplate );
LOG(NORMAL, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), dent.name);
@ -35,13 +35,9 @@ void CBaseEntityCollection::loadTemplates()
LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Failed to enumerate entity template directory\n");
return;
}
// He's so annoyingly slow...
CBaseEntity* dude = getTemplate( "Prometheus Dude" );
dude->m_speed *= 10.0f;
}
void CBaseEntityCollection::addTemplate( CBaseEntity& temp )
void CBaseEntityCollection::addTemplate( CBaseEntity* temp )
{
m_templates.push_back( temp );
}
@ -49,7 +45,7 @@ void CBaseEntityCollection::addTemplate( CBaseEntity& temp )
CBaseEntity* CBaseEntityCollection::getTemplate( CStr name )
{
for( u16 t = 0; t < m_templates.size(); t++ )
if( m_templates[t].m_name == name ) return( &( m_templates[t] ) );
if( m_templates[t]->m_name == name ) return( m_templates[t] );
return( NULL );
}
@ -57,7 +53,13 @@ CBaseEntity* CBaseEntityCollection::getTemplate( CStr name )
CBaseEntity* CBaseEntityCollection::getTemplateByActor( CObjectEntry* actor )
{
for( u16 t = 0; t < m_templates.size(); t++ )
if( m_templates[t].m_actorObject == actor ) return( &( m_templates[t] ) );
if( m_templates[t]->m_actorObject == actor ) return( m_templates[t] );
return( NULL );
}
CBaseEntityCollection::~CBaseEntityCollection()
{
for( u16 t = 0; t < m_templates.size(); t++ )
delete( m_templates[t] );
}

View File

@ -28,11 +28,12 @@
class CBaseEntityCollection : public Singleton<CBaseEntityCollection>
{
std::vector<CBaseEntity> m_templates;
std::vector<CBaseEntity*> m_templates;
public:
~CBaseEntityCollection();
CBaseEntity* getTemplate( CStr entityType );
void loadTemplates();
void addTemplate( CBaseEntity& temp );
void addTemplate( CBaseEntity* temp );
CBaseEntity* getTemplateByActor( CObjectEntry* actor );
};

View File

@ -11,31 +11,72 @@
#include "Terrain.h"
#include "Collision.h"
#include "PathfindEngine.h"
CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
{
m_position = position;
m_orientation = orientation;
m_ahead.x = sin( m_orientation );
m_ahead.y = cos( m_orientation );
m_base.associate( this, "template", ( void( IPropertyOwner::* )() )&CEntity::loadBase );
m_name.associate( this, "name" );
m_speed.associate( this, "speed" );
m_turningRadius.associate( this, "turningRadius" );
m_position.associate( this, "position", ( void( IPropertyOwner::* )() )&CEntity::teleport );
m_orientation.associate( this, "orientation", ( void( IPropertyOwner::* )() )&CEntity::reorient );
// Set our parent unit and build us an actor.
m_actor = NULL;
m_bounds = NULL;
m_base = base;
loadBase();
snapToGround();
updateActorTransforms();
}
CEntity::~CEntity()
{
for( i32 i = 0; i < m_base->m_inheritors.size(); i++ )
if( m_base->m_inheritors[i] == this )
m_base->m_inheritors.erase( m_base->m_inheritors.begin() + i );
if( m_actor )
{
g_UnitMan.RemoveUnit( m_actor );
delete( m_actor );
}
if( m_bounds ) delete( m_bounds );
}
void CEntity::loadBase()
{
if( m_actor )
{
g_UnitMan.RemoveUnit( m_actor );
delete( m_actor );
}
if( m_bounds )
{
delete( m_bounds );
}
m_actor = new CUnit(m_base->m_actorObject,m_base->m_actorObject->m_Model->Clone());
// HACK: Debugging
// assert( m_base->m_name != CStr( "Waypoint" ) );
// Register the actor with the renderer.
g_UnitMan.AddUnit( m_actor );
// Set up our instance data
m_speed = m_base->m_speed;
m_turningRadius = m_base->m_turningRadius;
m_position = position;
m_orientation = orientation;
m_ahead.x = sin( orientation );
m_ahead.y = cos( orientation );
m_base->m_inheritors.push_back( this );
rebuild();
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
{
@ -45,26 +86,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
{
m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box );
}
snapToGround();
updateActorTransforms();
// Register the addresses of our native properties with the properties table
m_properties["speed"].associate( &m_speed );
m_properties["orientation"].associate( &m_orientation );
m_properties["position"].associate( &m_position );
}
CEntity::~CEntity()
{
if( m_actor )
{
g_UnitMan.RemoveUnit( m_actor );
delete( m_actor );
}
if( m_bounds ) delete( m_bounds );
}
bool isWaypoint( CEntity* e )
@ -105,6 +126,8 @@ float CEntity::getExactGroundLevel( float x, float y )
u16* heightmap = g_Terrain.GetHeightMap();
unsigned long mapsize = g_Terrain.GetVerticesPerSide();
assert( ( xi >= 0 ) && ( xi < mapsize ) && ( yi >= 0 ) && ( yi < mapsize ) );
float h00 = heightmap[yi*mapsize + xi];
float h01 = heightmap[yi*mapsize + xi + mapsize];
float h10 = heightmap[yi*mapsize + xi + 1];
@ -204,6 +227,39 @@ void CEntity::pushOrder( CEntityOrder& order )
m_orderQueue.push_back( order );
}
void CEntity::repath()
{
CVector2D destination;
if( m_orderQueue.empty() ) return;
while( !m_orderQueue.empty() &&
( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
{
destination = m_orderQueue.front().m_data[0].location;
m_orderQueue.pop_front();
}
g_Pathfinder.requestPath( me, destination );
}
void CEntity::reorient()
{
m_ahead.x = sin( m_orientation );
m_ahead.y = cos( m_orientation );
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
updateActorTransforms();
}
void CEntity::teleport()
{
snapToGround();
updateActorTransforms();
m_bounds->setPosition( m_position.X, m_position.Z );
repath();
}
void CEntity::render()
{
// Rich! Help! ;)

View File

@ -47,29 +47,23 @@
class CEntityManager;
class CEntity
class CEntity : public IPropertyOwner
{
friend class CEntityManager;
private:
// Intrinsic properties
public:
CStr m_name;
float m_speed;
float m_turningRadius;
CVector3D m_position;
// Intrinsic properties
CProperty_CStr m_name;
CProperty_float m_speed;
CProperty_float m_turningRadius;
CProperty_CVector3D m_position;
CBoundingObject* m_bounds;
float m_targetorientation;
CVector2D m_ahead;
float m_orientation;
CBaseEntity* m_base;
CProperty_float m_orientation;
CUnit* m_actor;
std::deque<CEntityOrder> m_orderQueue;
// Extended properties table
STL_HASH_MAP<CStr,CGenericProperty,CStr_hash_compare> m_properties;
private:
CEntity( CBaseEntity* base, CVector3D position, float orientation );
@ -88,6 +82,12 @@ public:
void render();
float getExactGroundLevel( float x, float y );
void snapToGround();
void repath();
void loadBase();
void reorient();
void teleport(); // Fixes things if the position is changed by something externally.
void pushOrder( CEntityOrder& order );
};

View File

@ -34,6 +34,12 @@ HEntity CEntityManager::create( CStr templatename, CVector3D position, float ori
return( create( templateobj, position, orientation ) );
}
HEntity* CEntityManager::getByHandle( u16 index )
{
if( index >= MAX_HANDLES ) return( NULL );
if( !m_entities[index].m_refcount ) return( NULL );
return( new HEntity( index ) );
}
std::vector<HEntity>* CEntityManager::matches( EntityPredicate predicate )
{
std::vector<HEntity>* matchlist = new std::vector<HEntity>;

View File

@ -42,10 +42,11 @@ public:
~CEntityManager();
HEntity create( CBaseEntity* base, CVector3D position, float orientation );
HEntity create( CStr templatename, CVector3D position, float orientation );
HEntity* getByHandle( u16 index );
void kill( HEntity ent );
void updateAll( float timestep );
void dispatchAll( CMessage* msg );
void renderAll(); // TODO MT: What's the correct way to hook this up to the renderer?
void renderAll();
std::vector<HEntity>* matches( EntityPredicate predicate );
std::vector<HEntity>* getActive();
static inline bool extant() // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped.

View File

@ -1,621 +1,368 @@
#include "precompiled.h"
#include "EntityProperties.h"
#include "BaseEntityCollection.h"
#include "scripting/JSInterface_BaseEntity.h"
#include <cassert>
CGenericProperty::CGenericProperty()
void CProperty::associate( IPropertyOwner* owner, const CStr& name )
{
m_type = PROP_INTEGER;
m_integer = 0;
m_owner = owner;
owner->m_properties[name] = this;
m_updateFn = NULL;
}
CGenericProperty::~CGenericProperty()
void CProperty::associate( IPropertyOwner* owner, const CStr& name, void (IPropertyOwner::*updateFn)() )
{
releaseData();
m_owner = owner;
owner->m_properties[name] = this;
m_updateFn = updateFn;
}
void CGenericProperty::releaseData()
CProperty& CProperty::operator=( jsval value )
{
switch( m_type & ~PROP_TYPELOCKED )
{
case PROP_STRING:
delete( m_string ); break;
case PROP_VECTOR:
delete( m_vector ); break;
default:
break;
}
}
CGenericProperty::operator i32()
{
return( toInteger() );
}
CGenericProperty::operator float()
{
return( toFloat() );
}
CGenericProperty::operator CStr()
{
return( toString() );
}
CGenericProperty::operator CVector3D()
{
return( toVector() );
}
CGenericProperty::operator void *()
{
return( toVoid() );
}
CGenericProperty& CGenericProperty::operator=( int32_t value )
{
if( m_type & PROP_TYPELOCKED )
{
fromInteger( value );
}
else
{
releaseData();
m_type = PROP_INTEGER;
m_integer = value;
}
set( value );
return( *this );
}
CGenericProperty& CGenericProperty::operator=( float value )
CProperty_i32::CProperty_i32()
{
if( m_type & PROP_TYPELOCKED )
{
fromFloat( value );
}
else
{
releaseData();
m_type = PROP_FLOAT;
m_float = value;
}
modifier = NULL;
}
CProperty_i32::~CProperty_i32()
{
if( modifier )
delete( modifier );
}
inline CProperty_i32& CProperty_i32::operator =( i32 value )
{
if( !modifier )
modifier = new SProperty_NumericModifier();
*modifier = (float)value;
data = value;
return( *this );
}
CGenericProperty& CGenericProperty::operator=( CStr& value )
void CProperty_i32::set( jsval value )
{
if( m_type & PROP_TYPELOCKED )
if( !modifier )
modifier = new SProperty_NumericModifier();
try
{
fromString( value );
*modifier = (float)g_ScriptingHost.ValueToInt( value );
}
else
catch( ... )
{
releaseData();
m_type = PROP_STRING;
m_string = new CStr( value );
*modifier = 0;
}
}
bool CProperty_i32::rebuild( CProperty* parent, bool triggerFn )
{
CProperty_i32* _parent = (CProperty_i32*)parent;
i32 newvalue = 0;
if( _parent )
newvalue = *_parent;
if( modifier )
{
newvalue *= modifier->multiplicative;
newvalue += modifier->additive;
}
if( data == newvalue )
return( false ); // No change.
data = newvalue;
if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)();
return( true );
}
inline CProperty_i32::operator i32()
{
return( data );
}
CProperty_i32::operator jsval()
{
return( INT_TO_JSVAL( data ) );
}
CProperty_float::CProperty_float()
{
modifier = NULL;
}
CProperty_float::~CProperty_float()
{
if( modifier )
modifier = NULL;
}
CProperty_float& CProperty_float::operator =( const float& value )
{
if( !modifier )
modifier = new SProperty_NumericModifier();
*modifier = value;
data = value;
return( *this );
}
CGenericProperty& CGenericProperty::operator=( CVector3D& value )
void CProperty_float::set( const jsval value )
{
if( m_type & PROP_TYPELOCKED )
if( !modifier )
modifier = new SProperty_NumericModifier();
try
{
fromVector( value );
*modifier = (float)g_ScriptingHost.ValueToDouble( value );
}
else
catch( ... )
{
releaseData();
m_type = PROP_VECTOR;
m_vector = new CVector3D( value );
*modifier = 0.0f;
}
}
bool CProperty_float::rebuild( CProperty* parent, bool triggerFn )
{
CProperty_float* _parent = (CProperty_float*)parent;
float newvalue = 0;
if( _parent )
newvalue = *_parent;
if( modifier )
{
newvalue *= modifier->multiplicative;
newvalue += modifier->additive;
}
if( data == newvalue )
return( false ); // No change.
data = newvalue;
if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)();
return( true );
}
CProperty_float::operator float()
{
return( data );
}
CProperty_float::operator jsval()
{
return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), (jsdouble)data ) ) );
}
CProperty_float::operator bool()
{
return( data );
}
float CProperty_float::operator+( float value )
{
return( data + value );
}
float CProperty_float::operator-( float value )
{
return( data - value );
}
float CProperty_float::operator*( float value )
{
return( data * value );
}
float CProperty_float::operator/( float value )
{
return( data / value );
}
bool CProperty_float::operator<( float value )
{
return( data < value );
}
bool CProperty_float::operator>( float value )
{
return( data > value );
}
bool CProperty_float::operator==( float value )
{
return( data == value );
}
CProperty_CStr::CProperty_CStr()
{
modifier = NULL;
}
CProperty_CStr::~CProperty_CStr()
{
if( modifier )
delete( modifier );
}
CProperty_CStr& CProperty_CStr::operator=( const CStr& value )
{
if( !modifier )
modifier = new SProperty_StringModifier();
*modifier = value;
m_String = value;
return( *this );
}
CGenericProperty& CGenericProperty::operator =( void* value )
void CProperty_CStr::set( jsval value )
{
if( m_type & PROP_TYPELOCKED )
if( !modifier )
modifier = new SProperty_StringModifier();
try
{
fromVoid( value );
*modifier = g_ScriptingHost.ValueToString( value );
}
else
catch( ... )
{
releaseData();
m_type = PROP_PTR;
m_ptr = value;
*modifier = CStr();
m_String.clear();
}
}
bool CProperty_CStr::rebuild( CProperty* parent, bool triggerFn )
{
CProperty_CStr* _parent = (CProperty_CStr*)parent;
CStr newvalue = "";
if( _parent )
newvalue = *_parent;
if( modifier )
newvalue = modifier->replacement;
if( *this == newvalue )
return( false ); // No change.
m_String = newvalue;
if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)();
return( true );
}
CProperty_CStr::operator jsval()
{
return( STRING_TO_JSVAL( JS_NewStringCopyZ( g_ScriptingHost.getContext(), m_String.c_str() ) ) );
}
CProperty_CVector3D& CProperty_CVector3D::operator =( const CVector3D& value )
{
*( (CVector3D*)this ) = value;
return( *this );
}
void CGenericProperty::associate( i32* value )
void CProperty_CVector3D::set( jsval value )
{
i32 current = toInteger();
releaseData();
m_type = (EPropTypes)( PROP_INTEGER | PROP_INTRINSIC | PROP_TYPELOCKED );
m_integerptr = value;
//*m_integerptr = current;
}
void CGenericProperty::associate( float* value )
{
float current = toFloat();
releaseData();
m_type = (EPropTypes)( PROP_FLOAT | PROP_INTRINSIC | PROP_TYPELOCKED );
m_floatptr = value;
//*m_floatptr = current;
}
void CGenericProperty::associate( CStr* value )
{
CStr current = toString();
releaseData();
m_type = (EPropTypes)( PROP_STRING | PROP_VECTOR | PROP_TYPELOCKED );
m_string = value;
//*m_string = current;
}
void CGenericProperty::associate( CVector3D* value )
{
CVector3D current = toVector();
releaseData();
m_type = (EPropTypes)( PROP_VECTOR | PROP_INTRINSIC | PROP_TYPELOCKED );
m_vector = value;
//*value = current;
}
void CGenericProperty::typelock( EPropTypes type )
{
if( m_type & PROP_INTRINSIC ) return;
switch( type )
JSObject* vector3d = JSVAL_TO_OBJECT( value );
if( !JSVAL_IS_OBJECT( value ) || ( JS_GetClass( vector3d ) != &JSI_Vector3D::JSI_class ) )
{
case PROP_INTEGER:
X = 0.0f; Y = 0.0f; Z = 0.0f;
}
else
{
CVector3D* copy = ( (JSI_Vector3D::Vector3D_Info*)JS_GetPrivate( g_ScriptingHost.getContext(), vector3d ) )->vector;
X = copy->X;
Y = copy->Y;
Z = copy->Z;
}
}
bool CProperty_CVector3D::rebuild( CProperty* parent, bool triggerFn )
{
if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)();
return( false ); // Vector properties aren't inheritable.
}
CProperty_CVector3D::operator jsval()
{
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( this, m_owner, m_updateFn ) );
return( OBJECT_TO_JSVAL( vector3d ) );
}
CProperty_CBaseEntityPtr& CProperty_CBaseEntityPtr::operator =( CBaseEntity* value )
{
data = value;
return( *this );
}
void CProperty_CBaseEntityPtr::set( jsval value )
{
JSObject* baseEntity = JSVAL_TO_OBJECT( value );
if( JSVAL_IS_OBJECT( value ) && ( JS_GetClass( baseEntity ) == &JSI_BaseEntity::JSI_class ) )
data = (CBaseEntity*)JS_GetPrivate( g_ScriptingHost.getContext(), baseEntity );
}
bool CProperty_CBaseEntityPtr::rebuild( CProperty* parent, bool triggerFn )
{
if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)();
return( false ); // CBaseEntity* properties aren't inheritable.
}
CProperty_CBaseEntityPtr::operator jsval()
{
JSObject* baseEntity = JS_NewObject( g_ScriptingHost.getContext(), &JSI_BaseEntity::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), baseEntity, data );
return( OBJECT_TO_JSVAL( baseEntity ) );
}
CProperty_CBaseEntityPtr::operator bool()
{
return( data != NULL );
}
CProperty_CBaseEntityPtr::operator CBaseEntity*()
{
return( data );
}
CBaseEntity& CProperty_CBaseEntityPtr::operator *() const
{
return( *data );
}
CBaseEntity* CProperty_CBaseEntityPtr::operator ->() const
{
return( data );
}
void IPropertyOwner::rebuild( CStr propertyName )
{
CProperty* thisProperty = m_properties[propertyName];
CProperty* baseProperty = NULL;
if( m_base )
{
if( m_base->m_properties.find( propertyName ) != m_base->m_properties.end() )
baseProperty = m_base->m_properties[propertyName];
}
if( thisProperty->rebuild( baseProperty ) )
{
std::vector<IPropertyOwner*>::iterator it;
for( it = m_inheritors.begin(); it != m_inheritors.end(); it++ )
(*it)->rebuild( propertyName );
}
}
void IPropertyOwner::rebuild()
{
STL_HASH_MAP<CStr,CProperty*,CStr_hash_compare>::iterator property;
if( m_base )
{
for( property = m_properties.begin(); property != m_properties.end(); property++ )
{
i32 current = toInteger();
releaseData();
m_integer = current;
CProperty* baseProperty = NULL;
if( m_base->m_properties.find( property->first ) != m_base->m_properties.end() )
baseProperty = m_base->m_properties[property->first];
(property->second)->rebuild( baseProperty, false );
}
break;
case PROP_FLOAT:
{
float current = toFloat();
releaseData();
m_float = current;
}
break;
case PROP_STRING:
{
CStr* current = new CStr( toString() );
releaseData();
m_string = current;
}
break;
case PROP_VECTOR:
{
CVector3D* current = new CVector3D( toVector() );
releaseData();
m_vector = current;
}
break;
case PROP_PTR:
{
void* current = toVoid();
releaseData();
m_ptr = current;
}
break;
default:
return;
}
m_type = (EPropTypes)( type | PROP_TYPELOCKED );
}
void CGenericProperty::typeloose()
{
if( m_type & PROP_INTRINSIC ) return;
m_type = (EPropTypes)( m_type & ~PROP_TYPELOCKED );
}
i32& CGenericProperty::asInteger()
{
assert( ( m_type & PROP_STRIPFLAGS ) == PROP_INTEGER );
if( m_type & PROP_INTRINSIC )
return( *m_integerptr );
return( m_integer );
}
float& CGenericProperty::asFloat()
{
assert( ( m_type & PROP_STRIPFLAGS ) == PROP_FLOAT );
if( m_type & PROP_INTRINSIC )
return( *m_floatptr );
return( m_float );
}
CStr& CGenericProperty::asString()
{
assert( ( m_type & PROP_STRIPFLAGS ) == PROP_STRING );
return( *m_string );
}
CVector3D& CGenericProperty::asVector()
{
assert( ( m_type & PROP_STRIPFLAGS ) == PROP_VECTOR );
return( *m_vector );
}
i32 CGenericProperty::toInteger()
{
switch( m_type & PROP_STRIPFLAGS )
else
{
case PROP_INTEGER:
return( asInteger() );
case PROP_FLOAT:
return( (i32)asFloat() );
case PROP_STRING:
case PROP_STRING_INTRINSIC:
return( (i32)( asString().ToInt() ) );
case PROP_VECTOR:
case PROP_VECTOR_INTRINSIC:
case PROP_PTR:
return( 0 );
default:
assert( 0 && "Invalid property type" );
for( property = m_properties.begin(); property != m_properties.end(); property++ )
(property->second)->rebuild( NULL, false );
}
return( 0 );
std::vector<IPropertyOwner*>::iterator it;
for( it = m_inheritors.begin(); it != m_inheritors.end(); it++ )
(*it)->rebuild();
}
float CGenericProperty::toFloat()
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
return( (float)asInteger() );
case PROP_FLOAT:
return( asFloat() );
case PROP_STRING:
case PROP_STRING_INTRINSIC:
return( asString().ToFloat() );
case PROP_VECTOR:
case PROP_VECTOR_INTRINSIC:
case PROP_PTR:
return( 0.0f );
default:
assert( 0 && "Invalid property type" );
}
return( 0.0f );
}
CStr CGenericProperty::toString()
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
return( CStr( asInteger() ) );
case PROP_FLOAT:
return( CStr( asFloat() ) );
case PROP_STRING:
return( CStr( asString() ) );
case PROP_VECTOR:
{
char buffer[256];
snprintf( buffer, 250, "{ %f, %f, %f }", asVector().X, asVector().Y, asVector().Z );
return( CStr( buffer ) );
}
case PROP_PTR:
return CStr();
default:
assert( 0 && "Invalid property type" );
}
return CStr();
}
CVector3D CGenericProperty::toVector()
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_VECTOR:
return( CVector3D( asVector() ) );
case PROP_INTEGER:
case PROP_FLOAT:
case PROP_STRING:
case PROP_PTR:
return CVector3D();
default:
assert( 0 && "Invalid property type" );
}
return CVector3D();
}
void* CGenericProperty::toVoid()
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_PTR:
return( m_ptr );
case PROP_INTEGER:
case PROP_INTEGER_INTRINSIC:
case PROP_FLOAT:
case PROP_FLOAT_INTRINSIC:
case PROP_STRING:
case PROP_STRING_INTRINSIC:
case PROP_VECTOR:
case PROP_VECTOR_INTRINSIC:
return( NULL );
default:
assert( 0 && "Invalid property type" );
}
return( NULL );
}
void CGenericProperty::fromInteger( i32 value )
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
asInteger() = value; return;
case PROP_FLOAT:
asFloat() = (float)value; return;
case PROP_STRING:
asString() = value; return;
case PROP_VECTOR:
asVector() = CVector3D(); return;
case PROP_PTR:
m_ptr = NULL; return;
default:
assert( 0 && "Invalid property type" );
}
}
void CGenericProperty::fromFloat( float value )
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
asInteger() = (i32)value; return;
case PROP_FLOAT:
asFloat() = value; return;
case PROP_STRING:
asString() = value; return;
case PROP_VECTOR:
asVector() = CVector3D(); return;
case PROP_PTR:
m_ptr = NULL; return;
default:
assert( 0 && "Invalid property type" );
}
}
void CGenericProperty::fromString( CStr& value )
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
asInteger() = value.ToInt(); return;
case PROP_FLOAT:
asFloat() = value.ToFloat(); return;
case PROP_STRING:
asString() = value; return;
case PROP_VECTOR:
asVector() = CVector3D(); return;
case PROP_PTR:
m_ptr = NULL; return;
default:
assert( 0 && "Invalid property type" );
}
}
void CGenericProperty::fromVector( CVector3D& value )
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
asInteger() = 0; return;
case PROP_FLOAT:
asFloat() = 0.0f; return;
case PROP_STRING:
{
char buffer[256];
snprintf( buffer, 250, "{ %f, %f, %f }", value.X, value.Y, value.Z );
asString() = CStr( buffer );
}
return;
case PROP_VECTOR:
asVector() = CVector3D( value ); return;
case PROP_PTR:
m_ptr = NULL; return;
default:
assert( 0 && "Invalid property type" );
}
}
void CGenericProperty::fromVoid( void* value )
{
switch( m_type & PROP_STRIPFLAGS )
{
case PROP_INTEGER:
asInteger() = 0; return;
case PROP_FLOAT:
asFloat() = 0.0f; return;
case PROP_STRING:
asString() = CStr(); return;
case PROP_VECTOR:
asVector() = CVector3D(); return;
case PROP_PTR:
m_ptr = value; return;
default:
assert( 0 && "Invalid property type" );
}
}
/*
Here lies the old version of CGenericProperty. Will remove it when I know the new one works.
CGenericProperty::CGenericProperty()
{
m_type = PROP_INTEGER;
m_integer = 0;
}
CGenericProperty::CGenericProperty( i32 value )
{
m_type = PROP_INTEGER;
m_integer = value;
}
CGenericProperty::CGenericProperty( float value )
{
m_type = PROP_FLOAT;
m_float = value;
}
CGenericProperty::CGenericProperty( CStr& value )
{
m_type = PROP_STRING;
m_string = new CStr( value );
}
CGenericProperty::CGenericProperty( CVector3D& value )
{
m_type = PROP_VECTOR;
m_vector = new CVector3D( value );
}
CGenericProperty::CGenericProperty( void* value )
{
m_type = PROP_PTR;
m_ptr = value;
}
CGenericProperty::CGenericProperty( i32* value )
{
m_type = PROP_INTEGER_INTRINSIC;
m_integerptr = value;
}
CGenericProperty::CGenericProperty( float* value )
{
m_type = PROP_FLOAT_INTRINSIC;
m_floatptr = value;
}
CGenericProperty::CGenericProperty( CStr* value )
{
m_type = PROP_STRING_INTRINSIC;
m_string = value;
}
CGenericProperty::CGenericProperty( CVector3D* value )
{
m_type = PROP_VECTOR_INTRINSIC;
m_vector = value;
}
CGenericProperty::~CGenericProperty()
{
switch( m_type )
{
case PROP_STRING:
delete( m_string ); break;
case PROP_VECTOR:
delete( m_vector ); break;
default:
break;
}
}
CGenericProperty::operator CStr&()
{
char working[64];
switch( m_type )
{
case PROP_STRING:
case PROP_STRING_INTRINSIC:
return( *m_string );
case PROP_VECTOR:
case PROP_VECTOR_INTRINSIC:
snprintf( working, 63, "{ %f, %f, %f }", m_vector->X, m_vector->Y, m_vector->Z );
working[63] = 0;
return( CStr( working ) );
case PROP_INTEGER:
return( CStr( m_integer ) );
case PROP_INTEGER_INTRINSIC:
return( CStr( *m_integerptr ) );
case PROP_FLOAT:
return( CStr( m_float ) );
case PROP_FLOAT_INTRINSIC:
return( CStr( *m_floatptr ) );
default:
return CStr();
}
}
CGenericProperty::operator CVector3D()
{
switch( m_type )
{
case PROP_VECTOR:
return( *m_vector );
default:
return CVector3D();
}
}
CGenericProperty::operator i32()
{
switch( m_type )
{
case PROP_INTEGER:
return( m_integer );
case PROP_INTEGER_INTRINSIC:
return( *m_integerptr );
case PROP_FLOAT:
return( (i32)m_float );
case PROP_FLOAT_INTRINSIC:
return( (i32)*m_floatptr );
case PROP_STRING:
return( m_string->ToInt() );
default:
return( 0 );
}
}
CGenericProperty::operator float()
{
switch( m_type )
{
case PROP_INTEGER:
return( (float)m_integer );
case PROP_INTEGER_INTRINSIC:
return( (float)*m_integerptr );
case PROP_FLOAT:
return( m_float );
case PROP_FLOAT_INTRINSIC:
return( *m_floatptr );
case PROP_STRING:
return( m_string->ToFloat() );
default:
return( 0.0f );
}
}
CGenericProperty::operator void*()
{
switch( m_type )
{
case PROP_PTR:
return( m_ptr );
default:
return( NULL );
}
}
*/

View File

@ -17,6 +17,9 @@
#include "CStr.h"
#include "Vector3D.h"
#include "scripting/ScriptingHost.h"
#include "scripting/JSInterface_Entity.h"
#include "scripting/JSInterface_Vector3D.h"
#ifndef __GNUC__
@ -35,89 +38,126 @@
#endif
class CGenericProperty
class IPropertyOwner;
class CBaseEntity;
class CProperty;
struct SProperty_NumericModifier;
struct SProperty_StringModifier;
class CProperty
{
protected:
IPropertyOwner* m_owner;
void (IPropertyOwner::*m_updateFn)();
virtual void set( const jsval value ) = 0;
public:
CProperty& operator=( const jsval value );
virtual operator jsval() = 0;
virtual bool rebuild( CProperty* parent, bool triggerFn = true ) = 0; // Returns true if the rebuild changed the value of this property.
void associate( IPropertyOwner* owner, const CStr& name );
void associate( IPropertyOwner* owner, const CStr& name, void (IPropertyOwner::*updateFn)() );
};
class CProperty_i32 : public CProperty
{
i32 data;
SProperty_NumericModifier* modifier;
public:
CProperty_i32();
~CProperty_i32();
void set( const jsval value );
operator jsval();
bool rebuild( CProperty* parent, bool triggerFn = true );
CProperty_i32& operator=( const i32 value );
operator i32();
};
class CProperty_float : public CProperty
{
float data;
SProperty_NumericModifier* modifier;
public:
CProperty_float();
~CProperty_float();
void set( const jsval value );
operator jsval();
bool rebuild( CProperty* parent, bool triggerFn = true );
CProperty_float& operator=( const float& value );
operator float();
operator bool();
float operator+( float value );
float operator-( float value );
float operator*( float value );
float operator/( float value );
bool operator<( float value );
bool operator>( float value );
bool operator==( float value );
};
class CProperty_CStr : public CProperty, public CStr
{
SProperty_StringModifier* modifier;
public:
CProperty_CStr();
~CProperty_CStr();
void set( const jsval value );
operator jsval();
bool rebuild( CProperty* parent, bool triggerFn = true );
CProperty_CStr& operator=( const CStr& value );
};
class CProperty_CVector3D : public CProperty, public CVector3D
{
public:
enum EPropTypes
{
PROP_INTRINSIC = 256,
PROP_TYPELOCKED = 512,
PROP_STRIPFLAGS = 255,
PROP_INTEGER = 0,
PROP_FLOAT,
PROP_STRING,
PROP_VECTOR,
PROP_PTR,
PROP_INTEGER_INTRINSIC = PROP_INTEGER | PROP_INTRINSIC,
PROP_FLOAT_INTRINSIC = PROP_FLOAT | PROP_INTRINSIC,
PROP_STRING_INTRINSIC = PROP_STRING | PROP_INTRINSIC,
PROP_VECTOR_INTRINSIC = PROP_VECTOR | PROP_INTRINSIC
};
EPropTypes m_type;
private:
union
{
i32 m_integer;
i32* m_integerptr;
float m_float;
float* m_floatptr;
CStr* m_string;
CVector3D* m_vector;
void* m_ptr;
};
void set( const jsval value );
operator jsval();
bool rebuild( CProperty* parent, bool triggerFn = true );
CProperty_CVector3D& operator=( const CVector3D& value );
};
class CProperty_CBaseEntityPtr : public CProperty
{
CBaseEntity* data;
public:
CGenericProperty(); // Create an integer property containing 0.
~CGenericProperty();
void releaseData();
void set( const jsval value );
operator jsval();
bool rebuild( CProperty* parent, bool triggerFn = true );
operator CBaseEntity*();
operator bool();
CBaseEntity& operator*() const;
CBaseEntity* operator->() const;
CProperty_CBaseEntityPtr& operator=( CBaseEntity* value );
};
// Associator functions: Links the property with the specified engine variable.
void associate( i32* value );
void associate( float* value );
void associate( CStr* value );
void associate( CVector3D* value );
// e.g. Entities and their templates.
class IPropertyOwner
{
public:
CProperty_CBaseEntityPtr m_base;
STL_HASH_MAP<CStr,CProperty*,CStr_hash_compare> m_properties;
std::vector<IPropertyOwner*> m_inheritors;
void rebuild( CStr propName ); // Recursively rebuild just the named property over the inheritance tree.
void rebuild(); // Recursively rebuild everything over the inheritance tree.
};
// Getter functions: Attempts to convert the property to the given type.
operator i32(); // Convert to an integer if possible (integer, float, some strings), otherwise returns 0.
operator float(); // Convert to a float if possible (integer, float, some strings), otherwise returns 0.0f.
operator CStr(); // Convert to a string if possible (all except generic pointer), otherwise returns CStr().
operator CVector3D(); // If this property is a vector, returns that vector, otherwise returns CVector3D().
operator void*(); // If this property is a generic pointer, returns that pointer, otherwise returns NULL.
struct SProperty_NumericModifier
{
float multiplicative;
float additive;
void operator=( float value )
{
multiplicative = 0.0f;
additive = value;
}
};
// Setter functions: If this is a typelocked property, attempts to convert the given data
// into the appropriate type, otherwise setting the associated value to 0, 0.0f, CStr() or CVector3D().
// If this property is typeloose, converts this property into one of the same type
// as the given value, then stores that value in this property.
CGenericProperty& operator=( i32 value );
CGenericProperty& operator=( float value );
CGenericProperty& operator=( CStr& value );
CGenericProperty& operator=( CVector3D& value );
CGenericProperty& operator=( void* value ); // Be careful with this one. A lot of things will cast to void*.
// Especially pointers you meant to associate().
// Typelock functions. Use these when you want to make sure the property has the given type.
void typelock( EPropTypes type );
void typeloose();
private:
// resolve-as functions. References the data, whereever it is.
i32& asInteger();
float& asFloat();
CStr& asString();
CVector3D& asVector();
// to functions. Convert whatever this is now to the chosen type.
i32 toInteger();
float toFloat();
CStr toString();
CVector3D toVector();
void* toVoid();
// from functions. Convert the given value to whatever type this is now.
void fromInteger( i32 value );
void fromFloat( float value );
void fromString( CStr& value );
void fromVector( CVector3D& value );
void fromVoid( void* value );
struct SProperty_StringModifier
{
CStr replacement;
void operator=( const CStr& value )
{
replacement = value;
}
};
#endif

View File

@ -16,12 +16,18 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
float len = delta.length();
// janwas added EVIL HACK: BoundsChecker complains about NaNs
// in atan2 and fabs => delta must be 0 somewhere.
// currently skip over all math code that would break.
// what's the real solution?
if(len == 0.0f)
goto small_delta;
// ... 'Are we there yet?' ...
if( len < 0.1f )
{
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
{
repath();
}
else
m_orderQueue.pop_front();
return( false );
}
// Curve smoothing.
// Here there be trig.
@ -44,7 +50,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
{
m_targetorientation = atan2( delta.x, delta.y );
float deltatheta = m_targetorientation - m_orientation;
float deltatheta = m_targetorientation - (float)m_orientation;
while( deltatheta > PI ) deltatheta -= 2 * PI;
while( deltatheta < -PI ) deltatheta += 2 * PI;
@ -53,10 +59,10 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep;
if( deltatheta > 0 )
{
m_orientation += MIN( deltatheta, maxTurningSpeed );
m_orientation = m_orientation + MIN( deltatheta, maxTurningSpeed );
}
else
m_orientation += MAX( deltatheta, -maxTurningSpeed );
m_orientation = m_orientation + MAX( deltatheta, -maxTurningSpeed );
m_ahead.x = sin( m_orientation );
m_ahead.y = cos( m_orientation );
@ -68,33 +74,11 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
}
}
if( len < 0.1f )
{
small_delta:
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
{
// Repath.
CVector2D destination;
while( !m_orderQueue.empty() &&
( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
{
destination = m_orderQueue.front().m_data[0].location;
m_orderQueue.pop_front();
}
g_Pathfinder.requestPath( me, destination );
}
else
m_orderQueue.pop_front();
return( false );
}
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
float scale = timestep * m_speed;
float scale = m_speed * timestep;
if( scale > len )
scale = len;

View File

@ -5,8 +5,6 @@
sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject )
{
from = _from; to = _to;
assert( from.length() > 0.01f );
assert( to.length() > 0.01f );
entity = _entity; destinationCollisionObject = _destinationCollisionObject;
leftPre = NULL; leftPost = NULL;
@ -46,7 +44,7 @@ bool sparsePathTree::slice()
float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
if( turningRadius < entity->m_turningRadius ) turningRadius = entity->m_turningRadius;
if( entity->m_turningRadius > turningRadius ) turningRadius = entity->m_turningRadius;
// Too close, an impossible turn
if( r.distance < turningRadius )

View File

@ -0,0 +1,68 @@
#include "precompiled.h"
#include "JSInterface_BaseEntity.h"
#include "BaseEntity.h"
#include "EntityHandles.h"
JSClass JSI_BaseEntity::JSI_class = {
"EntityTemplate", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSI_BaseEntity::getProperty, JSI_BaseEntity::setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, NULL,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_BaseEntity::JSI_props[] =
{
{ 0 }
};
JSFunctionSpec JSI_BaseEntity::JSI_methods[] =
{
{ "toString", JSI_BaseEntity::toString, 0, 0, 0 },
{ 0 }
};
JSBool JSI_BaseEntity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj );
CStr propName = g_ScriptingHost.ValueToString( id );
if( e->m_properties.find( propName ) != e->m_properties.end() )
{
*vp = *(e->m_properties[propName]);
return( JS_TRUE );
}
return( JS_TRUE );
}
JSBool JSI_BaseEntity::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj );
CStr propName = g_ScriptingHost.ValueToString( id );
if( e->m_properties.find( propName ) != e->m_properties.end() )
{
*(e->m_properties[propName]) = *vp;
e->rebuild( propName );
return( JS_TRUE );
}
return( JS_TRUE );
}
void JSI_BaseEntity::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL );
}
JSBool JSI_BaseEntity::toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj );
char buffer[256];
snprintf( buffer, 256, "[object EntityTemplate: %s]", (const TCHAR*)e->m_name );
buffer[255] = 0;
*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
return( JS_TRUE );
}

View File

@ -0,0 +1,30 @@
// JSInterface_BaseEntity.h
//
// Last modified: 08 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
//
// An interface between CBaseEntity and the JavaScript class EntityTemplate
//
// Usage: Used when manipulating objects of class 'EntityTemplate' in JavaScript.
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#include "scripting/ScriptingHost.h"
#ifndef JSI_BASEENTITY_INCLUDED
#define JSI_BASEENTITY_INCLUDED
namespace JSI_BaseEntity
{
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool addProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool delProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
void finalize( JSContext* cx, JSObject* obj );
void init();
};
#endif

View File

@ -0,0 +1,136 @@
#include "precompiled.h"
#include "JSInterface_Entity.h"
#include "scripting/JSInterface_BaseEntity.h"
#include "scripting/JSInterface_Vector3D.h"
#include "EntityHandles.h"
#include "Entity.h"
#include "EntityManager.h"
#include "BaseEntityCollection.h"
#include "CConsole.h"
JSClass JSI_Entity::JSI_class = {
"Entity", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSI_Entity::getProperty, JSI_Entity::setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JSI_Entity::finalize,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_Entity::JSI_props[] =
{
{ 0 }
};
JSFunctionSpec JSI_Entity::JSI_methods[] =
{
{ "toString", JSI_Entity::toString, 0, 0, 0 },
{ 0 }
};
JSBool JSI_Entity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
HEntity* e = (HEntity*)JS_GetPrivate( cx, obj );
if( !e )
{
*vp = JSVAL_NULL;
return( JS_TRUE );
}
CStr propName = g_ScriptingHost.ValueToString( id );
if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() )
{
*vp = *((*e)->m_properties[propName]);
return( JS_TRUE );
}
return( JS_TRUE );
}
JSBool JSI_Entity::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
HEntity* e = (HEntity*)JS_GetPrivate( cx, obj );
CStr propName = g_ScriptingHost.ValueToString( id );
if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() )
{
*((*e)->m_properties[propName]) = *vp;
(*e)->rebuild( propName );
return( JS_TRUE );
}
return( JS_TRUE );
}
JSBool JSI_Entity::construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
{
assert( argc >= 2 );
CBaseEntity* baseEntity;
CVector3D position;
float orientation = 0.0f;
JSObject* jsBaseEntity = JSVAL_TO_OBJECT( argv[0] );
if( JSVAL_IS_OBJECT( argv[0] ) && ( JS_GetClass( jsBaseEntity ) == &JSI_BaseEntity::JSI_class ) )
{
baseEntity = (CBaseEntity*)JS_GetPrivate( cx, jsBaseEntity );
}
else
{
CStr templateName;
try
{
templateName = g_ScriptingHost.ValueToString( argv[0] );
}
catch( ... )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
baseEntity = g_EntityTemplateCollection.getTemplate( templateName );
}
if( !baseEntity )
{
*rval = JSVAL_NULL;
return( JS_TRUE );
}
JSObject* jsVector3D = JSVAL_TO_OBJECT( argv[1] );
if( JSVAL_IS_OBJECT( argv[1] ) && ( JS_GetClass( jsVector3D ) == &JSI_Vector3D::JSI_class ) )
position = *( ( (JSI_Vector3D::Vector3D_Info*)JS_GetPrivate( cx, jsVector3D ) )->vector );
if( argc >= 3 )
{
try
{
orientation = (float)g_ScriptingHost.ValueToDouble( argv[2] );
}
catch( ... )
{
orientation = 0.0f;
}
}
HEntity* handle = new HEntity( g_EntityManager.create( baseEntity, position, orientation ) );
(*handle)->dispatch( &CMessage( CMessage::EMSG_INIT ) );
JSObject* entity = JS_NewObject( cx, &JSI_Entity::JSI_class, NULL, NULL );
JS_SetPrivate( cx, entity, handle );
*rval = OBJECT_TO_JSVAL( entity );
return( JS_TRUE );
}
void JSI_Entity::finalize( JSContext* cx, JSObject* obj )
{
delete( JS_GetPrivate( cx, obj ) );
}
void JSI_Entity::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, construct, 2, JSI_props, JSI_methods, NULL, NULL );
}
JSBool JSI_Entity::toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
HEntity* e = (HEntity*)JS_GetPrivate( cx, obj );
char buffer[256];
snprintf( buffer, 256, "[object Entity: \"%s\" (%s)]", (const TCHAR*)(*e)->m_name, (const TCHAR*)(*e)->m_base->m_name );
buffer[255] = 0;
*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
return( JS_TRUE );
}

View File

@ -0,0 +1,31 @@
// JSInterface_Entity.h
//
// Last modified: 03 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
//
// The interface layer between JavaScript code and the actual CEntity object.
//
// Usage: Used when manipulating objects of class 'Entity' in JavaScript.
//
// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
#include "scripting/ScriptingHost.h"
#ifndef JSI_ENTITY_INCLUDED
#define JSI_ENTITY_INCLUDED
namespace JSI_Entity
{
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool addProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool delProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval );
void finalize( JSContext* cx, JSObject* obj );
void init();
};
#endif

View File

@ -23,6 +23,7 @@ package.files = {
{ sourcesfromdirs("../../ps") },
-- simulation/
{ sourcesfromdirs("../../simulation") },
{ sourcesfromdirs("../../simulation/scripting") },
-- lib/
{ sourcesfromdirs(
"../../lib",
@ -34,6 +35,7 @@ package.files = {
-- maths/
{ sourcesfromdirs(
"../../maths") },
{ sourcesfromdirs( "../../maths/scripting" ) },
-- renderer/
{ sourcesfromdirs(
"../../renderer") },