diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 6b386d7f..33c052af 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -13,9 +13,7 @@ #include "characterset.h" #include "isaverestore.h" #include "gamerules.h" -#ifdef _WIN32 -//#include "vscript_client_nut.h" -#endif +#include "vscript_client.nut" #ifdef MAPBASE_VSCRIPT #include "c_world.h" #include "proxyentity.h" @@ -405,13 +403,13 @@ bool VScriptClientInit() IGameSystem::RegisterVScriptAllSystems(); RegisterSharedScriptFunctions(); -#else - if ( scriptLanguage == SL_SQUIRREL ) - { - //g_pScriptVM->Run( g_Script_vscript_client ); - } #endif + if (scriptLanguage == SL_SQUIRREL) + { + g_pScriptVM->Run( g_Script_vscript_client ); + } + VScriptRunScript( "mapspawn", false ); VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" ); diff --git a/sp/src/game/client/vscript_client.nut b/sp/src/game/client/vscript_client.nut index 2efd3417..5fce6ff5 100644 --- a/sp/src/game/client/vscript_client.nut +++ b/sp/src/game/client/vscript_client.nut @@ -1,3 +1,4 @@ +static char g_Script_vscript_client[] = R"vscript( //========== Copyright © 2008, Valve Corporation, All rights reserved. ======== // // Purpose: @@ -17,3 +18,5 @@ function IncludeScript( name, scope = null ) } return ::DoIncludeScript( name, scope ); } + +)vscript"; \ No newline at end of file diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 0e2e6d19..7ab8c3d3 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -15,9 +15,7 @@ #include "sceneentity.h" // for exposing scene precache function #include "isaverestore.h" #include "gamerules.h" -#ifdef _WIN32 -//#include "vscript_server_nut.h" -#endif +#include "vscript_server.nut" #ifdef MAPBASE_VSCRIPT #include "world.h" #endif @@ -555,13 +553,13 @@ bool VScriptServerInit() IGameSystem::RegisterVScriptAllSystems(); RegisterSharedScriptFunctions(); -#else - if ( scriptLanguage == SL_SQUIRREL ) - { - //g_pScriptVM->Run( g_Script_vscript_server ); - } #endif + if (scriptLanguage == SL_SQUIRREL) + { + g_pScriptVM->Run( g_Script_vscript_server ); + } + VScriptRunScript( "mapspawn", false ); VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" ); diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index 5f6c285a..aefa9b24 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -1,3 +1,4 @@ +static char g_Script_vscript_server[] = R"vscript( //========== Copyright © 2008, Valve Corporation, All rights reserved. ======== // // Purpose: @@ -38,7 +39,7 @@ function __ReplaceClosures( script, scope ) local tempParent = { getroottable = function() { return null; } }; local temp = { runscript = script }; - delegate tempParent : temp; + temp.set_delegate(tempParent); temp.runscript() foreach( key,val in temp ) @@ -125,3 +126,4 @@ function __DumpScope( depth, table ) } } +)vscript"; \ No newline at end of file diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 398b136c..c964fc88 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -344,7 +344,7 @@ public: private: } g_ScriptConvarLookup; -BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarLookup, "Convars", SCRIPT_SINGLETON "Provides an interface for getting and setting convars." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarLookup, "CConvars", SCRIPT_SINGLETON "Provides an interface for getting and setting convars." ) #ifndef CLIENT_DLL DEFINE_SCRIPTFUNC( GetClientConvarValue, "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." ) #endif diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 859ce420..abb4febe 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -199,6 +199,7 @@ public: HSQUIRRELVM vm_ = nullptr; HSQOBJECT lastError_; HSQOBJECT vectorClass_; + HSQOBJECT regexpClass_; }; SQUserPointer TYPETAG_VECTOR = "VectorTypeTag"; @@ -1112,6 +1113,66 @@ void errorfunc(HSQUIRRELVM SQ_UNUSED_ARG(v), const SQChar* format, ...) va_end(args); } +const char * ScriptDataTypeToName(ScriptDataType_t datatype) +{ + switch (datatype) + { + case FIELD_VOID: return "void"; + case FIELD_FLOAT: return "float"; + case FIELD_CSTRING: return "string"; + case FIELD_VECTOR: return "Vector"; + case FIELD_INTEGER: return "int"; + case FIELD_BOOLEAN: return "bool"; + case FIELD_CHARACTER: return "char"; + case FIELD_HSCRIPT: return "handle"; + default: return ""; + } +} + +void RegisterDocumentation(HSQUIRRELVM vm, const ScriptFuncDescriptor_t& pFuncDesc, ScriptClassDesc_t* pClassDesc = nullptr) +{ + SquirrelSafeCheck safeCheck(vm); + + if (pFuncDesc.m_pszDescription && pFuncDesc.m_pszDescription[0] == SCRIPT_HIDE[0]) + return; + + char name[256] = ""; + + if (pClassDesc) + { + V_strcat_safe(name, pClassDesc->m_pszScriptName); + V_strcat_safe(name, "::"); + } + + V_strcat_safe(name, pFuncDesc.m_pszScriptName); + + + char signature[256] = ""; + V_snprintf(signature, sizeof(signature), "%s %s(", ScriptDataTypeToName(pFuncDesc.m_ReturnType), name); + + for (int i = 0; i < pFuncDesc.m_Parameters.Count(); ++i) + { + if (i != 0) + V_strcat_safe(signature, ", "); + + V_strcat_safe(signature, ScriptDataTypeToName(pFuncDesc.m_Parameters[i])); + } + + V_strcat_safe(signature, ")"); + + // RegisterHelp(name, signature, description) + sq_pushroottable(vm); + sq_pushstring(vm, "RegisterHelp", -1); + sq_get(vm, -2); + sq_remove(vm, -2); + sq_pushroottable(vm); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, signature, -1); + sq_pushstring(vm, pFuncDesc.m_pszDescription ? pFuncDesc.m_pszDescription : "", -1); + sq_call(vm, 4, SQFalse, SQFalse); + sq_pop(vm, 1); +} + bool SquirrelVM::Init() { @@ -1149,6 +1210,33 @@ bool SquirrelVM::Init() sqstd_seterrorhandlers(vm_); + { + // Unfortunately we can not get the pattern from a regexp instance + // so we need to wrap it with our own to get it. + if (Run(R"script( + class regexp extends regexp + { + constructor(pattern) + { + base.constructor(pattern); + pattern_ = pattern; + } + pattern_=""; + } + )script") == SCRIPT_ERROR) + { + this->Shutdown(); + return false; + } + + sq_resetobject(®expClass_); + sq_pushstring(vm_, "regexp", -1); + sq_rawget(vm_, -2); + sq_getstackobj(vm_, -1, ®expClass_); + sq_addref(vm_, ®expClass_); + sq_pop(vm_, 1); + } + sq_pop(vm_, 1); } @@ -1194,13 +1282,67 @@ bool SquirrelVM::Init() chain = []; } + DocumentedFuncs <- {} + + function RegisterHelp(name, signature, description) + { + if (description.len() && description[0] == '#') + { + // This is an alias function, could use split() if we could guarantee + // that ':' would not occur elsewhere in the description and Squirrel had + // a convience join() function -- It has split() + local colon = description.find(":"); + if (colon == null) + colon = description.len(); + local alias = description.slice(1, colon); + description = description.slice(colon + 1); + name = alias; + signature = null; + } + DocumentedFuncs[name] <- [signature, description]; + } + + function PrintHelp(pattern = "*") + { + local foundMatches = false; + foreach(name, doc in DocumentedFuncs) + { + if (pattern == "*" || name.tolower().find(pattern.tolower()) != null) + { + foundMatches = true; + printl("Function: " + name); + if (doc[0] == null) + { + // Is an aliased function + print("Signature: function " + name + "("); + foreach(k,v in this[name].getinfos()["parameters"]) + { + if (k == 0 && v == "this") continue; + if (k > 1) print(", "); + print(v); + } + printl(")"); + } + else + { + printl("Signature: " + doc[0]); + } + if (doc[1].len()) + printl("Description: " + doc[1]); + print("\n"); + } + } + + if (!foundMatches) + printl("Pattern " + pattern + " not found"); + } + )script") != SCRIPT_DONE) { this->Shutdown(); return false; } - return true; } @@ -1208,6 +1350,9 @@ void SquirrelVM::Shutdown() { if (vm_) { + sq_release(vm_, &vectorClass_); + sq_release(vm_, ®expClass_); + sq_close(vm_); vm_ = nullptr; } @@ -1516,6 +1661,8 @@ void SquirrelVM::RegisterFunction(ScriptFunctionBinding_t* pScriptFunction) sq_newslot(vm_, -3, isStatic); sq_pop(vm_, 1); + + RegisterDocumentation(vm_, pScriptFunction->m_desc); } bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc) @@ -1587,6 +1734,8 @@ bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc) sq_setparamscheck(vm_, scriptFunction.m_desc.m_Parameters.Count() + 1, typemask); bool isStatic = false; sq_newslot(vm_, -3, isStatic); + + RegisterDocumentation(vm_, scriptFunction.m_desc, pClassDesc); } sq_pushstring(vm_, pClassDesc->m_pszScriptName, -1); @@ -2164,18 +2313,9 @@ void SquirrelVM::WriteObject(CUtlBuffer* pBuffer, WriteStateMap& writeState, SQI // so we just check against the only class we need to deal with at the moment // which is "regexp" const char* builtinName = nullptr; + if (_class(obj) == _class(regexpClass_)) { - HSQOBJECT builtin; - sq_resetobject(&builtin); - sq_pushroottable(vm_); - sq_pushstring(vm_, "regexp", -1); - sq_rawget(vm_, -2); - sq_getstackobj(vm_, -1, &builtin); - sq_pop(vm_, 2); - if (_class(obj) == _class(builtin)) - { - builtinName = "regexp"; - } + builtinName = "regexp"; } if (builtinName) @@ -2240,6 +2380,16 @@ void SquirrelVM::WriteObject(CUtlBuffer* pBuffer, WriteStateMap& writeState, SQI WriteObject(pBuffer, writeState, -1); sq_pop(vm_, 1); + if (_instance(obj)->_class == _class(regexpClass_)) + { + sq_push(vm_, idx); + sq_pushstring(vm_, "pattern_", -1); + sq_rawget(vm_, -2); + WriteObject(pBuffer, writeState, -1); + sq_pop(vm_, 2); + break; + } + { // HACK: No way to get the default values part from accessing the class directly SQUnsignedInteger nvalues = _instance(obj)->_class->_defaultvalues.size(); @@ -2613,15 +2763,29 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState) ReadObject(pBuffer, readState); + HSQOBJECT klass; + sq_resetobject(&klass); + sq_getstackobj(vm_, -1, &klass); + if (_class(klass) == _class(regexpClass_)) + { + sq_pushnull(vm_); + ReadObject(pBuffer, readState); + sq_call(vm_, 2, SQTrue, SQFalse); + + sq_getstackobj(vm_, -1, obj); + sq_addref(vm_, obj); + + sq_remove(vm_, -2); + + break; + } + SQUserPointer typetag; sq_gettypetag(vm_, -1, &typetag); if (typetag && typetag != TYPETAG_VECTOR && ((ScriptClassDesc_t*)typetag)->m_pszDescription[0] == SCRIPT_SINGLETON[0]) { - HSQOBJECT klass; - sq_resetobject(&klass); - sq_getstackobj(vm_, -1, &klass); sq_poptop(vm_); Assert(sq_isclass(klass));