#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" #include "Scheduler.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 }, { "order", JSI_Entity::orderSingle, 1, 0, 0 }, { "orderQueued", JSI_Entity::orderQueued, 1, 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 ); } CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() ) { *vp = (*e)->m_properties[propName]->tojsval(); return( JS_TRUE ); } else { // Don't show the message if we're using a function defined by the engine. JSFunctionSpec* fnSpec = JSI_Entity::JSI_methods; while( fnSpec->name ) { if( CStr8( propName ) == CStr8( fnSpec->name ) ) return( JS_TRUE ); fnSpec++; } JS_ReportError( cx, "No such property on %s: %s", CStr8((*e)->m_name).c_str(), CStr8(propName).c_str() ); return( JS_TRUE ); } } JSBool JSI_Entity::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { HEntity* e = (HEntity*)JS_GetPrivate( cx, obj ); CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() ) { (*e)->m_properties[propName]->fromjsval( *vp ); (*e)->rebuild( propName ); } else { (*e)->addProperty( propName, *vp ); } return( JS_TRUE ); } JSBool JSI_Entity::construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval ) { debug_assert( argc >= 2 ); CBaseEntity* baseEntity = NULL; CVector3D position; float orientation = 0.0f; JSObject* jsBaseEntity = JSVAL_TO_OBJECT( argv[0] ); CStrW templateName; if( !JSVAL_IS_OBJECT( argv[0] ) || !( baseEntity = CBaseEntity::GetNative( cx, jsBaseEntity ) ) ) { try { templateName = g_ScriptingHost.ValueToUCString( argv[0] ); } catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_NULL; JS_ReportError( cx, "Invalid template identifier" ); return( JS_TRUE ); } baseEntity = g_EntityTemplateCollection.getTemplate( templateName ); } if( !baseEntity ) { *rval = JSVAL_NULL; JS_ReportError( cx, "No such template: %s", CStr8(templateName).c_str() ); return( JS_TRUE ); } JSI_Vector3D::Vector3D_Info* jsVector3D = NULL; if( JSVAL_IS_OBJECT( argv[1] ) && ( jsVector3D = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( argv[1] ), &JSI_Vector3D::JSI_class, NULL ) ) ) { position = *( jsVector3D->vector ); } if( argc >= 3 ) { try { orientation = ToPrimitive( argv[2] ); } catch( PSERROR_Scripting_ConversionFailed ) { // TODO: Net-safe random for this parameter. orientation = 0.0f; } } HEntity* handle = new HEntity( g_EntityManager.create( baseEntity, position, orientation ) ); CMessage message( CMessage::EMSG_INIT ); (*handle)->dispatch( &message ); 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 ) { JSClass* DebugInfo = JS_GetClass( obj ); delete( (HEntity*)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 ); wchar_t buffer[256]; swprintf( buffer, 256, L"[object Entity: \"%ls\" (%ls)]", (*e)->m_name.c_str(), (*e)->m_base->m_name.c_str() ); buffer[255] = 0; utf16_t utfbuf[256]; std::copy(buffer, buffer+256, utfbuf); *rval = STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, utfbuf ) ); return( JS_TRUE ); } JSBool JSI_Entity::orderSingle( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) { return( order( cx, obj, argc, argv, rval, false ) ); } JSBool JSI_Entity::orderQueued( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) { return( order( cx, obj, argc, argv, rval, true ) ); } JSBool JSI_Entity::order( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval, bool queueOrder ) { HEntity* e = (HEntity*)JS_GetPrivate( cx, obj ); // This needs to be sorted (uses Scheduler rather than network messaging) debug_assert( argc >= 1 ); int orderCode; try { orderCode = ToPrimitive( argv[0] ); } catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_FALSE; JS_ReportError( cx, "Invalid order type" ); return( JS_TRUE ); } CEntityOrder newOrder; (int&)newOrder.m_type = orderCode; switch( orderCode ) { case CEntityOrder::ORDER_GOTO: case CEntityOrder::ORDER_PATROL: if( argc < 3 ) { *rval = JSVAL_FALSE; JS_ReportError( cx, "Too few parameters" ); return( JS_TRUE ); } try { newOrder.m_data[0].location.x = g_ScriptingHost.ValueToDouble( argv[1] ); newOrder.m_data[0].location.y = g_ScriptingHost.ValueToDouble( argv[2] ); } catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_FALSE; JS_ReportError( cx, "Invalid location" ); return( JS_TRUE ); } g_Scheduler.pushFrame( ORDER_DELAY, (*e)->me, new CMessageOrder( newOrder, queueOrder ) ); *rval = JSVAL_TRUE; return( JS_TRUE ); default: *rval = JSVAL_FALSE; JS_ReportError( cx, "Invalid order type" ); return( JS_TRUE ); } } */