start of scriptman port. needs gameplay done to continue

This commit is contained in:
Dexter Haslem 2013-09-15 00:40:02 -06:00
parent 40b86daaa7
commit 4a88f21d70
2 changed files with 426 additions and 10 deletions

View File

@ -13,14 +13,7 @@
// engine
#include "filesystem.h"
// lua
//extern "C"
//{
// #include "lua.h"
// #include "lualib.h"
// #include "lauxlib.h"
//}
//
// TODO: check if these things are still needed for lua/luabind
//#undef MINMAX_H
//#undef min
//#undef max
@ -32,4 +25,322 @@
//#include "luabind/iterator_policy.hpp"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#include "tier0/memdbgon.h"
#if FF_DLL
// custom game modes made so damn easy
ConVar sv_mapluasuffix( "sv_mapluasuffix", "0", FCVAR_ARCHIVE, "Have a custom lua file (game mode) loaded when the map loads. If this suffix string is set, maps\\mapname__suffix__.lua (if it exists) is used instead of maps\\mapname.lua. To reset this cvar, make it 0.");
ConVar sv_luaglobalscript( "sv_globalluascript", "0", FCVAR_ARCHIVE, "Load a custom lua file globally after map scripts. Will overwrite map script. Will be loaded from maps\\globalscripts. To disable, set to 0.");
#endif
/////////////////////////////////////////////////////////////////////////////
using namespace luabind;
/////////////////////////////////////////////////////////////////////////////
// globals
CFFScriptManager _scriptman;
/////////////////////////////////////////////////////////////////////////////
CFFScriptManager::CFFScriptManager()
: L(NULL)
, m_isLoading(false)
, m_scriptCRC(0)
, m_ScriptExists(false)
{
}
/////////////////////////////////////////////////////////////////////////////
CFFScriptManager::~CFFScriptManager()
{
Shutdown();
}
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::Shutdown()
{
m_ScriptExists = false;
// shtutdown VM
if(L)
{
lua_close(L);
L = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::Init()
{
// shutdown VM if already running
if(L)
{
lua_close(L);
L = NULL;
}
// initialize VM
Msg("[SCRIPT] Attempting to start up the entity system...\n");
L = lua_open();
// no need to continue if VM failed to initialize
if(!L)
{
Msg("[SCRIPT] Unable to initialize Lua VM.\n");
return;
}
// load base libraries
luaopen_base(L);
luaopen_table(L);
luaopen_string(L);
luaopen_math(L);
// initialize luabind
luabind::open(L);
// initialize game-specific library
//FF_TODO: CFFLuaLib::Init(L);
Msg("[SCRIPT] Entity system initialization successful.\n");
}
#ifdef FF_DLL
void CFFScriptManager::LevelInit(const char* szMapName)
{
const char* default_luafile = "maps/default.lua";
//FF_TODO: VPROF_BUDGET("CFFScriptManager::LevelInit", VPROF_BUDGETGROUP_FF_LUA);
if(!szMapName)
return;
//FF_TODO: g_Disable_Timelimit = false;
// setup VM
Init();
// load lua files
BeginScriptLoad();
LoadFile(L, "maps/includes/base.lua");
char filename[256] = {0};
char globalscript_filename[256] = {0};
// Even though LoadFile already checks to see if the file exists, we'll check now so at least the default map lua file is loaded.
// That way servers can keep their suffix set without worrying about every map having whatever game mode they always want to use.
if ( sv_mapluasuffix.GetString()[0] != '0' )
{
Msg( "[SCRIPT] sv_mapluasuffix set to %s | finding maps\\%s__%s__.lua\n", sv_mapluasuffix.GetString(), szMapName, sv_mapluasuffix.GetString() );
if ( filesystem->FileExists( UTIL_VarArgs( "maps/%s__%s__.lua", szMapName, sv_mapluasuffix.GetString() ) ) )
{
Q_snprintf( filename, sizeof(filename), "maps/%s__%s__.lua", szMapName, sv_mapluasuffix.GetString() );
Msg( "[SCRIPT] maps\\%s__%s__.lua found\n", szMapName, sv_mapluasuffix.GetString() );
}
else
{
Msg( "[SCRIPT] maps\\%s__%s__.lua not found | reverting to maps\\%s.lua\n", szMapName, sv_mapluasuffix.GetString(), szMapName);
}
}
// Load global include script, overwriting previously loaded stuff per map
if( sv_luaglobalscript.GetString()[0] != '0' )
{
const char* scriptname = sv_luaglobalscript.GetString();
Msg("[SCRIPT] sv_luaglobalscript set to %s | loading global script maps maps\\globalscripts\\%s.lua\n", scriptname, scriptname );
if( filesystem->FileExists( UTIL_VarArgs( "maps/globalscripts/%s.lua", scriptname ) ) )
{
Q_snprintf( globalscript_filename, sizeof(globalscript_filename), "maps/globalscripts/%s.lua", scriptname );
Msg("[SCRIPT] maps\\globalscripts\\%s.lua found\n", scriptname );\
}
else
{
Msg("[SCRIPT] global script maps\\globalscripts\\%s.lua not found - nothing loaded post map lua.\n", scriptname );
}
}
if ( !filename[0] )
Q_snprintf( filename, sizeof(filename), "maps/%s.lua", szMapName );
//////////////////////////////////////////////////////////////////////////
// Try a precache, rumor has it this will cause the engine to send the lua files to clients
// FF_TODO: dexter - disabled for now, doesnt work anyway right?
//if(PRECACHE_LUA_FILES)
//{
// V_FixSlashes(filename);
// if(filesystem->FileExists(filename))
// {
// Util_AddDownload(filename);
// if(!engine->IsGenericPrecached(filename))
// engine->PrecacheGeneric(filename, true);
// }
// else // - if no map lua is found, send default (for testing mainly)
// {
// // no check - this file should *always* be there
// Util_AddDownload(default_luafile);
// if(!engine->IsGenericPrecached(default_luafile))
// engine->PrecacheGeneric(default_luafile, true);
// }
//
// // if we have a globalscript, precache it as well
// if( sv_luaglobalscript.GetString()[0] != '0' && globalscript_filename[0] )
// {
// V_FixSlashes(globalscript_filename);
// if(filesystem->FileExists(globalscript_filename))
// {
// Util_AddDownload(globalscript_filename);
// if(!engine->IsGenericPrecached(globalscript_filename))
// engine->PrecacheGeneric(globalscript_filename, true);
// }
// }
// //////////////////////////////////////////////////////////////////////////
// /*char testfile[] = {"maps/ff_dm.txt"};
// V_FixSlashes(testfile);
// if(filesystem->FileExists(testfile))
// {
// Util_AddDownload(testfile);
// if(!engine->IsGenericPrecached(testfile))
// engine->PrecacheGeneric(testfile, true);
// }*/
// //////////////////////////////////////////////////////////////////////////
//}
//////////////////////////////////////////////////////////////////////////
if(filesystem->FileExists(filename))
m_ScriptExists = LoadFile(L, filename);
else
{
Msg("[SCRIPT] File %s not found! Loaded fallback lua %s\n", filename, default_luafile);
m_ScriptExists = LoadFile(L, default_luafile);
}
// force loading global script in another call :/
if( sv_luaglobalscript.GetString()[0] != '0' && globalscript_filename[0] )
{
//BeginScriptLoad();
LoadFile(L, globalscript_filename);
//EndScriptLoad();
}
EndScriptLoad();
// spawn the helper entity
//FF_TODO: CFFEntitySystemHelper::Create();
}
#endif
#ifdef FF_DLL
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::LevelShutdown()
{
// shutdown the VM
if(L)
{
lua_close(L);
L = NULL;
}
}
#endif
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::OnScriptLoad(const char* szFileName,
const char* szFileContents)
{
// ignore the message if we are not still in the "loading" phase
if(!m_isLoading)
return;
// compute checksums of file contents
CRC32_ProcessBuffer(&m_scriptCRC,
szFileContents,
strlen(szFileContents));
}
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::BeginScriptLoad()
{
CRC32_Init(&m_scriptCRC);
m_isLoading = true;
}
/////////////////////////////////////////////////////////////////////////////
void CFFScriptManager::EndScriptLoad()
{
CRC32_Final(&m_scriptCRC);
m_isLoading = false;
}
/////////////////////////////////////////////////////////////////////////////
bool CFFScriptManager::LoadFile( lua_State *L, const char *filename)
{
//FF_TODO: VPROF_BUDGET( "CFFScriptManager::LoadFile", VPROF_BUDGETGROUP_FF_LUA );
// don't allow scripters to sneak in scripts after the initial load
if(!_scriptman.m_isLoading)
{
Warning("[SCRIPT] Loading of scripts after initial map load is not allowed.\n");
return false;
}
// open the file
Msg("[SCRIPT] Loading Lua File: %s\n", filename);
FileHandle_t hFile = filesystem->Open(filename, "rb", "MOD");
if (!hFile)
{
Warning("[SCRIPT] %s either does not exist or could not be opened.\n", filename);
return false;
}
// allocate buffer for file contents
int fileSize = filesystem->Size(hFile);
char *buffer = (char*)MemAllocScratch(fileSize + 1);
Assert(buffer);
// load file contents into a null-terminated buffer
filesystem->Read(buffer, fileSize, hFile);
buffer[fileSize] = 0;
filesystem->Close(hFile);
// preprocess script data
_scriptman.OnScriptLoad(filename, buffer);
// load script
int errorCode = luaL_loadbuffer(L, buffer, fileSize, filename);
// check if load was successful
if(errorCode)
{
if(errorCode == LUA_ERRSYNTAX )
{
// syntax error, lookup description for the error
const char *error = lua_tostring(L, -1);
if (error)
{
Warning("Error loading %s: %s\n", filename, error);
lua_pop( L, 1 );
}
else
Warning("Unknown Syntax Error loading %s\n", filename);
}
else
{
Msg("Unknown Error loading %s\n", filename);
}
return false;
}
// execute script. script at top scrop gets exectued
lua_pcall(L, 0, 0, 0);
Msg( "[SCRIPT] Successfully loaded %s\n", filename );
// cleanup
MemFreeScratch();
return true;
}

View File

@ -1,8 +1,113 @@
// ff_scriptman.h
#ifndef FF_SCRIPTMAN_H
#define FF_SCRIPTMAN_H
////
/////////////////////////////////////////////////////////////////////////////
// includes
#ifndef CHECKSUM_CRC_H
#include "checksum_crc.h"
#endif
#define PRECACHE_LUA_FILES 1
/////////////////////////////////////////////////////////////////////////////
// forward declarations
struct lua_State;
namespace luabind
{
namespace adl
{
class object;
}
}
class CFFLuaSC;
/////////////////////////////////////////////////////////////////////////////
class CFFScriptManager
{
public:
// 'structors
CFFScriptManager();
~CFFScriptManager();
public:
// inserts the lua file into the script environment
static bool LoadFile(lua_State*, const char* filePath);
public:
// loads the scripts for the level
void LevelInit(const char* szMapName);
// cleans up the scripts for the most recent level
void LevelShutdown();
private:
// initializes the script VM
void Init();
void Shutdown();
// surround code that loads scripts to capture crc checksum
// of the scripts that are loaded
void BeginScriptLoad();
void EndScriptLoad();
private:
// called when a script is loaded. internally computes the
// crc checksum of the file contents
void OnScriptLoad(const char* szFileName, const char* szFileContents);
public:
// sets a global variable in the script environment
static void SetVar( lua_State *L, const char *name, const char *value );
static void SetVar( lua_State *L, const char *name, int value );
static void SetVar( lua_State *L, const char *name, float value );
void SetVar(const char* name, const char* value);
void SetVar(const char* name, int value);
void SetVar(const char* name, float value);
// gets a global variable from the script environment
const char* GetString(const char* name);
int GetInt(const char* name);
float GetFloat(const char* name);
bool GetObject(CBaseEntity* pEntity, luabind::adl::object& outObject);
bool GetObject(const char* szTableName, luabind::adl::object& outObject);
bool GetFunction(CBaseEntity* pEntity,
const char* szFunctionName,
luabind::adl::object& outObject);
bool GetFunction(luabind::adl::object& tableObject,
const char* szFunctionName,
luabind::adl::object& outObject);
public:
int RunPredicates( CBaseEntity *pObject, CBaseEntity *pEntity, const char *szFunctionName = NULL);
bool RunPredicates_LUA( CBaseEntity *pObject, CFFLuaSC *pContext, const char *szFunctionName );
public:
// returns the lua interpreter
lua_State* GetLuaState() const { return L; }
bool ScriptExists( void ) const { return m_ScriptExists; }
// returns the crc checksum of the currently active script
CRC32_t GetScriptCRC() const { return m_scriptCRC; }
private:
// private data
lua_State* L; // lua VM
bool m_ScriptExists;
bool m_isLoading;
CRC32_t m_scriptCRC;
};
/////////////////////////////////////////////////////////////////////////////
// global externs
extern CFFScriptManager _scriptman;
/////////////////////////////////////////////////////////////////////////////
#endif