static int GM_CDECL gmfFireTeamGetInfo( gmThread *a_thread ) { CHECK_THIS_BOT(); GM_CHECK_NUM_PARAMS( 0 ); ET_FireTeamInfo ft; if ( InterfaceFuncs::FireTeamGetInfo( native, ft ) && ft.mInFireTeam ) { DisableGCInScope gcEn( a_thread->GetMachine() ); gmMachine *pM = a_thread->GetMachine(); gmTableObject *tbl = pM->AllocTableObject(); gmTableObject *mbrtbl = pM->AllocTableObject(); tbl->Set( pM, "Members", gmVariable( mbrtbl ) ); tbl->Set( pM, "FireTeamNum", gmVariable( ft.mFireTeamNum ) ); tbl->Set( pM, "Leader", gmVariable::EntityVar( ft.mLeader.AsInt() ) ); int m = 0; for ( int i = 0; i < ET_FireTeamInfo::MaxMembers; ++i ) { if ( ft.mMembers[ i ].IsValid() ) { mbrtbl->Set( pM, m++, gmVariable::EntityVar( ft.mMembers[ i ].AsInt() ) ); } } a_thread->PushTable( tbl ); } else a_thread->PushNull(); return GM_OK; }
// function: GetMG42Info // Returns currently mounted mg42 info for the bot // // // Parameters: // // GameEntity // Table // // Returns: // MG42 Info static int gmfGetMG42Info( gmThread *a_thread ) { CHECK_THIS_BOT(); GM_CHECK_NUM_PARAMS( 1 ); GM_CHECK_TABLE_PARAM( tbl, 0 ); DisableGCInScope gcEn( a_thread->GetMachine() ); if ( !tbl ) tbl = a_thread->GetMachine()->AllocTableObject(); ET_MG42Info mg42Info; if ( tbl != NULL && InterfaceFuncs::GetMg42Properties( native, mg42Info ) ) { tbl->Set( a_thread->GetMachine(), "CenterFacing", gmVariable( mg42Info.mCenterFacing ) ); tbl->Set( a_thread->GetMachine(), "MinHorizontal", gmVariable( mg42Info.mMinHorizontalArc ) ); tbl->Set( a_thread->GetMachine(), "MaxHorizontal", gmVariable( mg42Info.mMaxHorizontalArc ) ); tbl->Set( a_thread->GetMachine(), "MinVertical", gmVariable( mg42Info.mMinVerticalArc ) ); tbl->Set( a_thread->GetMachine(), "MaxVertical", gmVariable( mg42Info.mMaxVerticalArc ) ); a_thread->PushInt( 1 ); } else { a_thread->PushNull(); } return GM_OK; }
gmVariable FmodEventDesc::GetUserProperty( gmMachine* a_machine, const char* a_name ) { ASSERT(m_valid); FMOD_STUDIO_USER_PROPERTY prop; FMOD_RESULT result = m_desc.getUserProperty( a_name, &prop ); if ( result != FMOD_OK ) { WARN( result == FMOD_OK, "FmodEvent: unable to get user property '%s'", a_name ); gmVariable null_var; null_var.Nullify(); return null_var; } switch( prop.type ) { case FMOD_STUDIO_USER_PROPERTY_TYPE_FLOAT: return gmVariable(prop.floatValue); case FMOD_STUDIO_USER_PROPERTY_TYPE_INTEGER: return gmVariable(prop.intValue); case FMOD_STUDIO_USER_PROPERTY_TYPE_BOOLEAN: return gmVariable(prop.boolValue?1:0); case FMOD_STUDIO_USER_PROPERTY_TYPE_STRING: { gmStringObject* obj = a_machine->AllocStringObject( prop.stringValue ); return gmVariable(obj); } } // should not get here gmVariable var; var.Nullify(); return var; }
void LeapController::UpdateFrameGM() { // get vm gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); // call LeapManager.PreUpdateData gmFunctionObject* preupdate_func = m_gm_leap_manager->Get(vm, "PreUpdateData").GetFunctionObjectSafe(); ASSERT(preupdate_func); gmCall call_pre; call_pre.BeginFunction( vm, preupdate_func, gmVariable(m_gm_leap_manager) ); call_pre.End(); // grab current frame in GM gmTableObject * curr_frame_table = m_gm_leap_manager->Get(vm, "curr_frame").GetTableObjectSafe(); ASSERT(curr_frame_table); // data we are using to populate GM Tables const LeapFrame & frame = m_frames[m_frame_index]; UpdateInteractionBoxGM(); UpdateFingersGM( curr_frame_table, frame ); UpdateHandsGM( curr_frame_table, frame ); UpdateGesturesGM( curr_frame_table, frame ); // call LeapManager.PostUpdateData gmFunctionObject* postupdate_func = m_gm_leap_manager->Get(vm, "PostUpdateData").GetFunctionObjectSafe(); ASSERT(postupdate_func); gmCall call_post; call_post.BeginFunction( vm, postupdate_func, gmVariable(m_gm_leap_manager) ); call_post.End(); }
// function: GetCabinetData // Returns table of data for the cabinet // // // Parameters: // // GameEntity // Table // // Returns: // Table of Cabinet Data static int gmfGetCabinetData( gmThread *a_thread ) { GM_CHECK_NUM_PARAMS( 2 ); GameEntity gameEnt; GM_CHECK_GAMEENTITY_FROM_PARAM( gameEnt, 0 ); GM_CHECK_TABLE_PARAM( tbl, 1 ); DisableGCInScope gcEn( a_thread->GetMachine() ); if ( !tbl ) tbl = a_thread->GetMachine()->AllocTableObject(); ET_CabinetData cabinetData; if ( tbl != NULL && InterfaceFuncs::GetCabinetData( gameEnt, cabinetData ) ) { tbl->Set( a_thread->GetMachine(), "CurrentAmount", gmVariable( cabinetData.mCurrentAmount ) ); tbl->Set( a_thread->GetMachine(), "MaxAmount", gmVariable( cabinetData.mMaxAmount ) ); tbl->Set( a_thread->GetMachine(), "Rate", gmVariable( cabinetData.mRate ) ); a_thread->PushInt( 1 ); } else { a_thread->PushNull(); } return GM_OK; }
bool bbItem::ToScriptTable(gmMachine *_machine, gmTableObject *&_to) { _to->Set(_machine, "Owner", gmVariable(mOwner)); _to->Set(_machine, "Target", gmVariable(mTarget)); _to->Set(_machine, "ExpireTime", gmVariable(mExpireTime)); _to->Set(_machine, "DeleteOnExpire", gmVariable(mDeleteOnExpire ? 1 : 0)); return true; }
void LeapController::UpdateInteractionBoxGM() { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); gmTableObject * box_table = m_gm_leap_manager->Get(vm, "interaction_box").GetTableObjectSafe(); ASSERT(box_table); box_table->Set( vm, "center", gmVariable( m_interaction_box.center ) ); box_table->Set( vm, "dimen", gmVariable( m_interaction_box.dimen ) ); }
void LeapController::UpdateDevicePropertiesGM() { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); gmTableObject * device_prop_table = m_gm_leap_manager->Get(vm, "device_props").GetTableObjectSafe(); ASSERT(device_prop_table); device_prop_table->Set( vm, "frustum_x_axis_angle", gmVariable( m_device_props.frustum_x_axis_angle ) ); device_prop_table->Set( vm, "frustum_z_axis_angle", gmVariable( m_device_props.frustum_z_axis_angle ) ); device_prop_table->Set( vm, "frustum_y_height", gmVariable( m_device_props.frustum_y_height ) ); device_prop_table->Set( vm, "is_connected", gmVariable( m_device_props.is_connected ? 1:0 ) ); }
// function: GetCursorHint // Gets the current hint and hint value for the client // // Parameters: // // table - table to store results. function sets 'type' and 'value' // // Returns: // none static int GM_CDECL gmfGetCurrentCursorHint( gmThread *a_thread ) { CHECK_THIS_BOT(); GM_CHECK_NUM_PARAMS( 1 ); GM_CHECK_TABLE_PARAM( hint, 0 ); int iHintType = 0, iHintValue = 0; InterfaceFuncs::GetCurrentCursorHint( native, iHintType, iHintValue ); hint->Set( a_thread->GetMachine(), "type", gmVariable( iHintType ) ); hint->Set( a_thread->GetMachine(), "value", gmVariable( iHintValue ) ); return GM_OK; }
void VirtualMachine::Render() { if ( !m_drawManager.IsNull() ) { // draw only if not debugging if ( !m_vm->GetDebugMode() || !m_debugger.IsDebugging() ) { m_vm->GetGlobals()->Set( m_vm, "g_rendering", gmVariable(1) ); m_vm->ExecuteFunction(m_drawFunc, 0, true, &m_drawManager); m_vm->GetGlobals()->Set( m_vm, "g_rendering", gmVariable(0) ); } else { m_vm->ExecuteFunction(m_clearFunc, 0, true, &m_drawManager); } } }
void LeapController::InitGM() { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); // grab the leap manager object gmVariable global_obj_key = gmVariable(vm->AllocStringObject("g_leap")); m_gm_leap_manager = vm->GetGlobals()->Get(global_obj_key).GetTableObjectSafe(); ASSERT( m_gm_leap_manager ); }
void gmBindUtilityLib( gmMachine * a_machine ) { DisableGCInScope gcEn( a_machine ); a_machine->GetGlobals()->Set( a_machine, GM_PATHSTRING, gmVariable( a_machine->AllocStringObject( "?;?.gm" ) ) ); a_machine->GetGlobals()->Set( a_machine, GM_REQUIRETABLE, gmVariable( a_machine->AllocTableObject() ) ); // Register the bot functions. a_machine->RegisterLibrary( s_UtilityLib, sizeof( s_UtilityLib ) / sizeof( s_UtilityLib[ 0 ] ) ); // extra std::string utilities a_machine->RegisterTypeLibrary( GM_STRING, s_stringLib, sizeof( s_stringLib ) / sizeof( s_stringLib[ 0 ] ) ); // Create the dump flag table. gmTableObject *pDumpTable = a_machine->AllocTableObject(); pDumpTable->Set( a_machine, gmVariable( a_machine->AllocStringObject( "RECURSE" ) ), gmVariable( gmUtility::DUMP_RECURSE ) ); pDumpTable->Set( a_machine, gmVariable( a_machine->AllocStringObject( "FUNCTIONS" ) ), gmVariable( gmUtility::DUMP_FUNCTIONS ) ); pDumpTable->Set( a_machine, gmVariable( a_machine->AllocStringObject( "REFERENCES" ) ), gmVariable( gmUtility::DUMP_REFERENCES ) ); pDumpTable->Set( a_machine, gmVariable( a_machine->AllocStringObject( "TYPEFUNCTIONS" ) ), gmVariable( gmUtility::DUMP_TYPEFUNCTIONS ) ); pDumpTable->Set( a_machine, gmVariable( a_machine->AllocStringObject( "ALL" ) ), gmVariable( gmUtility::DUMP_ALL ) ); a_machine->GetGlobals()->Set( a_machine, gmVariable( a_machine->AllocStringObject( "DUMP" ) ), gmVariable( pDumpTable ) ); }
static int GM_CDECL gmStringTokenize( gmThread * a_thread ) { GM_CHECK_NUM_PARAMS( 1 ); GM_CHECK_STRING_PARAM( delim, 0 ); DisableGCInScope gcEn( a_thread->GetMachine() ); const gmVariable * var = a_thread->GetThis(); gmStringObject * strObj = var->GetStringObjectSafe(); StringVector tokens; Utils::Tokenize( strObj->GetString(), delim, tokens ); gmTableObject *pTbl = a_thread->GetMachine()->AllocTableObject(); for ( uint32_t i = 0; i < tokens.size(); ++i ) pTbl->Set( a_thread->GetMachine(), i, gmVariable( a_thread->GetMachine()->AllocStringObject( tokens[ i ].c_str() ) ) ); a_thread->PushTable( pTbl ); return GM_OK; }
// RAGE AGAINST THE VIRTUAL MACHINE =) gmThread::State gmThread::Sys_Execute(gmVariable * a_return) { register union { const gmuint8 * instruction; const gmuint32 * instruction32; }; register gmVariable * top; gmVariable * base; gmVariable * operand; const gmuint8 * code; if(m_state != RUNNING) return m_state; #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_isBroken) { if(m_machine->m_isBroken(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT // make sure we have a stack frame GM_ASSERT(m_frame); GM_ASSERT(GetFunction()->m_type == GM_FUNCTION); // cache our "registers" gmFunctionObject * fn = (gmFunctionObject *) GM_MOBJECT(m_machine, GetFunction()->m_value.m_ref); code = (const gmuint8 *) fn->GetByteCode(); if(m_instruction == NULL) instruction = code; else instruction = m_instruction; top = GetTop(); base = GetBase(); // // start byte code execution // for(;;) { #ifdef GM_CHECK_USER_BREAK_CALLBACK // This may be defined in gmConfig_p.h // Check external source to break execution with exception eg. Check for CTRL-BREAK // Endless loop protection could be implemented with this, or in a similar manner. if( gmMachine::s_userBreakCallback && gmMachine::s_userBreakCallback(this) ) { GMTHREAD_LOG("User break. Execution halted."); goto LabelException; } #endif //GM_CHECK_USER_BREAK_CALLBACK switch(*(instruction32++)) { // // unary operator // #if GM_USE_INCDECOPERATORS case BC_OP_INC : case BC_OP_DEC : #endif case BC_BIT_INV : case BC_OP_NEG : case BC_OP_POS : case BC_OP_NOT : { operand = top - 1; gmOperatorFunction op = OPERATOR(operand->m_type, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("unary operator %s undefined for type %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type)); goto LabelException; } break; } // // operator // case BC_OP_ADD : case BC_OP_SUB : case BC_OP_MUL : case BC_OP_DIV : case BC_OP_REM : case BC_BIT_OR : case BC_BIT_XOR : case BC_BIT_AND : case BC_BIT_SHL : case BC_BIT_SHR : case BC_OP_LT : case BC_OP_GT : case BC_OP_LTE : case BC_OP_GTE : case BC_OP_EQ : case BC_OP_NEQ : { operand = top - 2; --top; // NOTE: Classic logic for operators. Higher type processes the operation. register gmType t1 = operand[1].m_type; if(operand->m_type > t1) t1 = operand->m_type; gmOperatorFunction op = OPERATOR(t1, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(t1, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[3] = operand[1]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 4); State res = PushStackFrame(2, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("operator %s undefined for type %s and %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type), m_machine->GetTypeName((operand + 1)->m_type)); goto LabelException; } break; } case BC_GETIND : { operand = top - 2; --top; gmOperatorFunction op = OPERATOR(operand->m_type, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[3] = operand[1]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 4); State res = PushStackFrame(2, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("operator %s undefined for type %s and %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type), m_machine->GetTypeName((operand + 1)->m_type)); goto LabelException; } break; } case BC_SETIND : { operand = top - 3; top -= 3; gmOperatorFunction op = OPERATOR(operand->m_type, O_SETIND); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, O_SETIND))) { operand[4] = operand[2]; operand[3] = operand[1]; operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 5); State res = PushStackFrame(3, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("setind failed."); goto LabelException; } break; } case BC_NOP : { break; } case BC_LINE : { #if GMDEBUG_SUPPORT if(m_machine->GetDebugMode() && m_machine->m_line) { SetTop(top); m_instruction = instruction; if(m_machine->m_line(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } case BC_GETDOT : { operand = top - 1; gmptr member = OPCODE_PTR(instruction); top->m_type = GM_STRING; top->m_value.m_ref = member; gmType t1 = operand->m_type; gmOperatorFunction op = OPERATOR(t1, O_GETDOT); if(op) { op(this, operand); if(operand->m_type) break; } if(t1 == GM_NULL) { GMTHREAD_LOG("getdot failed."); goto LabelException; } *operand = m_machine->GetTypeVariable(t1, gmVariable(GM_STRING, member)); break; } case BC_SETDOT : { operand = top - 2; gmptr member = OPCODE_PTR(instruction); top->m_type = GM_STRING; top->m_value.m_ref = member; top -= 2; gmOperatorFunction op = OPERATOR(operand->m_type, O_SETDOT); if(op) { op(this, operand); } else { GMTHREAD_LOG("setdot failed."); goto LabelException; } break; } case BC_BRA : { instruction = code + OPCODE_PTR_NI(instruction); break; } case BC_BRZ : { #if GM_BOOL_OP operand = top - 1; --top; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP --top; if(top->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRNZ : { #if GM_BOOL_OP operand = top - 1; --top; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP --top; if(top->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRZK : { #if GM_BOOL_OP operand = top - 1; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP if(top[-1].m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRNZK : { #if GM_BOOL_OP operand = top - 1; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP if(top[-1].m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_CALL : { SetTop(top); int numParams = (int) OPCODE_INT(instruction); State res = PushStackFrame(numParams, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) { #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_call) { m_instruction = instruction; if(m_machine->m_call(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { if(a_return) *a_return = m_stack[m_top - 1]; m_machine->Sys_SwitchState(this, KILLED); } return res; } case BC_RET : { PUSHNULL; } case BC_RETV : { SetTop(top); int res = Sys_PopStackFrame(instruction, code); top = GetTop(); base = GetBase(); if(res == RUNNING) { #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_return) { m_instruction = instruction; if(m_machine->m_return(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } if(res == KILLED) { if(a_return) *a_return = *(top - 1); m_machine->Sys_SwitchState(this, KILLED); return KILLED; } if(res == SYS_EXCEPTION) goto LabelException; break; } #if GM_USE_FORK // duplicates the current thread and just the local stack frame // and branches around the forked section of code case BC_FORK : { int id; gmThread* newthr = GetMachine()->CreateThread(&id); GM_ASSERT( newthr ); // make sure there is enough room newthr->Touch( m_size - m_base + 2 - GMTHREAD_SLACKSPACE); // copy stack and vars memcpy( newthr->m_stack, &m_stack[ m_base - 2 ], sizeof( gmVariable ) * (m_top - m_base + 2 ) ); newthr->m_top = m_top - m_base + 2; newthr->m_frame = m_machine->Sys_AllocStackFrame(); newthr->m_frame->m_prev = 0; newthr->m_frame->m_returnAddress = 0; newthr->m_frame->m_returnBase = 0; newthr->m_base = 2; newthr->m_instruction = instruction + sizeof(gmptr); // skip branch on other thread newthr->PushInt( GetId() ); instruction = code + OPCODE_PTR_NI( instruction ); // branch top->m_type = GM_INT; top->m_value.m_int = newthr->GetId(); ++top; break; } #endif //GM_USE_FORK case BC_FOREACH : { gmuint32 localvalue = OPCODE_INT(instruction); gmuint32 localkey = localvalue >> 16; localvalue &= 0xffff; // iterator is at tos-1, table is at tos -2, push int 1 if continuing loop. write key and value into localkey and localvalue if(top[-2].m_type != GM_TABLE) { #if GM_USER_FOREACH gmTypeIteratorCallback itrfunc = m_machine->GetUserTypeIteratorCallback(top[-2].m_type); if (!itrfunc) { GMTHREAD_LOG("foreach expression has no iterator function"); goto LabelException; } gmTypeIterator it = (gmTypeIterator) top[-1].m_value.m_int; gmUserObject *obj = (gmUserObject*)GM_MOBJECT(m_machine, top[-2].m_value.m_ref); // Do callback for getnext gmVariable localvar; gmVariable localkeyvar; itrfunc(this, obj, it, &localkeyvar, &localvar); if (it != GM_TYPE_ITR_NULL) { base[localkey] = localkeyvar; base[localvalue] = localvar; top->m_type = GM_INT; top->m_value.m_int = 1; } else { top->m_type = GM_INT; top->m_value.m_int = 0; } top[-1].m_value.m_int = it; ++top; #else //GM_USER_FOREACH (original) GMTHREAD_LOG("foreach expression is not table type"); goto LabelException; #endif //GM_USER_FOREACH } else { GM_ASSERT(top[-1].m_type == GM_INT); gmTableIterator it = (gmTableIterator) top[-1].m_value.m_int; gmTableObject * table = (gmTableObject *) GM_MOBJECT(m_machine, top[-2].m_value.m_ref); gmTableNode * node = table->GetNext(it); top[-1].m_value.m_int = it; if(node) { base[localkey] = node->m_key; base[localvalue] = node->m_value; top->m_type = GM_INT; top->m_value.m_int = 1; } else { top->m_type = GM_INT; top->m_value.m_int = 0; } ++top; } break; } case BC_POP : { --top; break; } case BC_POP2 : { top -= 2; break; } case BC_DUP : { top[0] = top[-1]; ++top; break; } case BC_DUP2 : { top[0] = top[-2]; top[1] = top[-1]; top += 2; break; } case BC_SWAP : { top[0] = top[-1]; top[-1] = top[-2]; top[-2] = top[0]; break; } case BC_PUSHNULL : { PUSHNULL; break; } case BC_PUSHINT : { top->m_type = GM_INT; top->m_value.m_int = OPCODE_INT(instruction); ++top; break; } case BC_PUSHINT0 : { top->m_type = GM_INT; top->m_value.m_int = 0; ++top; break; } case BC_PUSHINT1 : { top->m_type = GM_INT; top->m_value.m_int = 1; ++top; break; } case BC_PUSHFP : { top->m_type = GM_FLOAT; top->m_value.m_float = OPCODE_FLOAT(instruction); ++top; break; } case BC_PUSHSTR : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); ++top; break; } case BC_PUSHTBL : { SetTop(top); top->m_type = GM_TABLE; top->m_value.m_ref = m_machine->AllocTableObject()->GetRef(); ++top; break; } case BC_PUSHFN : { top->m_type = GM_FUNCTION; top->m_value.m_ref = OPCODE_PTR(instruction); ++top; break; } case BC_PUSHTHIS : { *top = *GetThis(); ++top; break; } case BC_GETLOCAL : { gmuint32 offset = OPCODE_INT(instruction); *(top++) = base[offset]; break; } case BC_SETLOCAL : { gmuint32 offset = OPCODE_INT(instruction); // Write barrier old local objects { gmGarbageCollector* gc = m_machine->GetGC(); if( !gc->IsOff() && base[offset].IsReference() ) { gmObject * object = GM_MOBJECT(m_machine, base[offset].m_value.m_ref); gc->WriteBarrier(object); } } base[offset] = *(--top); break; } case BC_GETGLOBAL : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); *top = m_machine->GetGlobals()->Get(*top); ++top; break; } case BC_SETGLOBAL : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); m_machine->GetGlobals()->Set(m_machine, *top, *(top-1)); --top; break; } case BC_GETTHIS : { gmptr member = OPCODE_PTR(instruction); const gmVariable * thisVar = GetThis(); *top = *thisVar; top[1].m_type = GM_STRING; top[1].m_value.m_ref = member; gmOperatorFunction op = OPERATOR(thisVar->m_type, O_GETDOT); if(op) { op(this, top); if(top->m_type) { ++top; break; } } if(thisVar->m_type == GM_NULL) { GMTHREAD_LOG("getthis failed. this is null"); goto LabelException; } *top = m_machine->GetTypeVariable(thisVar->m_type, top[1]); ++top; break; } case BC_SETTHIS : { gmptr member = OPCODE_PTR(instruction); const gmVariable * thisVar = GetThis(); operand = top - 1; *top = *operand; *operand = *thisVar; top[1].m_type = GM_STRING; top[1].m_value.m_ref = member; --top; gmOperatorFunction op = OPERATOR(thisVar->m_type, O_SETDOT); if(op) { op(this, operand); } else { GMTHREAD_LOG("setthis failed."); goto LabelException; } break; } default : { break; } } } LabelException: // // exception handler // m_instruction = instruction; // spit out error info LogLineFile(); LogCallStack(); // call machine exception handler if(gmMachine::s_machineCallback) { if(gmMachine::s_machineCallback(m_machine, MC_THREAD_EXCEPTION, this)) { #if GMDEBUG_SUPPORT // if we are being debugged, put this thread into a limbo state, waiting for delete. if(m_machine->GetDebugMode() && m_machine->m_debugUser) { m_machine->Sys_SwitchState(this, EXCEPTION); return EXCEPTION; } #endif } } // kill the thread m_machine->Sys_SwitchState(this, KILLED); return KILLED; }
gmThread::State gmThread::PushStackFrame(int a_numParameters, const gmuint8 ** a_ip, const gmuint8 ** a_cp) { // calculate new stack base int base = m_top - a_numParameters; if( base == 2 ) // When initial thread function is ready, signal thread creation { // This may not be the best place to signal, but we at least want a valid 'this' m_base = base; // Init so some thread queries work m_machine->Sys_SignalCreateThread(this); } gmVariable * fnVar = &m_stack[base - 1]; if(fnVar->m_type != GM_FUNCTION) { m_machine->GetLog().LogEntry("attempt to call non function type"); return SYS_EXCEPTION; } gmFunctionObject * fn = (gmFunctionObject *) GM_MOBJECT(m_machine, fnVar->m_value.m_ref); if(fn->m_cFunction) { // // Its a native function call, call it now as we cannot stack wind natives. this avoids // pushing a gmStackFrame. // m_numParameters = (short) a_numParameters; int lastBase = m_base; int lastTop = m_top; m_base = base; int result = fn->m_cFunction(this); // Write barrier old local objects at native pop time { gmGarbageCollector* gc = m_machine->GetGC(); if( !gc->IsOff() ) { for(int index = m_base; index < m_top; ++index) { if(m_stack[index].IsReference()) { gmObject * object = GM_MOBJECT(m_machine, m_stack[index].m_value.m_ref); gc->WriteBarrier(object); } } } } // handle state if(result == GM_SYS_STATE) { // this is special case, a bit messy. return PushStackFrame(a_numParameters - GM_STATE_NUM_PARAMS, a_ip, a_cp); } // NOTE: It is not currently safe for a C binding to kill this thread. // Since we cant unwind mixed script and native functions anyway, // perhaps the safest thing would be for ALWAYS delay killed threads // from deletion. // push a null if the function did not return anything if(lastTop == m_top) { m_stack[m_base - 2] = gmVariable(GM_NULL, 0); } else { m_stack[m_base - 2] = m_stack[m_top - 1]; } // Restore the stack m_top = m_base - 1; m_base = lastBase; // check the call result if(result != GM_OK) { const gmuint8 * returnAddress = (a_ip) ? *a_ip : NULL; if(result == GM_SYS_YIELD) { m_machine->Sys_RemoveSignals(this); m_instruction = returnAddress; return SYS_YIELD; } else if(result == GM_SYS_BLOCK) { m_instruction = returnAddress; m_machine->Sys_SwitchState(this, BLOCKED); return BLOCKED; } else if(result == GM_SYS_SLEEP) { m_instruction = returnAddress; m_machine->Sys_SwitchState(this, SLEEPING); return SLEEPING; } else if(result == GM_SYS_KILL) { return KILLED; } return SYS_EXCEPTION; } if(!m_frame) // C called C function, no stack frame, so signal killed. { return KILLED; } // return result return RUNNING; } // // Its a script function call, push a stack frame // int clearSize = fn->GetNumParamsLocals() - a_numParameters; if(!Touch(clearSize + fn->GetMaxStackSize())) { m_machine->GetLog().LogEntry("stack overflow"); return SYS_EXCEPTION; } // zero missing params and locals. if(a_numParameters <= fn->GetNumParams()) { memset(GetTop(), 0, sizeof(gmVariable) * clearSize); } else { memset(&m_stack[base + fn->GetNumParams()], 0, sizeof(gmVariable) * fn->GetNumLocals()); } // push a new stack frame gmStackFrame * frame = m_machine->Sys_AllocStackFrame(); frame->m_prev = m_frame; m_frame = frame; // cache new frame variables m_frame->m_returnBase = m_base; if(a_ip) { m_frame->m_returnAddress = *a_ip; *a_ip = (const gmuint8 *) fn->GetByteCode(); *a_cp = *a_ip; } else { m_frame->m_returnAddress = NULL; } m_base = base; m_top = base + fn->GetNumParamsLocals(); return RUNNING; }
void LeapController::UpdateFingersGM( gmTableObject* a_frame_table, const LeapFrame & a_frame ) { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); gmTableObject * fingers_table = a_frame_table->Get(vm, "fingers").GetTableObjectSafe(); ASSERT(fingers_table); // populate fingers for( size_t i = 0; i < a_frame.fingers.size(); ++i ) { const LeapFinger & finger = a_frame.fingers[i]; // create the finger gmTableObject * finger_obj = AllocFreeObj("pool_fingers"); // if none in pool if ( finger_obj == nullptr ) continue; finger_obj->Set( vm, "id", gmVariable( finger.id ) ); finger_obj->Set( vm, "hand_id", gmVariable( finger.hand_id ) ); finger_obj->Set( vm, "hand_index", gmVariable( finger.hand_index ) ); finger_obj->Set( vm, "finger_size", gmVariable( finger.finger_size ) ); finger_obj->Set( vm, "dir", gmVariable( finger.dir ) ); finger_obj->Set( vm, "tip_pos", gmVariable( finger.tip_pos ) ); finger_obj->Set( vm, "tip_pos_stabilized", gmVariable( finger.tip_pos_stabilized ) ); finger_obj->Set( vm, "tip_vel", gmVariable( finger.tip_vel ) ); finger_obj->Set( vm, "age", gmVariable( finger.age ) ); finger_obj->Set( vm, "dist_to_boundary", gmVariable( finger.dist_to_boundary ) ); fingers_table->Set( vm, gmVariable(finger.id), gmVariable(finger_obj) ); } }
void VirtualMachine::RunMain() { IniReader ini(RESOURCE_PATH("common/ini/main.ini")); int debugMode = 1; int runGmLibs = 0; #ifdef FNK_FINAL debugMode = 0; runGmLibs = 1; #endif int fps = ini.GetInt("Window", "FPS"); int gcWorkPerIncrement = ini.GetInt("VirtualMachine", "GC_WorkPerIncrement"); int gcDestructsPerIncrement = ini.GetInt("VirtualMachine", "GC_DestructPerIncrement"); int memUsageSoft = ini.GetInt("VirtualMachine", "MemUsageSoft"); int memUsageHard = ini.GetInt("VirtualMachine", "MemUsageHard"); m_vm->GetGC()->SetWorkPerIncrement(gcWorkPerIncrement); m_vm->GetGC()->SetDestructPerIncrement(gcDestructsPerIncrement); m_vm->SetDesiredByteMemoryUsageSoft(memUsageSoft); m_vm->SetDesiredByteMemoryUsageHard(memUsageHard); m_vm->SetDebugMode(debugMode == 1); m_bUseGmByteCode = runGmLibs == 1; m_dt = 1.0f/fps; // print current setting char buffer[128]; sprintf_s(buffer, "Running at %d hz, VM Debug Mode: %d, VM Run Byte-Code: %d", fps, debugMode, runGmLibs ); m_console.Log(buffer); sprintf_s(buffer, "GC Works Per Increment: %d, GC Destructs Per Increment: %d", gcWorkPerIncrement, gcDestructsPerIncrement ); m_console.Log(buffer); sprintf_s(buffer, "Mem Usage Soft: %d bytes, Mem Usage Hard: %d bytes", memUsageSoft, memUsageHard ); m_console.Log(buffer); // attach debugger if ( m_vm->GetDebugMode() ) m_debugger.Open(m_vm); RegisterLibs(m_vm); // set dt m_vm->GetGlobals()->Set( m_vm, "g_dt", gmVariable(m_dt) ); m_vm->GetGlobals()->Set( m_vm, "g_rendering", gmVariable(0) ); m_vm->GetGlobals()->Set( m_vm, "g_resourcePathPrefix", gmVariable(m_vm->AllocStringObject(RESOURCE_PATH(""))) ); m_threadId = gmCompileStr(m_vm, kEntryFile); printf("'%s' Main thread: %d\n", kEntryFile, m_threadId ); // get draw manager gmVariable drawManagerKey = gmVariable(m_vm->AllocStringObject("g_drawManager")); gmTableObject* drawManager = m_vm->GetGlobals()->Get(drawManagerKey).GetTableObjectSafe(); m_drawManager.Nullify(); if ( drawManager ) { m_drawManager = gmVariable(gmVariable(drawManager)); // grab draw functions gmVariable drawKey = gmVariable(m_vm->AllocStringObject("Draw")); m_drawFunc = drawManager->Get(drawKey).GetFunctionObjectSafe(); gmVariable clearKey = gmVariable(m_vm->AllocStringObject("Clear")); m_clearFunc = drawManager->Get(clearKey).GetFunctionObjectSafe(); } }
void LeapController::UpdateHandsGM( gmTableObject* a_frame_table, const LeapFrame & a_frame ) { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); gmTableObject * hands_table = a_frame_table->Get(vm, "hands").GetTableObjectSafe(); ASSERT(hands_table); gmTableObject * fingers_table = a_frame_table->Get(vm, "fingers").GetTableObjectSafe(); ASSERT(fingers_table); // populate hands for( size_t i = 0; i < a_frame.hands.size(); ++i ) { const LeapHand & hand = a_frame.hands[i]; // create the finger gmTableObject * hand_obj = AllocFreeObj("pool_hands"); // if none in pool if ( hand_obj == nullptr ) continue; // populate finger ids gmTableObject * hand_obj_fingers_ids = hand_obj->Get( vm, "fingers" ).GetTableObjectSafe(); hand_obj_fingers_ids->ClearTable(vm, false); // go through each hand ASSERT(hand.fingers_count >= 0); const int hand_num_fingers = min( hand.fingers_count, LEAP_MAX_NUM_FINGERS_PER_HAND ); for ( int j = 0; j < hand_num_fingers; ++j ) { int finger_index = hand.fingers_index[j]; const LeapFinger & finger = a_frame.fingers[finger_index]; int finger_id = finger.id; // grab finger object gmVariable finger_obj = fingers_table->Get(gmVariable(finger_id)); // quick fix to ignore finger if null if ( finger_obj.IsNull() ) continue; ASSERT(!finger_obj.IsNull()); // make sure the id doesnt already exist ASSERT( hand_obj_fingers_ids->Get(gmVariable(finger_id)).IsNull() ); hand_obj_fingers_ids->Set(vm, gmVariable(finger_id), finger_obj ); } hand_obj->Set( vm, "id", gmVariable( hand.id ) ); hand_obj->Set( vm, "dir", gmVariable( hand.dir ) ); hand_obj->Set( vm, "palm_normal", gmVariable( hand.palm_normal ) ); hand_obj->Set( vm, "palm_pos", gmVariable( hand.palm_pos ) ); hand_obj->Set( vm, "palm_vel", gmVariable( hand.palm_vel ) ); hand_obj->Set( vm, "sphere_center", gmVariable( hand.sphere_center ) ); hand_obj->Set( vm, "sphere_radius", gmVariable( hand.sphere_radius ) ); hand_obj->Set( vm, "age", gmVariable( hand.age ) ); hand_obj->Set( vm, "dist_to_boundary", gmVariable( hand.dist_to_boundary ) ); hands_table->Set( vm, gmVariable(hand.id), gmVariable(hand_obj) ); } }
/ (_ / _ `/ ' \/ -_) /|_/ / _ \/ _ \/ '_/ -_) // /\ \/ __/ __/ / _ \/ __/ \___/\_,_/_/_/_/\__/_/ /_/\___/_//_/_/\_\\__/\_, /___/\__/_/ /_/ .__/\__/ /___/ /_/ See Copyright Notice in gmMachine.h */ #include "gmConfig.h" #include "gmVariable.h" #include "gmThread.h" #include "gmStringObject.h" #include "gmUserObject.h" // Init statics and constants gmVariable gmVariable::s_null = gmVariable(GM_NULL, 0); const char * gmVariable::AsString(gmMachine * a_machine, char * a_buffer, int a_len) const { switch(m_type) { case GM_NULL : _gmsnprintf(a_buffer, a_len, "null"); break; case GM_INT : _gmsnprintf(a_buffer, a_len, "%d", m_value.m_int); break; case GM_FLOAT : _gmsnprintf(a_buffer, a_len, "%g", m_value.m_float); break;
void LeapController::UpdateGesturesGM( gmTableObject* a_frame_table, const LeapFrame & a_frame ) { gmMachine* vm = &VirtualMachine::Ref().GetVM(); ASSERT(vm); gmTableObject * gestures_table = a_frame_table->Get(vm, "gestures").GetTableObjectSafe(); ASSERT(gestures_table); // populate hands for( size_t i = 0; i < a_frame.gestures.size(); ++i ) { const LeapGesture & gesture = a_frame.gestures[i]; // create the finger gmTableObject * gesture_obj = AllocFreeObj("pool_gestures"); // if none in pool if ( gesture_obj == nullptr ) continue; gesture_obj->ClearTable(vm); // set basic gesture properties gesture_obj->Set( vm, "id", gmVariable( gesture.id ) ); gesture_obj->Set( vm, "duration", gmVariable( gesture.duration ) ); gesture_obj->Set( vm, "type", gmVariable( gesture.type ) ); gesture_obj->Set( vm, "state", gmVariable( gesture.state ) ); switch( gesture.type ) { case LEAPGESTURE_CIRCLE: { gesture_obj->Set( vm, "finger_id", gmVariable( gesture.data.circle.finger_id ) ); gesture_obj->Set( vm, "center", gmVariable( gesture.data.circle.center.toV3() ) ); gesture_obj->Set( vm, "normal", gmVariable( gesture.data.circle.normal.toV3() ) ); gesture_obj->Set( vm, "progress", gmVariable( gesture.data.circle.progress) ); gesture_obj->Set( vm, "radius", gmVariable( gesture.data.circle.radius ) ); break; } case LEAPGESTURE_SWIPE: { gesture_obj->Set( vm, "finger_id", gmVariable( gesture.data.swipe.finger_id ) ); gesture_obj->Set( vm, "dir", gmVariable( gesture.data.swipe.dir.toV3() ) ); gesture_obj->Set( vm, "pos", gmVariable( gesture.data.swipe.pos.toV3() ) ); gesture_obj->Set( vm, "start_pos", gmVariable( gesture.data.swipe.start_pos.toV3() ) ); gesture_obj->Set( vm, "speed", gmVariable( gesture.data.swipe.speed ) ); break; } case LEAPGESTURE_SCREEN_TAP: { gesture_obj->Set( vm, "finger_id", gmVariable( gesture.data.screen_tap.finger_id ) ); gesture_obj->Set( vm, "dir", gmVariable( gesture.data.screen_tap.dir.toV3() ) ); gesture_obj->Set( vm, "pos", gmVariable( gesture.data.screen_tap.pos.toV3() ) ); break; } case LEAPGESTURE_KEY_TAP: { gesture_obj->Set( vm, "finger_id", gmVariable( gesture.data.key_tap.finger_id ) ); gesture_obj->Set( vm, "dir", gmVariable( gesture.data.key_tap.dir.toV3() ) ); gesture_obj->Set( vm, "pos", gmVariable( gesture.data.key_tap.pos.toV3() ) ); break; } default: { ASSERT(false); } } gestures_table->Set( vm, gmVariable(gesture.id), gmVariable(gesture_obj) ); } }
void OscHandler::UpdateAddressValues( gmMachine * a_vm ) { // an example address data is like: // "/address" = { value = v2(1.0f), age = 0.0f }; ASSERT( m_socket.isOk() ); const int timeout = 1; /* timeout, in ms */ while ( m_socket.receiveNextPacket( timeout ) ) { m_packet_reader.init( m_socket.packetData(), m_socket.packetSize()); oscpkt::Message *msg; while (m_packet_reader.isOk() && (msg = m_packet_reader.popMessage()) != 0) { ASSERT(msg->isOk()); // grab parameters const std::string & address = msg->addressPattern(); const std::string & type_tags = msg->typeTags(); oscpkt::Message::ArgReader arg_reader = msg->match( address ); const size_t num_args = arg_reader.nbArgRemaining(); // grab the table that corresponds to this address gmVariable address_table_var = m_data_table->Get( a_vm, address.c_str() ); // if address not registered if ( address_table_var.IsNull() ) { TRACE( "OSC address '%s' not registered!\n", address.c_str() ); continue; } // var at address must be be a table ASSERT( address_table_var.IsTable() ); gmTableObject * address_table = address_table_var.GetTableObjectSafe(); gmVariable curr_address_val = address_table->Get( a_vm, "val" ); ASSERT( !curr_address_val.IsNull() ); // result value gmVariable next_address_val; next_address_val.Nullify(); if ( num_args == 0 ) continue; else if ( num_args == 1 ) // handle 1 arg { if ( arg_reader.isBool() ) { bool val; arg_reader.popBool(val); next_address_val.SetInt( val ? 1 : 0 ); } else if ( arg_reader.isInt32() ) { int val; arg_reader.popInt32(val); next_address_val.SetInt( val ); } else if ( arg_reader.isInt64() ) { // downcasted 64->32 bit int int64_t val; arg_reader.popInt64(val); next_address_val.SetInt( (int)val ); } else if ( arg_reader.isFloat() ) { // downcasted 64->32 bit int float val; arg_reader.popFloat(val); next_address_val.SetFloat( val ); } else if ( arg_reader.isDouble() ) { // downcasted 64->32 bit double val; arg_reader.popDouble(val); next_address_val.SetFloat( (float)val ); } else if ( arg_reader.isStr() ) { std::string val; arg_reader.popStr(val); next_address_val.SetString( a_vm, val.c_str() ); } else { TRACE("OSC unrecognzed arg type for of address '%s'", address.c_str(), num_args ); } } else if ( num_args == 2 ) // can only be v2 or v2i { if ( type_tags == "ii" ) { v2i result; if ( GetArgIntVal( arg_reader, result.x ) && GetArgIntVal( arg_reader, result.y ) ) { next_address_val.SetV2i(result); } else { TRACE("OSC unable to grab v2i from address '%s'", address.c_str() ); } } else { v2 result; if ( GetArgFloatOrIntVal( arg_reader, result.x ) && GetArgFloatOrIntVal( arg_reader, result.y ) ) { next_address_val.SetV2(result); } else { TRACE("OSC unable to grab v2 from address '%s'", address.c_str() ); } } } else if ( num_args == 3 ) // handle 3 args, should be v3() { v3 result; if ( GetArgFloatOrIntVal( arg_reader, result.x ) && GetArgFloatOrIntVal( arg_reader, result.y ) && GetArgFloatOrIntVal( arg_reader, result.z ) ) { next_address_val.SetV3(result); } else { TRACE("OSC: unable to grab v3 from address '%s'", address.c_str() ); } } else { TRACE("OSC: unrecognzed number of args for '%s': %d\n", address.c_str(), num_args ); } if ( curr_address_val.GetType() != next_address_val.GetType() ) { // was not able to grab value if ( next_address_val.IsNull() ) { TRACE("OSC: unable to parse value for address '%s'\n", address.c_str() ); } TRACE("OSC: address '%s' expected type '%s' but instead got '%s'\n", address.c_str(), a_vm->GetTypeName(curr_address_val.GetType()), a_vm->GetTypeName(next_address_val.GetType()) ); } else { // set the address variable and reset the age timer address_table->Set( a_vm, "val", next_address_val ); address_table->Set( a_vm, "age", gmVariable(0.0f) ); } } } }
bool ScriptCommandExecutor::Exec( const StringVector & args, const gmVariable &_this ) { const bool bPrintUsage = args.size() > 1 && args[ 1 ] == "?"; if ( mCommandTable ) { DisableGCInScope gcEn( mMachine ); gmVariable vEntry = mCommandTable->Get( mMachine, args[ 0 ].c_str() ); gmFunctionObject *pFn = vEntry.GetFunctionObjectSafe(); if ( !pFn ) { // See if it's new style, and in a table. gmTableObject *pTbl = vEntry.GetTableObjectSafe(); if ( pTbl ) { pFn = pTbl->Get( mMachine, "Func" ).GetFunctionObjectSafe(); bool bRunImmediate = false; if ( !pTbl->Get( mMachine, "RunImmediate" ).GetBoolSafe( bRunImmediate, false ) ) bRunImmediate = false; if ( bPrintUsage ) { gmVariable vHelp = pTbl->Get( mMachine, "Help" ); const char *pHelpString = vHelp.GetCStringSafe( 0 ); if ( pHelpString ) { EngineFuncs::ConsoleMessage( pHelpString ); } else { gmTableObject *pUsageTbl = vHelp.GetTableObjectSafe(); if ( pUsageTbl ) { gmTableIterator tIt; gmTableNode *pNode = pUsageTbl->GetFirst( tIt ); while ( pNode ) { const char *pHelp = pNode->m_value.GetCStringSafe( 0 ); if ( pHelp ) EngineFuncs::ConsoleMessage( pHelp ); pNode = pUsageTbl->GetNext( tIt ); } } } return true; } } } if ( bPrintUsage ) { EngineFuncs::ConsoleError( va( "No Usage Info For Command: %s", args[ 0 ].c_str() ) ); return true; } if ( pFn ) { gmCall call; if ( call.BeginFunction( mMachine, pFn, _this, true ) ) { // Add all the params gmTableObject *pParamTable = mMachine->AllocTableObject(); if ( args.size() > 1 ) { for ( uint32_t i = 1; i < args.size(); ++i ) { char *endPtr; const char *startPtr = args[ i ].c_str(); long iNum = strtol( startPtr, &endPtr, 10 ); double dNum; if ( endPtr != startPtr && !*endPtr ) { pParamTable->Set( mMachine, i - 1, gmVariable( (int)iNum ) ); } else if ( Utils::ConvertString( args[ i ], dNum ) ) { pParamTable->Set( mMachine, i - 1, gmVariable( (float)dNum ) ); } else { pParamTable->Set( mMachine, i - 1, gmVariable( mMachine->AllocStringObject( args[ i ].c_str() ) ) ); } } } call.AddParamTable( pParamTable ); call.End(); return true; } } return false; } return false; }