ns/releases/3.1.2/source/mod/AvHScriptManager.cpp

343 lines
8.4 KiB
C++

//======== (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 "mod/AvHScriptManager.h"
#include "util/Checksum.h"
#include "util/STLUtil.h"
#include "mod/AvHConstants.h"
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
AvHScriptInstance* gRunningScript = NULL;
AvHScriptInstance::AvHScriptInstance(string inScriptName)
{
this->mState = NULL;
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;
// Execute callback
lua_getglobal(this->mState, inFunctionName.c_str());
//lua_pushstring(this->mState, inFunctionName.c_str());
lua_call(this->mState, 0, 0);
gRunningScript = NULL;
}
void AvHScriptInstance::Cleanup()
{
ASSERT(!this->CallbacksPending());
ASSERT(this->mState);
lua_close(this->mState);
}
lua_State* AvHScriptInstance::GetState()
{
return this->mState;
}
void AvHScriptInstance::Init()
{
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
}
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;
lua_dofile(this->mState, this->mScriptName.c_str());
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)
{
// 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++;
}
}
}
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 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
return theSuccess;
}
#endif