//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= // // The copyright to the contents herein is the property of Charles G. Cleveland. // The contents may be used and/or copied only with the written permission of // Charles G. Cleveland, or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: Contains all script bindings for testing functionality // // $Workfile: AvHAvHScriptManager.cpp $ // $Date: 2002/11/22 21:24:27 $ // //------------------------------------------------------------------------------- // $Log: AvHScriptManager.cpp,v $ // Revision 1.3 2002/11/22 21:24:27 Flayra // - Changed AVH_DEVELOPER_BUILD to DEBUG // // Revision 1.2 2002/06/25 18:15:52 Flayra // - Some enhancements and bugfixes for tutorial // // Revision 1.1 2002/05/23 02:33:20 Flayra // - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development. // //=============================================================================== #include "../util/nowarnings.h" #include "AvHScriptManager.h" #include "../util/Checksum.h" #include "../util/STLUtil.h" #include "AvHConstants.h" #ifdef USE_LUA extern "C" { #include #include #include } #endif AvHScriptInstance* gRunningScript = NULL; AvHScriptInstance::AvHScriptInstance(string inScriptName) { #ifdef USE_LUA this->mState = NULL; #endif this->Init(); // Assumes that filenames are relative to the ns/scripts directory //this->mScriptName = kModDirectory + string("/") + kScriptsDirectory + string("/") + inScriptName; this->mScriptName = inScriptName; } void AvHScriptInstance::AddCallback(string& inCallbackName, float inTime) { CallbackType theCallback(inCallbackName, inTime); this->mCallbacksQueuedForAdd.push_back(theCallback); } bool AvHScriptInstance::CallbacksPending() const { bool theCallbacksPending = false; if((this->mCallbackList.size() > 0) || (this->mCallbacksQueuedForAdd.size() > 0)) { theCallbacksPending = true; } return theCallbacksPending; } void AvHScriptInstance::CallSimpleFunction(const string& inFunctionName) { gRunningScript = this; #ifdef USE_LUA // Execute callback lua_getglobal(this->mState, inFunctionName.c_str()); //lua_pushstring(this->mState, inFunctionName.c_str()); lua_call(this->mState, 0, 0); #endif gRunningScript = NULL; } void AvHScriptInstance::Cleanup() { ASSERT(!this->CallbacksPending()); ASSERT(this->mState); #ifdef USE_LUA lua_close(this->mState); #endif } #ifdef USE_LUA lua_State* AvHScriptInstance::GetState() { return this->mState; } #endif void AvHScriptInstance::Init() { #ifdef USE_LUA this->mState = lua_open(); lua_baselibopen(this->mState); lua_strlibopen(this->mState); lua_mathlibopen(this->mState); //lua_iolibopen(this->mState); this->InitShared(); #ifdef AVH_SERVER this->InitServer(); #else this->InitClient(); #endif #endif } void AvHScriptInstance::Reset() { // Delete callbacks this->mCallbackList.clear(); this->mCallbacksQueuedForAdd.clear(); // Cleanup this->Cleanup(); } void AvHScriptInstance::Run() { ASSERT(this->mState); ASSERT(this->mScriptName != ""); // Set global current script so it's accessible statically (needed for setting callbacks) gRunningScript = this; #ifdef USE_LUA lua_dofile(this->mState, this->mScriptName.c_str()); #endif gRunningScript = NULL; } void AvHScriptInstance::Update(float inTime) { // First add any queued callback onto our list for(CallbackListType::iterator theQueuedIter = this->mCallbacksQueuedForAdd.begin(); theQueuedIter != this->mCallbacksQueuedForAdd.end(); theQueuedIter++) { this->mCallbackList.push_back(*theQueuedIter); } // Clear queued list this->mCallbacksQueuedForAdd.clear(); // Update callbacks for(CallbackListType::iterator theIter = this->mCallbackList.begin(); theIter != this->mCallbackList.end(); /* no increment*/) { CallbackType& theCallback = *theIter; if(inTime >= theCallback.second) { this->CallSimpleFunction(theCallback.first.c_str()); // Remove callback from list theIter = this->mCallbackList.erase(theIter); } else { theIter++; } } } AvHScriptManager* AvHScriptManager::sSingleton = NULL; AvHScriptManager* AvHScriptManager::Instance() { if(!sSingleton) { sSingleton = new AvHScriptManager(); } ASSERT(sSingleton); return sSingleton; } void AvHScriptManager::Reset() { for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); theIter++) { theIter->Reset(); } this->mScriptList.clear(); } void AvHScriptManager::RunScript(const string& inScriptName) { // Create new AvHScriptInstance, and add it AvHScriptInstance theAvHScriptInstance(inScriptName); // Run it theAvHScriptInstance.Run(); bool theIsRunningOnClient = false; #ifdef AVH_CLIENT theIsRunningOnClient = true; #endif // If it's still running, add it to the list if(theAvHScriptInstance.CallbacksPending() || theIsRunningOnClient) { this->mScriptList.push_back(theAvHScriptInstance); } } void AvHScriptManager::Update(float inTime) { // Run through list of scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); /* no increment */) { // If callback is pending if(theIter->CallbacksPending()) { // Is it time to run any of our callbacks? theIter->Update(inTime); // Always increment theIter++; } // else else { // Remove it from the list theIter = this->mScriptList.erase(theIter); } } } #ifdef AVH_CLIENT void AvHScriptManager::ClientUpdate(float inTimePassed) { #ifdef USE_LUA // For all scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); /* no increment */) { // Call "clientUpdate(inTimePassed)" function (push function then args) lua_getglobal(theIter->GetState(), "clientUpdate"); // Push time passed lua_pushnumber(theIter->GetState(), inTimePassed); // Push num args and num return lua_call(theIter->GetState(), 1, 1); // If function returns false, delete it bool theKeepRunning = true; int theNumReturned = lua_gettop(theIter->GetState()); if(theNumReturned > 0) { string theString = lua_tostring(theIter->GetState(), 1); theKeepRunning = lua_tonumber(theIter->GetState(), 1); lua_pop(theIter->GetState(), 1); } if(!theKeepRunning) { theIter->Reset(); theIter = this->mScriptList.erase(theIter); } else { // else increment theIter++; } } #endif } void AvHScriptManager::DrawNormal() { // For all scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); theIter++) { theIter->CallSimpleFunction("drawNormal"); } } void AvHScriptManager::DrawTransparent() { // For all scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); theIter++) { theIter->CallSimpleFunction("drawTransparent"); } } void AvHScriptManager::DrawNoZBuffering() { // For all scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); theIter++) { theIter->CallSimpleFunction("drawNoZBuffering"); } } bool AvHScriptManager::GetClientMove(int& outButtonBits, int& outImpulse) { bool theSuccess = false; #ifdef USE_LUA #ifdef DEBUG // For all scripts for(AvHScriptInstanceListType::iterator theIter = this->mScriptList.begin(); theIter != this->mScriptList.end(); theIter++) { // Call getClientMove() on script. If it is successful, stop processing. Only one script can control movement at a time const int kNumExpectedReturnValues = 2; // Execute callback lua_getglobal(theIter->GetState(), "getClientMove"); lua_call(theIter->GetState(), 0, kNumExpectedReturnValues); // Check for success int theNumReturned = lua_gettop(theIter->GetState()); if(theNumReturned >= kNumExpectedReturnValues) { // Populating move structure if possible outButtonBits = (int)lua_tonumber(theIter->GetState(), 1); outImpulse = (int)lua_tonumber(theIter->GetState(), 2); lua_pop(theIter->GetState(), kNumExpectedReturnValues); theSuccess = true; } if(theSuccess) { break; } } #endif #endif return theSuccess; } #endif