From 78ef63e24d7dddde74033a74512b1dd0313fc35d Mon Sep 17 00:00:00 2001 From: relt-1 <60782515+relt-1@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:17:56 +0200 Subject: [PATCH] more rundowns --- __main__.py | 112 ++- .../Contributing/API/Structs/QCFunc.html | 43 +- .../API/Structs/QModuleDefFunc.html | 43 +- .../Contributing/API/Structs/QReturn.html | 43 +- .../Contributing/API/Structs/QScriptArgs.html | 49 +- .../API/Structs/QScriptCallback.html | 49 +- .../API/Structs/QScriptClass.html | 49 +- .../API/Structs/QScriptClassCreator.html | 49 +- .../API/Structs/QScriptFunction.html | 49 +- .../API/Structs/QScriptObject.html | 49 +- .../Contributing/API/Structs/QType.html | 43 +- .../Contributing/API/Structs/QValue.html | 43 +- dst/QScript/Contributing/API/qscript.html | 43 +- dst/QScript/Contributing/Contributing.html | 43 +- .../Internals/IBaseScriptingInterface.html | 112 ++- dst/QScript/Contributing/Internals/QArgs.html | 49 +- .../Contributing/Internals/QCallback.html | 49 +- .../Contributing/Internals/QClass.html | 49 +- .../Contributing/Internals/QFunction.html | 49 +- .../Contributing/Internals/QInstance.html | 482 ++++++++++++ .../Contributing/Internals/QInterface.html | 49 +- dst/QScript/Contributing/Internals/QMod.html | 482 ++++++++++++ .../Contributing/Internals/QModule.html | 49 +- .../Contributing/Internals/QObject.html | 49 +- .../Contributing/Rundown/QScriptRundown1.html | 47 +- .../Contributing/Rundown/QScriptRundown2.html | 47 +- .../Contributing/Rundown/QScriptRundown3.html | 47 +- .../Contributing/Rundown/QScriptRundown4.html | 53 +- .../Contributing/Rundown/QScriptRundown5.html | 520 +++++++++++++ .../Contributing/Rundown/QScriptRundown6.html | 706 ++++++++++++++++++ dst/QScript/Introduction.html | 43 +- dst/QScript/Lua/Classes.html | 47 +- dst/QScript/Lua/Exports.html | 47 +- dst/QScript/Lua/Imports.html | 49 +- dst/QScript/Lua/Intro.html | 43 +- dst/QScript/Lua/Objects.html | 47 +- dst/QScript/Private_Members.html | 43 +- dst/QScript/Squirrel/Exports_And_Imports.html | 47 +- dst/QScript/Squirrel/Intro.html | 43 +- dst/QScript/Tutorial/Chapter1.html | 43 +- dst/QScript/Tutorial/Chapter2.html | 43 +- dst/index.html | 43 +- .../Internals/IBaseScriptingInterface.md | 67 +- .../Contributing/Internals/QInstance.md | 3 + src/QScript/Contributing/Internals/QMod.md | 3 + .../Contributing/Rundown/QScriptRundown4.md | 9 +- .../Contributing/Rundown/QScriptRundown5.md | 41 + .../Contributing/Rundown/QScriptRundown6.md | 227 ++++++ template.html | 31 +- 49 files changed, 4143 insertions(+), 322 deletions(-) create mode 100644 dst/QScript/Contributing/Internals/QInstance.html create mode 100644 dst/QScript/Contributing/Internals/QMod.html create mode 100644 dst/QScript/Contributing/Rundown/QScriptRundown5.html create mode 100644 dst/QScript/Contributing/Rundown/QScriptRundown6.html create mode 100644 src/QScript/Contributing/Internals/QInstance.md create mode 100644 src/QScript/Contributing/Internals/QMod.md create mode 100644 src/QScript/Contributing/Rundown/QScriptRundown5.md create mode 100644 src/QScript/Contributing/Rundown/QScriptRundown6.md diff --git a/__main__.py b/__main__.py index 1aed2a3..28a30f7 100644 --- a/__main__.py +++ b/__main__.py @@ -4,7 +4,7 @@ import os import re import shutil -mark = markdown2.Markdown(extras={"tables":True,"fenced-code-blocks":None,"code-friendly":True,"break-on-newline":True}) +mark = markdown2.Markdown(extras={"tables":True,"fenced-code-blocks":None,"code-friendly":True,"break-on-newline":True,"markdown-in-html":True}) rootpath = os.path.dirname(os.path.realpath(__file__)) src = rootpath+"/src/" @@ -69,43 +69,85 @@ def FindFile(name): return os.path.join(root[lensrc:],name) raise SyntaxError(f"Could not find file {name}!") + +def ConvertStrToHtml(rawmarkdown : str): + i = 0 + indentlevel = 0 + beginningdollar = -1 + tocut = -1 + dollarname = "" + while True: + if rawmarkdown[i:i+2] == '$_': + if indentlevel == 0: + tocut = i + dollarsnippet = rawmarkdown[i+2:] + if dollarsnippet.startswith("SMALL"): + dollarname = "SMALL" + #closelist.append("SMALL") + #rawmarkdown = rawmarkdown[:i]+""+rawmarkdown[i+7:] + i+=5 + elif dollarsnippet.startswith("FRAME"): + dollarname = "FRAME" + #closelist.append("FRAME") + #rawmarkdown = rawmarkdown[:i]+"
"+rawmarkdown[i+7:] + i+=5 + elif dollarsnippet.startswith("INLINEFRAME"): + dollarname = "INLINEFRAME" + #closelist.append("INLINEFRAME") + #rawmarkdown = rawmarkdown[:i]+"
"+rawmarkdown[i+13:] + i+=11 + beginningdollar = i+2 + indentlevel += 1 + i+=2 + elif rawmarkdown[i:i+2] == "_$": + indentlevel -= 1 + if indentlevel == 0 and beginningdollar != -1: + snippet = ConvertStrToHtml(rawmarkdown[beginningdollar:i].strip()).strip() + if dollarname == "SMALL": + snippet = ""+snippet.strip().replace("

","").replace("

","")+"
" + elif dollarname == "FRAME": + snippet = "
"+snippet+"
" + elif dollarname == "INLINEFRAME": + snippet = "
"+snippet+"
" + rawmarkdown = rawmarkdown[:tocut]+snippet+rawmarkdown[i+2:] + beginningdollar = -1 + i = tocut+len(snippet)-3 + i+=2 + i+=1 + if i>len(rawmarkdown): + break + links = re.findall(r'\[\[[^\[^\]]+\]\]', rawmarkdown) + for link in links: + if os.path.exists(os.path.join(src,link[2:-2]+".md")): + rawmarkdown = rawmarkdown.replace(link, ""+link[2:-2].split("/")[-1]+"") + else: + foundpath = FindFile(link[2:-2]+".md").replace(".md","").replace("\\","/") + rawmarkdown = rawmarkdown.replace(link, ""+foundpath.split("/")[-1]+"") + embeds = re.findall(r'\{\{[^\{^\}]+\}\}', rawmarkdown) + for embed in embeds: + if os.path.exists(os.path.join(src,embed[2:-2]+".embed.md")): + rawmarkdown = rawmarkdown.replace(embed, ConvertToHtml(src+embed[2:-2]+".embed.md")) + else: + foundpath = FindFile(embed[2:-2]+".embed.md").replace("\\","/") + rawmarkdown = rawmarkdown.replace(embed, ConvertToHtml(src+foundpath)) + links = re.findall(r'\[[^\[^\]]+\]\[[^\[^\]]+\]',rawmarkdown) + for link in links: + name = link[1:].split("]",1)[0] + href = link[1:].split("[",1)[1].split("]",1)[0] + if(href.startswith("http://") or href.startswith("https://")): + rawmarkdown = rawmarkdown.replace(link, ""+name+"") + elif os.path.exists(os.path.join(src,href+".md")): + rawmarkdown = rawmarkdown.replace(link, ""+name+"") + else: + foundpath = FindFile(href+".md").replace(".md","").replace("\\","/") + rawmarkdown = rawmarkdown.replace(link, ""+name+"") + converted = mark.convert(rawmarkdown) + return converted + def ConvertToHtml(fpath): with open(fpath,"r") as f: rawmarkdown = f.read().replace("\r\n","\n") - smalls = re.findall(r"^\$\_SMALL\s[\s\S]+?\s\_\$$",rawmarkdown,re.MULTILINE) - for small in smalls: - rawmarkdown = rawmarkdown.replace(small, ""+small[8:-3]+"") - frames = re.findall(r"^\$_FRAME\s[\S\s]+?\s_\$$",rawmarkdown,re.MULTILINE) - for frame in frames: - framed_string = frame[8:-3] - rawmarkdown = rawmarkdown.replace(frame,f"
{framed_string}
") - links = re.findall(r'\[\[[^\[^\]]+\]\]', rawmarkdown) - for link in links: - if os.path.exists(os.path.join(src,link[2:-2]+".md")): - rawmarkdown = rawmarkdown.replace(link, ""+link[2:-2].split("/")[-1]+"") - else: - foundpath = FindFile(link[2:-2]+".md").replace(".md","").replace("\\","/") - rawmarkdown = rawmarkdown.replace(link, ""+foundpath.split("/")[-1]+"") - embeds = re.findall(r'\{\{[^\{^\}]+\}\}', rawmarkdown) - for embed in embeds: - if os.path.exists(os.path.join(src,embed[2:-2]+".embed.md")): - rawmarkdown = rawmarkdown.replace(embed, ConvertToHtml(src+embed[2:-2]+".embed.md")) - else: - foundpath = FindFile(embed[2:-2]+".embed.md").replace("\\","/") - rawmarkdown = rawmarkdown.replace(embed, ConvertToHtml(src+foundpath)) - links = re.findall(r'\[[^\[^\]]+\]\[[^\[^\]]+\]',rawmarkdown) - for link in links: - name = link[1:].split("]",1)[0] - href = link[1:].split("[",1)[1].split("]",1)[0] - if(href.startswith("http://") or href.startswith("https://")): - rawmarkdown = rawmarkdown.replace(link, ""+name+"") - elif os.path.exists(os.path.join(src,href+".md")): - rawmarkdown = rawmarkdown.replace(link, ""+name+"") - else: - foundpath = FindFile(href+".md").replace(".md","").replace("\\","/") - rawmarkdown = rawmarkdown.replace(link, ""+name+"") - converted = mark.convert(rawmarkdown) - return converted + return ConvertStrToHtml(rawmarkdown) template = template.replace("@DOCUMENTLIST",str(documentlist)).replace("@NAMELIST",str(namelist)) diff --git a/dst/QScript/Contributing/API/Structs/QCFunc.html b/dst/QScript/Contributing/API/Structs/QCFunc.html index 05fac5a..5415f3a 100644 --- a/dst/QScript/Contributing/API/Structs/QCFunc.html +++ b/dst/QScript/Contributing/API/Structs/QCFunc.html @@ -2,8 +2,8 @@ SourceBox Wiki + + +
+ + +
+
+ +

QInstance

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +
\ No newline at end of file diff --git a/dst/QScript/Contributing/Internals/QInterface.html b/dst/QScript/Contributing/Internals/QInterface.html index a2d270c..18af85e 100644 --- a/dst/QScript/Contributing/Internals/QInterface.html +++ b/dst/QScript/Contributing/Internals/QInterface.html @@ -2,8 +2,8 @@ SourceBox Wiki + + +
+ + +
+
+ +

QMod

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +

This page has NO CONTENT! You should write some by making a pull request on our GitHub repository

+ +
\ No newline at end of file diff --git a/dst/QScript/Contributing/Internals/QModule.html b/dst/QScript/Contributing/Internals/QModule.html index 1539bfb..59f37ab 100644 --- a/dst/QScript/Contributing/Internals/QModule.html +++ b/dst/QScript/Contributing/Internals/QModule.html @@ -2,8 +2,8 @@ SourceBox Wiki + + +
+ + +
+
+ +

QScript Rundown Page 5

+ +

Scripting language interfaces inherit from IBaseScriptingInterface. While there is not one way of implementing the interface, it is best to learn how each one works. Let's start with Lua.

+ +

When the game starts up, it will initialize all DLLs. During initialization, it will call the Connect() function which you use to connect to other DLLs. Lua connects to tier1, filesystem, and qscript itself. It also sets the current_interface variable to this.

+ +

luainterface/luainterface.cpp

+ +
+
bool CLuaInterface::Connect(CreateInterfaceFn factory)
+{
+    ConnectTier1Libraries(&factory, 1);
+    ConVar_Register();
+    g_pFullFileSystem = (IFileSystem*)factory(FILESYSTEM_INTERFACE_VERSION, NULL);
+    g_pQScript = (IQScript*)factory(QSCRIPT_INTERFACE_VERSION, NULL);
+    current_interface = this;
+    return true;
+}
+
+
+ +

You are expected to return true if nothing went wrong during connection.

+ +

After that, other DLLs will call to QScript add their modules. That happens during the Init() phase.
+After each module is loaded (at PostInit()), QScript will call ImportModules() with the modules CUtlVector<QModule*>* you can safely save it to the interface object if you dont want to do anything during import.

+ +

luainterface/luainterface.cpp

+ +
+
void CLuaInterface::ImportModules(CUtlVector<QModule*>* modules)
+{
+    m_modules = modules;
+}
+
+
+ +

After that, there come the mods. QScript will just give you the file path of the mod along with the QMod itself. You must check whether the extension matches your scripting language. If it does not, return 0, but if it does, load the file yourself and return a QInstance pointer.

+ +

This is where things start getting complicated.

+ +
+ + + + + +
\ No newline at end of file diff --git a/dst/QScript/Contributing/Rundown/QScriptRundown6.html b/dst/QScript/Contributing/Rundown/QScriptRundown6.html new file mode 100644 index 0000000..66c94f3 --- /dev/null +++ b/dst/QScript/Contributing/Rundown/QScriptRundown6.html @@ -0,0 +1,706 @@ + +SourceBox Wiki + + + + +
+ + +
+
+ +

QScript Rundown Page 6

+ +

In Lua, the ExecuteLua() function does what it says. It executes a Lua script, while it may sound simple, a lot comes into that.

+ +

I figured that it may be easiest to just go through the function seciton by section.

+ +

luainterface/luainterface.cpp

+ +

+ +
lua_State* L = luaL_newstate();
+
+ +
+ +
+ +

Simply create a new lua state.

+ +
+ +

luainterface/luainterface.cpp

+ +
+
QInstance* ins = new QInstance();
+ins->env = L;
+ins->lang = (IBaseScriptingInterface*)current_interface;
+
+
+ +
+ +

Create a new QInstance which contains the current language interface and Lua instance

+ +
+ +

luainterface/luainterface.cpp

+ +
+
luaL_openlibs(L);
+
+
+ +
+ +

Which is:

+ +

lua/linit.c

+ +
+
static const luaL_Reg loadedlibs[] = {
+  {LUA_GNAME, luaopen_base},
+  {LUA_COLIBNAME, luaopen_coroutine},
+  {LUA_TABLIBNAME, luaopen_table},
+  {LUA_STRLIBNAME, luaopen_string},
+  {LUA_MATHLIBNAME, luaopen_math},
+  {LUA_UTF8LIBNAME, luaopen_utf8},
+  {NULL, NULL}
+};
+
+
+LUALIB_API void luaL_openlibs (lua_State *L) {
+  const luaL_Reg *lib;
+  /* "require" functions from 'loadedlibs' and set results to global table */
+  for (lib = loadedlibs; lib->func; lib++) {
+    luaL_requiref(L, lib->name, lib->func, 1);
+    lua_pop(L, 1);  /* remove lib */
+  }
+}
+
+ +
+ +
+ +

You can notice that it does not include every library, thats because QScript values safety and stability. Some libraries allow for bad things to happen, like unrestricted file access.

+ +

luainterface/luainterface.cpp

+ +
+
luaL_newmetatable(L, "QSCRIPT_OBJECT");
+lua_pushstring(L, "__index");
+lua_pushcclosure(L, Lua_QScript_Index, 0);
+lua_settable(L, -3);
+
+
+ +
+ +

Here the QSCRIPT_OBJECT metatable starts being defined and here is where things start to get a little wild.
+The Lua_QScript_Index function is responsible for getting a value or method from the QObject.

+ +

luainterface/luainterface.cpp

+ +
+
int Lua_QScript_Index(lua_State* L)
+{
+    QObject* obj;
+    Lua_Userdata* usr;
+    if (!(usr = (Lua_Userdata*)luaL_checkudata(L, 1, "QSCRIPT_OBJECT")))
+        return 0;
+    obj = usr->obj;
+    const char* name = lua_tostring(L, 2);
+    int index = g_pQScript->GetObjectValueIndex((QScriptObject)obj, name);
+    if (index == -1)
+    {
+        index = g_pQScript->GetObjectMethodIndex((QScriptObject)obj, name);
+        if (index == -1)
+            return 0;
+        QFunction* func = (QFunction*)g_pQScript->GetObjectMethod((QScriptObject)obj, index);
+        usr = (Lua_Userdata*)lua_newuserdata(L, sizeof(Lua_Userdata));
+        usr->func = func;
+        luaL_setmetatable(L, "QSCRIPT_FUNCTION");
+        return 1;
+    }
+    QValue val = g_pQScript->GetObjectValue((QScriptObject)obj, index);
+    QType type = g_pQScript->GetObjectValueType((QScriptObject)obj, index);
+    switch (type)
+    {
+    case QType_Int:
+        lua_pushinteger(L, val.value_int);
+        return 1;
+    case QType_String:
+        lua_pushstring(L, val.value_string);
+        return 1;
+    case QType_Float:
+        lua_pushnumber(L, val.value_float);
+        return 1;
+    case QType_Bool:
+        lua_pushboolean(L, val.value_bool);
+        return 1;
+    default:
+        lua_pushnil(L);
+        return 1;
+    }
+}
+
+ +
+ +
+ +

You can notice that this is just a regular Lua C function. And the way it is pushed to the Lua stack suggests so... You will see why im pointing this out later.
+The function itself first checks the userdata and gets the wanted value name from the second argument.
+It searches first through the values, and then the methods. If any one is found, the appropriate conversion is performed.

+ +

Something interesting that happens here is this snippet:

+ +

luainterface/luainterface.cpp

+ +
+
QFunction* func = (QFunction*)g_pQScript->GetObjectMethod((QScriptObject)obj, index);
+usr = (Lua_Userdata*)lua_newuserdata(L, sizeof(Lua_Userdata));
+usr->func = func;
+luaL_setmetatable(L, "QSCRIPT_FUNCTION");
+
+
+ +

You can notice it creating a Lua_Userdata struct with the userdata, why is that?

+ +

The Lua_Userdata is more of a union pointer than a struct, this is the definition of it:

+ +

luainterface/luainterface.cpp

+ +
+
struct Lua_Userdata
+{
+    union {
+        QObject* obj;
+        QClass* cls;
+        QClassCreator* creator;
+        QFunction* func;
+    };
+};
+
+
+ +

You can notice that it can store multiple types, and there is not even a separate variable that says which one it is!
+The reason, is that we already have that variable... it's the metatable!

+ +

We already know if the userdata has a specific metatable, that the pointer stored in the userdata is what we want.

+ +
+ +In fact, here are all the Lua functions that get included. + +
+ +
+ +
+ +

luainterface/luainterface.cpp

+ +
+
int Lua_QScript_New_Index(lua_State* L)
+{
+    QObject* obj;
+    Lua_Userdata* usr;
+    if (!(usr = (Lua_Userdata*)luaL_checkudata(L, 1, "QSCRIPT_OBJECT")))
+        return 0;
+    obj = usr->obj;
+    const char* name = lua_tostring(L, 2);
+    int index = g_pQScript->GetObjectValueIndex((QScriptObject)obj, name);
+    if (index == -1)
+        return 0;
+    QType type = g_pQScript->GetObjectValueType((QScriptObject)obj, index);
+    QValue val;
+    switch (type) // TODO : error check the type
+    {
+    case QType_Int:
+        val.value_int = lua_tointeger(L, 3);
+        g_pQScript->SetObjectValue((QScriptObject)obj, index, val);
+        return 0;
+    case QType_String:
+        g_pQScript->SetObjectString((QScriptObject)obj, index, lua_tostring(L,3));
+        return 0;
+    case QType_Float:
+        val.value_float = lua_tonumber(L, 3);
+        g_pQScript->SetObjectValue((QScriptObject)obj, index, val);
+        return 0;
+    case QType_Bool:
+        val.value_bool = lua_toboolean(L, 3);
+        g_pQScript->SetObjectValue((QScriptObject)obj, index, val);
+        return 0;
+    default:
+        return 0;
+    }
+}
+
+
+ +
\ No newline at end of file diff --git a/dst/QScript/Introduction.html b/dst/QScript/Introduction.html index 47ab64e..1faede4 100644 --- a/dst/QScript/Introduction.html +++ b/dst/QScript/Introduction.html @@ -2,8 +2,8 @@ SourceBox Wiki