diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0b34454 --- /dev/null +++ b/.clang-format @@ -0,0 +1,32 @@ +BasedOnStyle: Google +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: Always +ReflowComments: false +AccessModifierOffset: -4 +IncludeBlocks: Preserve +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakBeforeBinaryOperators: NonAssignment +SpaceInEmptyBlock: true +SpacesBeforeTrailingComments: 1 +SpaceAfterTemplateKeyword: true +IndentAccessModifiers: false +IndentRequiresClause: false +IndentCaseLabels: false +IndentPPDirectives: BeforeHash +InsertNewlineAtEOF: true +BinPackArguments: true +BinPackParameters: true +PackConstructorInitializers: BinPack +NamespaceIndentation: All +Cpp11BracedListStyle: false +FixNamespaceComments: false +AlignAfterOpenBracket: DontAlign +AlignOperands: false +AllowShortLoopsOnASingleLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowAllArgumentsOnNextLine: false diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..54de247 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +Checks: > + -* + clang-analyzer-* + +WarningsAsErrors: "*" +FormatStyle: file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6133a26 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/CMakeLists.txt b/CMakeLists.txt index 37bbd4d..8f92d33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,10 @@ else() endif() enable_language(ASM_NASM) +# CMake +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +include(ClangTools) + # CPack set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..6b76d1c --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,25 @@ +{ + "version": 7, + "cmakeMinimumRequired": { + "major": 3, + "minor": 27, + "patch": 0 + }, + "configurePresets": [ + { + "name": "windows", + "generator": "MinGW Makefiles", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": ".vcpkg/windows.cmake", + "COD4X": true + } + }, + { + "name": "linux", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": ".vcpkg/linux.cmake", + "COD4X": true + } + } + ] +} diff --git a/README.md b/README.md index f3d8bbb..60616f3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # CGSC [![Checks](https://img.shields.io/github/checks-status/Iswenzz/CGSC/master?logo=github)](https://github.com/Iswenzz/CGSC/actions) @@ -7,20 +6,23 @@ This Call of Duty 4X source extension adds new utilities to extend the server and the creation of new plugins. Such things include new functions to get data types that the original source doesn't offer, the ability to call functions defined in GSC from the C files and async workers for expensive operations on the server. To use this extension you must add the CGSC files included in the release section to the `/src/CGSC` folder, and then compile the CoD4X server source. More detailed instructions can be found towards the bottom of this document. -``Note: Depending on the version of Call of Duty 4X that you're running, some features of CGSC may not be available.`` +`Note: Depending on the version of Call of Duty 4X that you're running, some features of CGSC may not be available.` ## Documentation -* [API](https://github.com/Iswenzz/CGSC/blob/master/docs/api.md) -* [Async](https://github.com/Iswenzz/CGSC/blob/master/docs/async.md) -* [Extensions](https://github.com/Iswenzz/CGSC/blob/master/docs/extensions.md) + +- [API](https://github.com/Iswenzz/CGSC/blob/master/docs/api.md) +- [Async](https://github.com/Iswenzz/CGSC/blob/master/docs/async.md) +- [Extensions](https://github.com/Iswenzz/CGSC/blob/master/docs/extensions.md) ## Instructions -In order to use this extension, just download the archived file down below, and extract it to the cod4x server's ``src/CGSC`` directory, then copy the makefile snippet below and paste it before the default rule. -Then simply build the library with the build instructions and recompile the cod4x source with ``make``. + +In order to use this extension, just download the archived file down below, and extract it to the cod4x server's `src/CGSC` directory, then copy the makefile snippet below and paste it before the default rule. +Then simply build the library with the build instructions and recompile the cod4x source with `make`. ### **[Download](https://github.com/Iswenzz/CGSC/releases)** ### **Snippet to add to the cod4x source's makefile before the first target:** + ```makefile ################################## # CGSC @@ -41,20 +43,23 @@ $(OBJ_DIR)/%.o: $(CGSC_DIR)/asm/%.asm ``` ## Building (Linux) + _Pre-Requisites:_ - sudo dpkg --add-architecture i386 - sudo apt-get update - sudo apt-get install nasm:i386 build-essential gcc-multilib g++-multilib + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install nasm:i386 build-essential gcc-multilib g++-multilib _Build Command:_ mkdir build && cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=.vcpkg/linux.cmake -DCOD4X=True + cmake .. --preset linux cmake --build . ## Building (Windows) + _Pre-Requisites:_ + 1. Windows [MinGW i686-8.1.0-win32-dwarf-msvcrt](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-win32/dwarf/i686-8.1.0-release-win32-dwarf-rt_v6-rev0.7z) 2. [NASM](https://www.nasm.us/) 3. [CMake](https://cmake.org/) and [vcpkg](https://vcpkg.io/en/). @@ -62,11 +67,13 @@ _Pre-Requisites:_ _Build Command:_ mkdir build && cd build - cmake .. -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=.vcpkg/windows.cmake -DCOD4X=True + cmake .. --preset windows cmake --build . ## Package + This package is available for use via [vcpkg-registry](https://github.com/Iswenzz/vcpkg-registry). ## Contributors: -***Note:*** If you would like to contribute to this repository, feel free to send a pull request, and I will review your code. Also feel free to post about any problems that may arise in the issues section of the repository. + +**_Note:_** If you would like to contribute to this repository, feel free to send a pull request, and I will review your code. Also feel free to post about any problems that may arise in the issues section of the repository. diff --git a/cgsc.h b/cgsc.h index 9d943d5..b16bb88 100644 --- a/cgsc.h +++ b/cgsc.h @@ -1,7 +1,8 @@ #pragma once #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #ifdef _WIN32 @@ -42,8 +43,8 @@ extern "C" { /// @brief Adds the definition for cod4x server and plugin export. #define EXPORT(type, definition) \ -type definition; \ -type Plugin_##definition + type definition; \ + type Plugin_##definition #define CLASS_NUM_COUNT sizeof(gScrClassMap) / sizeof(gScrClassMap[0]) #define DEBUG_REFCOUNT_SIZE 65536 @@ -73,6 +74,7 @@ type Plugin_##definition #define IsObject(var) ((var->w.type & VAR_MASK) >= VAR_THREAD) #define IsObjectVal(var) ((var->type & VAR_MASK) >= VAR_THREAD) +// clang-format off enum GSCTypeFlag { FLAG_UNDEFINED = 1, @@ -107,12 +109,12 @@ enum GSCTypeFlag struct scrStringDebugGlob_t { - volatile int refCount[DEBUG_REFCOUNT_SIZE]; - volatile int totalRefCount; - int ignoreLeaks; + volatile int refCount[DEBUG_REFCOUNT_SIZE]; + volatile int totalRefCount; + int ignoreLeaks; }; -struct __attribute__((aligned (64))) scrVarGlob_t +struct __attribute__((aligned(64))) scrVarGlob_t { VariableValueInternal* variableList; }; @@ -120,13 +122,14 @@ struct __attribute__((aligned (64))) scrVarGlob_t typedef struct { uint32_t length; - VariableValue *items; + VariableValue* items; } VariableValueArray; +// clang-format on -#include "sys/compatibility.h" -#include "sys/async.h" #include "extensions/functions.h" #include "extensions/variables.h" +#include "sys/async.h" +#include "sys/compatibility.h" #include "utils/utils.h" #ifdef __cplusplus diff --git a/cmake/ClangTools.cmake b/cmake/ClangTools.cmake new file mode 100644 index 0000000..1bd646b --- /dev/null +++ b/cmake/ClangTools.cmake @@ -0,0 +1,12 @@ +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_custom_target(clang-tidy + COMMAND find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -exec clang-tidy --config-file=.clang-tidy {} + + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +add_custom_target(clang-format + COMMAND find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -exec clang-format -style=file -i --verbose {} + + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +set_target_properties(clang-tidy PROPERTIES FOLDER Clang) +set_target_properties(clang-format PROPERTIES FOLDER Clang) diff --git a/cod4x.h b/cod4x.h index 54b529b..093b84c 100644 --- a/cod4x.h +++ b/cod4x.h @@ -1,20 +1,20 @@ -#pragma once -#define COD4X - -#ifndef PLUGIN_HANDLER_VERSION_MAJOR - #include -#endif - -#define CHECK_UNSUPPORTED(condition) \ -if (CGSC_UnsupportedMessage(condition, "CGSC: This feature is unsupported in this version.")) \ -{ \ - Scr_AddUndefined(); \ - return; \ -} - -#include -#include -#include -#include - -#undef ASSERT +#pragma once +#define COD4X + +#ifndef PLUGIN_HANDLER_VERSION_MAJOR + #include +#endif + +#define CHECK_UNSUPPORTED(condition) \ + if (CGSC_UnsupportedMessage(condition, "CGSC: This feature is unsupported in this version.")) \ + { \ + Scr_AddUndefined(); \ + return; \ + } + +#include +#include +#include +#include + +#undef ASSERT diff --git a/extensions/__test__/main.test.c b/extensions/__test__/main.test.c index 8641008..544af77 100644 --- a/extensions/__test__/main.test.c +++ b/extensions/__test__/main.test.c @@ -1,13 +1,14 @@ -#include -GREATEST_MAIN_DEFS(); - -extern SUITE(Suite_utils); - -int main(int argc, char** argv) -{ - GREATEST_MAIN_BEGIN(); - - RUN_SUITE(Suite_utils); - - GREATEST_MAIN_END(); -} +#include + +GREATEST_MAIN_DEFS(); + +extern SUITE(Suite_utils); + +int main(int argc, char** argv) +{ + GREATEST_MAIN_BEGIN(); + + RUN_SUITE(Suite_utils); + + GREATEST_MAIN_END(); +} diff --git a/extensions/functions.c b/extensions/functions.c index 1bf8fbc..2574f95 100644 --- a/extensions/functions.c +++ b/extensions/functions.c @@ -1,85 +1,85 @@ -#include "functions.h" - -void Scr_CallFunction(void (*function)(void), ...) -{ - function(); - __callArgNumber = 0; -} - -void Scr_CallMethod(void (*function)(scr_entref_t), scr_entref_t ent, ...) -{ - function(ent); - __callArgNumber = 0; -} - -qboolean Scr_SetParamGeneric(unsigned int paramnum, void *var, int type) -{ - VariableValue *funcParam = Scr_SelectParamOrDefault(paramnum); - if (funcParam == NULL) - return qfalse; - else - { - switch (type) - { - case VAR_FLOAT: - funcParam->type = VAR_FLOAT; - funcParam->u.floatValue = *(float *)var; - break; - case VAR_INTEGER: - funcParam->type = VAR_INTEGER; - funcParam->u.intValue = *(int *)var; - break; - case VAR_ISTRING: - funcParam->type = VAR_ISTRING; - funcParam->u.stringValue = Scr_AllocString(*(const char **)var); - break; - case VAR_STRING: - funcParam->type = VAR_STRING; - funcParam->u.stringValue = Scr_AllocString(*(const char **)var); - break; - #if CGSC(4) - case VAR_VECTOR: - funcParam->type = VAR_VECTOR; - funcParam->u.vectorValue = Scr_AllocVector(*(const float **)var); - break; - #endif - case VAR_POINTER: - funcParam->type = VAR_POINTER; - funcParam->u.pointerValue = *(int *)var; - break; - case VAR_FUNCTION: - funcParam->type = VAR_FUNCTION; - funcParam->u.codePosValue = *(const char **)var; - break; - case VAR_UNDEFINED: - default: - funcParam->type = VAR_UNDEFINED; - funcParam->u.intValue = 0; - break; - } - __callArgNumber++; - return qtrue; - } -} - -int Scr_GetThreadReturn() -{ - int value; - GetRegisterValue(&value, "edx"); - - #if CGSC(4) - return *(int *)value; - #elif CGSC(3) - return value; - #endif -} - -void GScr_Test(scr_entref_t entref) -{ - #if CGSC_EQ(3) - void (*iprintlnbold)(void) = (void (*)(void))0x80c2c14; - #endif - - const char *str = "TEST"; - Scr_CallFunction(iprintlnbold, STRING(&str)); -} +#include "functions.h" + +void Scr_CallFunction(void (*function)(void), ...) +{ + function(); + __callArgNumber = 0; +} + +void Scr_CallMethod(void (*function)(scr_entref_t), scr_entref_t ent, ...) +{ + function(ent); + __callArgNumber = 0; +} + +qboolean Scr_SetParamGeneric(unsigned int paramnum, void *var, int type) +{ + VariableValue *funcParam = Scr_SelectParamOrDefault(paramnum); + if (funcParam == NULL) + return qfalse; + else + { + switch (type) + { + case VAR_FLOAT: + funcParam->type = VAR_FLOAT; + funcParam->u.floatValue = *(float *)var; + break; + case VAR_INTEGER: + funcParam->type = VAR_INTEGER; + funcParam->u.intValue = *(int *)var; + break; + case VAR_ISTRING: + funcParam->type = VAR_ISTRING; + funcParam->u.stringValue = Scr_AllocString(*(const char **)var); + break; + case VAR_STRING: + funcParam->type = VAR_STRING; + funcParam->u.stringValue = Scr_AllocString(*(const char **)var); + break; +#if CGSC(4) + case VAR_VECTOR: + funcParam->type = VAR_VECTOR; + funcParam->u.vectorValue = Scr_AllocVector(*(const float **)var); + break; +#endif + case VAR_POINTER: + funcParam->type = VAR_POINTER; + funcParam->u.pointerValue = *(int *)var; + break; + case VAR_FUNCTION: + funcParam->type = VAR_FUNCTION; + funcParam->u.codePosValue = *(const char **)var; + break; + case VAR_UNDEFINED: + default: + funcParam->type = VAR_UNDEFINED; + funcParam->u.intValue = 0; + break; + } + __callArgNumber++; + return qtrue; + } +} + +int Scr_GetThreadReturn() +{ + int value; + GetRegisterValue(&value, "edx"); + +#if CGSC(4) + return *(int *)value; +#elif CGSC(3) + return value; +#endif +} + +void GScr_Test(scr_entref_t entref) +{ +#if CGSC_EQ(3) + void (*iprintlnbold)(void) = (void (*)(void))0x80c2c14; +#endif + + const char *str = "TEST"; + Scr_CallFunction(iprintlnbold, STRING(&str)); +} diff --git a/extensions/functions.h b/extensions/functions.h index ce4e2b9..ea743bb 100644 --- a/extensions/functions.h +++ b/extensions/functions.h @@ -1,43 +1,53 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" /// @brief This variable is used to keep track of param count for a single call, /// and can only be used in non-thread safe environment. /// @todo - Experimental feature. __attribute__((used)) static int __callArgNumber = 0; -/// @brief Alloc a new GSC float param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC float param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define FLOAT(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_FLOAT) -/// @brief Alloc a new GSC int param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC int param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define INT(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_INTEGER) -/// @brief Alloc a new GSC vector param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC vector param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define VECTOR(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_VECTOR) -/// @brief Alloc a new GSC pointer param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC pointer param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define POINTER(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_POINTER) -/// @brief Alloc a new GSC string param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC string param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define STRING(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_STRING) -/// @brief Alloc a new GSC localized string param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC localized string param before calling the function +/// with Scr_CallFunction/Scr_CallMethod. #define ISTRING(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_ISTRING) -/// @brief Alloc a new GSC function param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC function param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define FUNC(val) Scr_SetParamGeneric(__callArgNumber, val, VAR_FUNCTION) -/// @brief Alloc a new GSC undefined param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC undefined param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. #define UNDEFINED() Scr_SetParamGeneric(__callArgNumber, NULL, VAR_UNDEFINED) -/// @brief Alloc a new GSC generic param before calling the function with Scr_CallFunction/Scr_CallMethod. +/// @brief Alloc a new GSC generic param before calling the function with +/// Scr_CallFunction/Scr_CallMethod. /// @param paramnum - The param index to alloc. /// @param var - The value of the generic variable. /// @param type - The type of the generic variable. /// @return qboolean - Boolean result. EXPORT(qboolean, Scr_SetParamGeneric(unsigned int paramnum, void *var, int type)); -/// @brief Call the specified GSC function pointer. This function is experimental. +/// @brief Call the specified GSC function pointer. This function is +/// experimental. /// @param function - The GSC function pointer. /// @param ... - GSC alloc macros can be written here only for convenience. /// @todo diff --git a/extensions/variables.c b/extensions/variables.c index 3d8ae3f..a717ba1 100644 --- a/extensions/variables.c +++ b/extensions/variables.c @@ -1,241 +1,293 @@ -#include "variables.h" - -VariableValueArray Scr_CreateArray(int length) -{ - VariableValueArray array; - array.length = length; - array.items = (VariableValue *)malloc(length * sizeof(VariableValue)); - return array; -} - -void Scr_FreeArray(VariableValueArray* array) -{ - if (array && array->items) - free(array->items); -} - -VariableValueArray Scr_GetArray(unsigned int paramnum) -{ - VariableValueArray array = { 0 }; - int parentId = Scr_GetObject(paramnum); - - if (Scr_GetObjectType(parentId) != VAR_ARRAY) - return array; - - int length = GetArraySize(parentId); - int index = length - 1; - - if (!length) - return array; - - VariableValueInternal *entryValue; - array = Scr_CreateArray(length); - unsigned int id = IGScrVarGlob[parentId + VARIABLELIST_PARENT_BEGIN].nextSibling; - unsigned int nextSibling; - - if (id) - { - while (qtrue) - { - entryValue = &IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN]; - - array.items[index].type = entryValue->w.type & VAR_MASK; - array.items[index].u = entryValue->u.u; - - nextSibling = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN].nextSibling; - if (!nextSibling) - break; - - id = IGScrVarGlob[nextSibling + VARIABLELIST_CHILD_BEGIN].hash.id; - index--; - } - } - return array; -} - -void Scr_AddPointerArray(unsigned int pointerValue) -{ - if (Scr_GetObjectType(pointerValue) != VAR_ARRAY) - return; - - int length = GetArraySize(pointerValue); - int index = length - 1; - - if (!length) - { - Scr_MakeArray(); - return; - } - - VariableValueInternal *entries = (VariableValueInternal *)malloc(length * sizeof(VariableValueInternal)); - unsigned int id = IGScrVarGlob[pointerValue + VARIABLELIST_PARENT_BEGIN].nextSibling; - unsigned int nextSibling; - - if (id) - { - while (qtrue) - { - entries[index] = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN]; - - nextSibling = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN].nextSibling; - if (!nextSibling) - break; - - id = IGScrVarGlob[nextSibling + VARIABLELIST_CHILD_BEGIN].hash.id; - index--; - } - } - Scr_MakeArray(); - - for (int i = 0; i < length; i++) - { - VariableValue value; - value.type = entries[i].w.type & VAR_MASK; - value.u = entries[i].u.u; - Scr_AddVariable(value); - - VariableValue indexerValue = Scr_GetArrayIndexValue(entries[i].w.name >> VAR_NAME_BITS); - if (indexerValue.type == VAR_STRING) - Scr_AddArrayStringIndexed(indexerValue.u.stringValue); - else if (indexerValue.type == VAR_INTEGER) - Scr_AddArray(); - } - free(entries); -} - -VariableValue Scr_ReturnResult() -{ - VariableValue *returnRef = Scr_GetTop(-1); - VariableValue var = *returnRef; - returnRef->type = 0; - return var; -} - -VariableValue *Scr_SelectParam(unsigned int paramnum) -{ - if (paramnum >= IGScrVmPub.outparamcount) - { - Scr_Error(fmt("parameter %d does not exist\n", paramnum + 1)); - return NULL; - } - return Scr_GetTop(paramnum); -} - -VariableValue *Scr_GetTop(unsigned int paramnum) -{ - return &IGScrVmPub.top[-paramnum]; -} - -VariableValue *Scr_SelectParamOrDefault(unsigned int paramnum) -{ - if (paramnum >= IGScrVmPub.outparamcount) - { - IGScrVmPub.top++; - IGScrVmPub.outparamcount++; - } - return Scr_GetTop(paramnum); -} - -void Scr_AddVariable(VariableValue var) -{ - switch (var.type) - { -#if CGSC(4) - case VAR_POINTER: - switch (Scr_GetObjectType(var.u.pointerValue)) - { - case VAR_ARRAY: - Scr_AddPointerArray(var.u.pointerValue); - break; - case VAR_OBJECT: - case VAR_ENTITY: - Scr_AddObject(var.u.pointerValue); - break; - case VAR_UNDEFINED: - default: - Scr_AddUndefined(); - break; - } - break; - case VAR_FUNCTION: - Scr_AddFunc(var.u.codePosValue); - break; - case VAR_ISTRING: - Scr_AddIString(SL_ConvertToString(var.u.stringValue)); - break; -#endif -#if CGSC_EQ(3) - case VAR_POINTER: - case VAR_FUNCTION: - case VAR_ISTRING: - CGSC_Printf("CGSC: Unsupported type %s.\n", var_typename[var.type]); - Scr_AddUndefined(); - break; -#endif - case VAR_FLOAT: - Scr_AddFloat(var.u.floatValue); - break; - case VAR_INTEGER: - Scr_AddInt(var.u.intValue); - break; - case VAR_STRING: - Scr_AddString(SL_ConvertToString(var.u.stringValue)); - break; - case VAR_VECTOR: - { - const float *vec = var.u.vectorValue; - vec3_t value = { vec[0], vec[1], vec[2] }; -#if CGSC(4) - Scr_AddVector((float *)value); -#elif CGSC(3) - Scr_AddVector((vec_t *)value); -#endif - break; - } - case VAR_ENTITY: - Scr_AddEntity(&g_entities[157 * var.u.entityOffset]); - break; - case VAR_UNDEFINED: - default: - Scr_AddUndefined(); - break; - } -} - -uint32_t Scr_GetArrayFlags(VariableValueArray array) -{ - uint32_t flags = 0; - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_UNDEFINED: flags |= FLAG_UNDEFINED; break; - case VAR_POINTER: flags |= FLAG_POINTER; break; - case VAR_STRING: flags |= FLAG_STRING; break; - case VAR_ISTRING: flags |= FLAG_ISTRING; break; - case VAR_VECTOR: flags |= FLAG_VECTOR; break; - case VAR_FLOAT: flags |= FLAG_FLOAT; break; - case VAR_INTEGER: flags |= FLAG_INTEGER; break; - case VAR_CODEPOS: flags |= FLAG_CODEPOS; break; - case VAR_PRECODEPOS: flags |= FLAG_PRECODEPOS; break; - case VAR_FUNCTION: flags |= FLAG_FUNCTION; break; - case VAR_STACK: flags |= FLAG_STACK; break; - case VAR_ANIMATION: flags |= FLAG_ANIMATION; break; - case VAR_DEVELOPER_CODEPOS: flags |= FLAG_DEVELOPER_CODEPOS; break; - case VAR_INCLUDE_CODEPOS: flags |= FLAG_INCLUDE_CODEPOS; break; - case VAR_THREAD: flags |= FLAG_THREAD; break; - case VAR_NOTIFY_THREAD: flags |= FLAG_NOTIFY_THREAD; break; - case VAR_TIME_THREAD: flags |= FLAG_TIME_THREAD; break; - case VAR_CHILD_THREAD: flags |= FLAG_CHILD_THREAD; break; - case VAR_OBJECT: flags |= FLAG_OBJECT; break; - case VAR_DEAD_ENTITY: flags |= FLAG_DEAD_ENTITY; break; - case VAR_ENTITY: flags |= FLAG_ENTITY; break; - case VAR_ARRAY: flags |= FLAG_ARRAY; break; - case VAR_DEAD_THREAD: flags |= FLAG_DEAD_THREAD; break; - case VAR_COUNT: flags |= FLAG_COUNT; break; - case VAR_THREAD_LIST: flags |= FLAG_THREAD_LIST; break; - case VAR_ENDON_LIST: flags |= FLAG_ENDON_LIST; break; - } - } - return flags; -} +#include "variables.h" + +VariableValueArray Scr_CreateArray(int length) +{ + VariableValueArray array; + array.length = length; + array.items = (VariableValue *)malloc(length * sizeof(VariableValue)); + return array; +} + +void Scr_FreeArray(VariableValueArray *array) +{ + if (array && array->items) + free(array->items); +} + +VariableValueArray Scr_GetArray(unsigned int paramnum) +{ + VariableValueArray array = { 0 }; + int parentId = Scr_GetObject(paramnum); + + if (Scr_GetObjectType(parentId) != VAR_ARRAY) + return array; + + int length = GetArraySize(parentId); + int index = length - 1; + + if (!length) + return array; + + VariableValueInternal *entryValue; + array = Scr_CreateArray(length); + unsigned int id = IGScrVarGlob[parentId + VARIABLELIST_PARENT_BEGIN].nextSibling; + unsigned int nextSibling; + + if (id) + { + while (qtrue) + { + entryValue = &IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN]; + + array.items[index].type = entryValue->w.type & VAR_MASK; + array.items[index].u = entryValue->u.u; + + nextSibling = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN].nextSibling; + if (!nextSibling) + break; + + id = IGScrVarGlob[nextSibling + VARIABLELIST_CHILD_BEGIN].hash.id; + index--; + } + } + return array; +} + +void Scr_AddPointerArray(unsigned int pointerValue) +{ + if (Scr_GetObjectType(pointerValue) != VAR_ARRAY) + return; + + int length = GetArraySize(pointerValue); + int index = length - 1; + + if (!length) + { + Scr_MakeArray(); + return; + } + + VariableValueInternal *entries = (VariableValueInternal *)malloc(length * sizeof(VariableValueInternal)); + unsigned int id = IGScrVarGlob[pointerValue + VARIABLELIST_PARENT_BEGIN].nextSibling; + unsigned int nextSibling; + + if (id) + { + while (qtrue) + { + entries[index] = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN]; + + nextSibling = IGScrVarGlob[id + VARIABLELIST_CHILD_BEGIN].nextSibling; + if (!nextSibling) + break; + + id = IGScrVarGlob[nextSibling + VARIABLELIST_CHILD_BEGIN].hash.id; + index--; + } + } + Scr_MakeArray(); + + for (int i = 0; i < length; i++) + { + VariableValue value; + value.type = entries[i].w.type & VAR_MASK; + value.u = entries[i].u.u; + Scr_AddVariable(value); + + VariableValue indexerValue = Scr_GetArrayIndexValue(entries[i].w.name >> VAR_NAME_BITS); + if (indexerValue.type == VAR_STRING) + Scr_AddArrayStringIndexed(indexerValue.u.stringValue); + else if (indexerValue.type == VAR_INTEGER) + Scr_AddArray(); + } + free(entries); +} + +VariableValue Scr_ReturnResult() +{ + VariableValue *returnRef = Scr_GetTop(-1); + VariableValue var = *returnRef; + returnRef->type = 0; + return var; +} + +VariableValue *Scr_SelectParam(unsigned int paramnum) +{ + if (paramnum >= IGScrVmPub.outparamcount) + { + Scr_Error(fmt("parameter %d does not exist\n", paramnum + 1)); + return NULL; + } + return Scr_GetTop(paramnum); +} + +VariableValue *Scr_GetTop(unsigned int paramnum) +{ + return &IGScrVmPub.top[-paramnum]; +} + +VariableValue *Scr_SelectParamOrDefault(unsigned int paramnum) +{ + if (paramnum >= IGScrVmPub.outparamcount) + { + IGScrVmPub.top++; + IGScrVmPub.outparamcount++; + } + return Scr_GetTop(paramnum); +} + +void Scr_AddVariable(VariableValue var) +{ + switch (var.type) + { +#if CGSC(4) + case VAR_POINTER: + switch (Scr_GetObjectType(var.u.pointerValue)) + { + case VAR_ARRAY: + Scr_AddPointerArray(var.u.pointerValue); + break; + case VAR_OBJECT: + case VAR_ENTITY: + Scr_AddObject(var.u.pointerValue); + break; + case VAR_UNDEFINED: + default: + Scr_AddUndefined(); + break; + } + break; + case VAR_FUNCTION: + Scr_AddFunc(var.u.codePosValue); + break; + case VAR_ISTRING: + Scr_AddIString(SL_ConvertToString(var.u.stringValue)); + break; +#endif +#if CGSC_EQ(3) + case VAR_POINTER: + case VAR_FUNCTION: + case VAR_ISTRING: + CGSC_Printf("CGSC: Unsupported type %s.\n", var_typename[var.type]); + Scr_AddUndefined(); + break; +#endif + case VAR_FLOAT: + Scr_AddFloat(var.u.floatValue); + break; + case VAR_INTEGER: + Scr_AddInt(var.u.intValue); + break; + case VAR_STRING: + Scr_AddString(SL_ConvertToString(var.u.stringValue)); + break; + case VAR_VECTOR: + { + const float *vec = var.u.vectorValue; + vec3_t value = { vec[0], vec[1], vec[2] }; +#if CGSC(4) + Scr_AddVector((float *)value); +#elif CGSC(3) + Scr_AddVector((vec_t *)value); +#endif + break; + } + case VAR_ENTITY: + Scr_AddEntity(&g_entities[157 * var.u.entityOffset]); + break; + case VAR_UNDEFINED: + default: + Scr_AddUndefined(); + break; + } +} + +uint32_t Scr_GetArrayFlags(VariableValueArray array) +{ + uint32_t flags = 0; + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_UNDEFINED: + flags |= FLAG_UNDEFINED; + break; + case VAR_POINTER: + flags |= FLAG_POINTER; + break; + case VAR_STRING: + flags |= FLAG_STRING; + break; + case VAR_ISTRING: + flags |= FLAG_ISTRING; + break; + case VAR_VECTOR: + flags |= FLAG_VECTOR; + break; + case VAR_FLOAT: + flags |= FLAG_FLOAT; + break; + case VAR_INTEGER: + flags |= FLAG_INTEGER; + break; + case VAR_CODEPOS: + flags |= FLAG_CODEPOS; + break; + case VAR_PRECODEPOS: + flags |= FLAG_PRECODEPOS; + break; + case VAR_FUNCTION: + flags |= FLAG_FUNCTION; + break; + case VAR_STACK: + flags |= FLAG_STACK; + break; + case VAR_ANIMATION: + flags |= FLAG_ANIMATION; + break; + case VAR_DEVELOPER_CODEPOS: + flags |= FLAG_DEVELOPER_CODEPOS; + break; + case VAR_INCLUDE_CODEPOS: + flags |= FLAG_INCLUDE_CODEPOS; + break; + case VAR_THREAD: + flags |= FLAG_THREAD; + break; + case VAR_NOTIFY_THREAD: + flags |= FLAG_NOTIFY_THREAD; + break; + case VAR_TIME_THREAD: + flags |= FLAG_TIME_THREAD; + break; + case VAR_CHILD_THREAD: + flags |= FLAG_CHILD_THREAD; + break; + case VAR_OBJECT: + flags |= FLAG_OBJECT; + break; + case VAR_DEAD_ENTITY: + flags |= FLAG_DEAD_ENTITY; + break; + case VAR_ENTITY: + flags |= FLAG_ENTITY; + break; + case VAR_ARRAY: + flags |= FLAG_ARRAY; + break; + case VAR_DEAD_THREAD: + flags |= FLAG_DEAD_THREAD; + break; + case VAR_COUNT: + flags |= FLAG_COUNT; + break; + case VAR_THREAD_LIST: + flags |= FLAG_THREAD_LIST; + break; + case VAR_ENDON_LIST: + flags |= FLAG_ENDON_LIST; + break; + } + } + return flags; +} diff --git a/extensions/variables.h b/extensions/variables.h index 7009fe2..d77d50d 100644 --- a/extensions/variables.h +++ b/extensions/variables.h @@ -1,5 +1,5 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" /// @brief Create a new VariableValueArray with a fixed length. /// The array can be freed with Scr_FreeArray.The array can be freed with Scr_FreeArray. @@ -43,7 +43,7 @@ EXPORT(short, Scr_ExecThreadResult(int callbackHook, unsigned int numArgs)); /// @brief Return a GSC Function from specified codeposvalue. /// @param codePosValue - The code pos value. -EXPORT(void, Scr_AddFunc(const char *codePosValue)); +EXPORT(void, Scr_AddFunc(const char* codePosValue)); /// @brief Return a GSC array from the pointer value. /// @param pointerValue - The pointer value. diff --git a/plugin.h b/plugin.h index 27281ef..a1a9fcb 100644 --- a/plugin.h +++ b/plugin.h @@ -1,151 +1,151 @@ -#pragma once -#define PLUGIN - -#ifndef PLUGIN_INCLUDES - #include -#endif - -#ifdef PLUGIN - #define Com_Printf Plugin_Printf - #define Scr_Error Plugin_Scr_Error - #define Scr_AddUndefined Plugin_Scr_AddUndefined - #define Sys_GetCommonVersion Plugin_Sys_GetCommonVersion -#endif - -#define CHECK_PARAMS(count, message) \ -if (Plugin_Scr_GetNumParam() != count) \ -{ \ - Plugin_Scr_Error(message); \ - return; \ -} - -#define CHECK_UNSUPPORTED(condition) \ -if (Plugin_CGSC_UnsupportedMessage(condition, "CGSC: This feature is unsupported in this version.")) \ -{ \ - Plugin_Scr_AddUndefined(); \ - return; \ -} - -struct VariableStackBuffer -{ - const char *pos; - uint16_t size; - uint16_t bufLen; - uint16_t localId; - char time; - char buf[1]; -}; - -union VariableUnion -{ - int intValue; - float floatValue; - unsigned int stringValue; - const float *vectorValue; - const char *codePosValue; - unsigned int pointerValue; - struct VariableStackBuffer *stackValue; - unsigned int entityOffset; -}; - -typedef struct -{ - union VariableUnion u; - int type; -} VariableValue; - -union ObjectInfo_u -{ - uint16_t size; - uint16_t entnum; - uint16_t nextEntId; - uint16_t self; -}; - -struct ObjectInfo -{ - uint16_t refCount; - union ObjectInfo_u u; -}; - -union VariableValueInternal_u -{ - uint16_t next; - union VariableUnion u; - struct ObjectInfo o; -}; - -union VariableValueInternal_w -{ - unsigned int status; - unsigned int type; - unsigned int name; - unsigned int classnum; - unsigned int notifyName; - unsigned int waitTime; - unsigned int parentLocalId; -}; - -union VariableValueInternal_v -{ - uint16_t next; - uint16_t index; -}; - -union Variable_u -{ - uint16_t prev; - uint16_t prevSibling; -}; - -struct Variable -{ - uint16_t id; - union Variable_u u; -}; - -typedef struct -{ - struct Variable hash; - union VariableValueInternal_u u; - union VariableValueInternal_w w; - union VariableValueInternal_v v; - uint16_t nextSibling; -}VariableValueInternal; - -enum $0E0E04F36A22A28F2C0A7A22DC12DAE9 -{ - VAR_UNDEFINED = 0x0, - VAR_BEGIN_REF = 0x1, - VAR_POINTER = 0x1, - VAR_STRING = 0x2, - VAR_ISTRING = 0x3, - VAR_VECTOR = 0x4, - VAR_END_REF = 0x5, - VAR_FLOAT = 0x5, - VAR_INTEGER = 0x6, - VAR_CODEPOS = 0x7, - VAR_PRECODEPOS = 0x8, - VAR_FUNCTION = 0x9, - VAR_STACK = 0xA, - VAR_ANIMATION = 0xB, - VAR_DEVELOPER_CODEPOS = 0xC, - VAR_INCLUDE_CODEPOS = 0xD, - VAR_THREAD = 0xE, - VAR_NOTIFY_THREAD = 0xF, - VAR_TIME_THREAD = 0x10, - VAR_CHILD_THREAD = 0x11, - VAR_OBJECT = 0x12, - VAR_DEAD_ENTITY = 0x13, - VAR_ENTITY = 0x14, - VAR_ARRAY = 0x15, - VAR_DEAD_THREAD = 0x16, - VAR_COUNT = 0x17, - VAR_THREAD_LIST = 0x18, - VAR_ENDON_LIST = 0x19 -}; - -/// @brief Get GSC function id from specified param num. -/// @param paramnum - GSC param index. -/// @return The GSC function id. -int Plugin_Scr_GetFunction(unsigned int paramnum); +#pragma once +#define PLUGIN + +#ifndef PLUGIN_INCLUDES + #include +#endif + +#ifdef PLUGIN + #define Com_Printf Plugin_Printf + #define Scr_Error Plugin_Scr_Error + #define Scr_AddUndefined Plugin_Scr_AddUndefined + #define Sys_GetCommonVersion Plugin_Sys_GetCommonVersion +#endif + +#define CHECK_PARAMS(count, message) \ + if (Plugin_Scr_GetNumParam() != count) \ + { \ + Plugin_Scr_Error(message); \ + return; \ + } + +#define CHECK_UNSUPPORTED(condition) \ + if (Plugin_CGSC_UnsupportedMessage(condition, "CGSC: This feature is unsupported in this version.")) \ + { \ + Plugin_Scr_AddUndefined(); \ + return; \ + } + +struct VariableStackBuffer +{ + const char *pos; + uint16_t size; + uint16_t bufLen; + uint16_t localId; + char time; + char buf[1]; +}; + +union VariableUnion +{ + int intValue; + float floatValue; + unsigned int stringValue; + const float *vectorValue; + const char *codePosValue; + unsigned int pointerValue; + struct VariableStackBuffer *stackValue; + unsigned int entityOffset; +}; + +typedef struct +{ + union VariableUnion u; + int type; +} VariableValue; + +union ObjectInfo_u +{ + uint16_t size; + uint16_t entnum; + uint16_t nextEntId; + uint16_t self; +}; + +struct ObjectInfo +{ + uint16_t refCount; + union ObjectInfo_u u; +}; + +union VariableValueInternal_u +{ + uint16_t next; + union VariableUnion u; + struct ObjectInfo o; +}; + +union VariableValueInternal_w +{ + unsigned int status; + unsigned int type; + unsigned int name; + unsigned int classnum; + unsigned int notifyName; + unsigned int waitTime; + unsigned int parentLocalId; +}; + +union VariableValueInternal_v +{ + uint16_t next; + uint16_t index; +}; + +union Variable_u +{ + uint16_t prev; + uint16_t prevSibling; +}; + +struct Variable +{ + uint16_t id; + union Variable_u u; +}; + +typedef struct +{ + struct Variable hash; + union VariableValueInternal_u u; + union VariableValueInternal_w w; + union VariableValueInternal_v v; + uint16_t nextSibling; +} VariableValueInternal; + +enum $0E0E04F36A22A28F2C0A7A22DC12DAE9 +{ + VAR_UNDEFINED = 0x0, + VAR_BEGIN_REF = 0x1, + VAR_POINTER = 0x1, + VAR_STRING = 0x2, + VAR_ISTRING = 0x3, + VAR_VECTOR = 0x4, + VAR_END_REF = 0x5, + VAR_FLOAT = 0x5, + VAR_INTEGER = 0x6, + VAR_CODEPOS = 0x7, + VAR_PRECODEPOS = 0x8, + VAR_FUNCTION = 0x9, + VAR_STACK = 0xA, + VAR_ANIMATION = 0xB, + VAR_DEVELOPER_CODEPOS = 0xC, + VAR_INCLUDE_CODEPOS = 0xD, + VAR_THREAD = 0xE, + VAR_NOTIFY_THREAD = 0xF, + VAR_TIME_THREAD = 0x10, + VAR_CHILD_THREAD = 0x11, + VAR_OBJECT = 0x12, + VAR_DEAD_ENTITY = 0x13, + VAR_ENTITY = 0x14, + VAR_ARRAY = 0x15, + VAR_DEAD_THREAD = 0x16, + VAR_COUNT = 0x17, + VAR_THREAD_LIST = 0x18, + VAR_ENDON_LIST = 0x19 +}; + +/// @brief Get GSC function id from specified param num. +/// @param paramnum - GSC param index. +/// @return The GSC function id. +int Plugin_Scr_GetFunction(unsigned int paramnum); diff --git a/sys/async.c b/sys/async.c index 8dfedfe..48cacbc 100644 --- a/sys/async.c +++ b/sys/async.c @@ -1,118 +1,121 @@ -#include "async.h" - -async_handler* AsyncInit() -{ - async_handler* handler = (async_handler*)malloc(sizeof(async_handler)); - handler->workers = (async_worker*)calloc(1, sizeof(async_worker)); - handler->loop = uv_default_loop(); - return handler; -} - -uv_loop_t* AsyncLoopCreate() -{ - uv_loop_t* loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); - uv_loop_init(loop); - return loop; -} - -int AsyncLoopRun(uv_loop_t* loop) -{ - return uv_run(loop, UV_RUN_DEFAULT); -} - -void AsyncLoopStop(uv_loop_t* loop) -{ - if (!loop || !uv_loop_alive(loop)) - return; - - uv_stop(loop); -} - -void AsyncLoopFree(uv_loop_t* loop) -{ - if (!loop) return; - AsyncLoopStop(loop); - uv_loop_close(loop); -} - -async_worker* AsyncWorker(async_handler* handler, void* data, uv_work_cb callback, uv_after_work_cb afterCallback) -{ - if (!handler) return NULL; - - uv_work_t* req = (uv_work_t*)malloc(sizeof(uv_work_t)); - async_worker* worker = (async_worker*)malloc(sizeof(async_worker)); - - worker->status = ASYNC_PENDING; - worker->req = req; - worker->loop = handler->loop; - worker->thread = 0; - worker->data = data; - worker->running = qtrue; - worker->next = handler->workers->next; - - handler->workers->next = worker; - req->data = worker; - - uv_queue_work(worker->loop, req, callback, afterCallback); - - return worker; -} - -void* AsyncWorkerData(uv_work_t* req) -{ - async_worker* worker = (async_worker*)req->data; - return worker->data; -} - -void AsyncWorkerDone(uv_work_t* req, async_status status) -{ - async_worker* worker = (async_worker*)req->data; - worker->status = status; - worker->running = qfalse; -} - -void AsyncWorkerCancel(async_worker* worker) -{ - if (!worker) - return; - worker->status = ASYNC_CANCEL; -} - -void AsyncWorkerFree(async_worker* worker) -{ - if (!worker) - return; - if (worker->req) - { - free(worker->req); - worker->req = NULL; - } -} - -void AsyncShutdown(async_handler* handler) -{ - if (!handler) return; - - async_worker* worker = handler->workers->next; - while (worker) - { - AsyncLoopStop(worker->loop); - AsyncWorkerCancel(worker); - worker = worker->next; - } - - worker = handler->workers->next; - while (worker) - { - while (worker->running) - uv_sleep(50); - - async_worker* prev = worker; - worker = worker->next; - free(prev); - } - if (handler->workers) - free(handler->workers); - free(handler); - handler = NULL; -} +#include "async.h" + +async_handler* AsyncInit() +{ + async_handler* handler = (async_handler*)malloc(sizeof(async_handler)); + handler->workers = (async_worker*)calloc(1, sizeof(async_worker)); + handler->loop = uv_default_loop(); + return handler; +} + +uv_loop_t* AsyncLoopCreate() +{ + uv_loop_t* loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); + uv_loop_init(loop); + return loop; +} + +int AsyncLoopRun(uv_loop_t* loop) +{ + return uv_run(loop, UV_RUN_DEFAULT); +} + +void AsyncLoopStop(uv_loop_t* loop) +{ + if (!loop || !uv_loop_alive(loop)) + return; + + uv_stop(loop); +} + +void AsyncLoopFree(uv_loop_t* loop) +{ + if (!loop) + return; + AsyncLoopStop(loop); + uv_loop_close(loop); +} + +async_worker* AsyncWorker(async_handler* handler, void* data, uv_work_cb callback, uv_after_work_cb afterCallback) +{ + if (!handler) + return NULL; + + uv_work_t* req = (uv_work_t*)malloc(sizeof(uv_work_t)); + async_worker* worker = (async_worker*)malloc(sizeof(async_worker)); + + worker->status = ASYNC_PENDING; + worker->req = req; + worker->loop = handler->loop; + worker->thread = 0; + worker->data = data; + worker->running = qtrue; + worker->next = handler->workers->next; + + handler->workers->next = worker; + req->data = worker; + + uv_queue_work(worker->loop, req, callback, afterCallback); + + return worker; +} + +void* AsyncWorkerData(uv_work_t* req) +{ + async_worker* worker = (async_worker*)req->data; + return worker->data; +} + +void AsyncWorkerDone(uv_work_t* req, async_status status) +{ + async_worker* worker = (async_worker*)req->data; + worker->status = status; + worker->running = qfalse; +} + +void AsyncWorkerCancel(async_worker* worker) +{ + if (!worker) + return; + worker->status = ASYNC_CANCEL; +} + +void AsyncWorkerFree(async_worker* worker) +{ + if (!worker) + return; + if (worker->req) + { + free(worker->req); + worker->req = NULL; + } +} + +void AsyncShutdown(async_handler* handler) +{ + if (!handler) + return; + + async_worker* worker = handler->workers->next; + while (worker) + { + AsyncLoopStop(worker->loop); + AsyncWorkerCancel(worker); + worker = worker->next; + } + + worker = handler->workers->next; + while (worker) + { + while (worker->running) + uv_sleep(50); + + async_worker* prev = worker; + worker = worker->next; + free(prev); + } + if (handler->workers) + free(handler->workers); + free(handler); + handler = NULL; +} diff --git a/sys/async.h b/sys/async.h index dccd4e7..99dbf49 100644 --- a/sys/async.h +++ b/sys/async.h @@ -1,5 +1,6 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" + #include typedef enum @@ -14,39 +15,39 @@ typedef enum typedef struct async_worker_s { async_status status; - uv_work_t* req; - uv_loop_t* loop; + uv_work_t *req; + uv_loop_t *loop; uv_thread_t thread; qboolean running; - void* data; - struct async_worker_s* next; + void *data; + struct async_worker_s *next; } async_worker; typedef struct { - async_worker* workers; - uv_loop_t* loop; + async_worker *workers; + uv_loop_t *loop; } async_handler; /// @brief Initialize the async handler. -EXPORT(async_handler*, AsyncInit()); +EXPORT(async_handler *, AsyncInit()); /// @brief Create an async loop. /// @return -EXPORT(uv_loop_t*, AsyncLoopCreate()); +EXPORT(uv_loop_t *, AsyncLoopCreate()); /// @brief Run the async loop. /// @param loop - The loop. /// @return -EXPORT(int, AsyncLoopRun(uv_loop_t* loop)); +EXPORT(int, AsyncLoopRun(uv_loop_t *loop)); /// @brief Stop the async loop. /// @param loop - The loop. -EXPORT(void, AsyncLoopStop(uv_loop_t* loop)); +EXPORT(void, AsyncLoopStop(uv_loop_t *loop)); /// @brief Free and stop the async loop. /// @param loop - The loop. -EXPORT(void, AsyncLoopFree(uv_loop_t* loop)); +EXPORT(void, AsyncLoopFree(uv_loop_t *loop)); /// @brief Create a new async worker. /// @param handler - The async handler. @@ -54,26 +55,28 @@ EXPORT(void, AsyncLoopFree(uv_loop_t* loop)); /// @param callback - The async loop. /// @param afterCallback - The after callback. /// @return -EXPORT(async_worker*, AsyncWorker(async_handler* handler, void* data, uv_work_cb callback, uv_after_work_cb afterCallback)); +EXPORT(async_worker *, + AsyncWorker(async_handler *handler, void *data, uv_work_cb callback, uv_after_work_cb afterCallback)); /// @brief Get the worker data. /// @param req - The worker. /// @return -EXPORT(void*, AsyncWorkerData(uv_work_t* req)); +EXPORT(void *, AsyncWorkerData(uv_work_t *req)); /// @brief Set the worker status and stop running. /// @param req - The worker. /// @param status - The worker done status. -EXPORT(void, AsyncWorkerDone(uv_work_t* req, async_status status)); +EXPORT(void, AsyncWorkerDone(uv_work_t *req, async_status status)); /// @brief Cancel a worker. /// @param req - The worker. -EXPORT(void, AsyncWorkerCancel(async_worker* worker)); +EXPORT(void, AsyncWorkerCancel(async_worker *worker)); /// @brief Free a worker. /// @param req - The worker. -EXPORT(void, AsyncWorkerFree(async_worker* worker)); +EXPORT(void, AsyncWorkerFree(async_worker *worker)); -/// @brief Shutdown the async handler by canceling any pending requests and waiting for all threads to complete. +/// @brief Shutdown the async handler by canceling any pending requests and +/// waiting for all threads to complete. /// @param handler - The async handler. -EXPORT(void, AsyncShutdown(async_handler* handler)); +EXPORT(void, AsyncShutdown(async_handler *handler)); diff --git a/sys/compatibility.c b/sys/compatibility.c index dd38fad..7ab086f 100644 --- a/sys/compatibility.c +++ b/sys/compatibility.c @@ -1,34 +1,37 @@ -#include "compatibility.h" -#include -#include - -float CGSC_Version() -{ - char version[20] = { 0 }; - sprintf(version, "%d.%d", PLUGIN_HANDLER_VERSION_MAJOR, PLUGIN_HANDLER_VERSION_MINOR); - return atof(version); -} - -qboolean CGSC_Unsupported(qboolean versionCondition) -{ - if (!versionCondition) return qfalse; - - Scr_Error("CGSC: This feature is unsupported in this version."); - return qtrue; -} - -qboolean CGSC_UnsupportedMessage(qboolean versionCondition, char *format, ...) -{ - if (!versionCondition) return qfalse; - va_list argptr; - - va_start(argptr, format); - Scr_Error(fmt(format, argptr)); - va_end(argptr); - return qtrue; -} - -qboolean CGSC_SupportIndexedString() -{ - return Sys_GetCommonVersion() >= 20.0f; -} +#include "compatibility.h" + +#include +#include + +float CGSC_Version() +{ + char version[20] = { 0 }; + sprintf(version, "%d.%d", PLUGIN_HANDLER_VERSION_MAJOR, PLUGIN_HANDLER_VERSION_MINOR); + return atof(version); +} + +qboolean CGSC_Unsupported(qboolean versionCondition) +{ + if (!versionCondition) + return qfalse; + + Scr_Error("CGSC: This feature is unsupported in this version."); + return qtrue; +} + +qboolean CGSC_UnsupportedMessage(qboolean versionCondition, char *format, ...) +{ + if (!versionCondition) + return qfalse; + va_list argptr; + + va_start(argptr, format); + Scr_Error(fmt(format, argptr)); + va_end(argptr); + return qtrue; +} + +qboolean CGSC_SupportIndexedString() +{ + return Sys_GetCommonVersion() >= 20.0f; +} diff --git a/sys/compatibility.h b/sys/compatibility.h index 512b4f4..9f416ed 100644 --- a/sys/compatibility.h +++ b/sys/compatibility.h @@ -1,5 +1,5 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" /// @brief Get server version. EXPORT(float, Sys_GetCommonVersion()); diff --git a/utils/__test__/utils.test.c b/utils/__test__/utils.test.c index 71f8cbe..9d11285 100644 --- a/utils/__test__/utils.test.c +++ b/utils/__test__/utils.test.c @@ -1,16 +1,17 @@ -#include "utils/utils.h" -#include - -TEST test_fmt() -{ - ASSERT_STR_EQ(fmt("test"), "test"); - ASSERT_STR_EQ(fmt("test %d", 1), "test 1"); - ASSERT_STR_EQ(fmt("%s %d", "test", 2), "test 2"); - - PASS(); -} - -SUITE(Suite_utils) -{ - RUN_TEST(test_fmt); -} +#include "utils/utils.h" + +#include + +TEST test_fmt() +{ + ASSERT_STR_EQ(fmt("test"), "test"); + ASSERT_STR_EQ(fmt("test %d", 1), "test 1"); + ASSERT_STR_EQ(fmt("%s %d", "test", 2), "test 2"); + + PASS(); +} + +SUITE(Suite_utils) +{ + RUN_TEST(test_fmt); +} diff --git a/utils/utils.c b/utils/utils.c index 12d6787..482a0e8 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -1,29 +1,30 @@ -#include "utils.h" -#include - -char *fmt(char *format, ...) -{ - va_list argptr; - static char string[2][32000]; // In case va is called by nested functions - static int index = 0; - char *buf; - - buf = string[index & 1]; - index++; - - va_start(argptr, format); - vsnprintf(buf, sizeof(*string), format, argptr); - va_end(argptr); - - return buf; -} - -qboolean HasFlag(int var, int flag) -{ - return (var & flag) == flag; -} - -qboolean IsFlag(int var, int flag) -{ - return var == flag; -} +#include "utils.h" + +#include + +char *fmt(char *format, ...) +{ + va_list argptr; + static char string[2][32000]; // In case va is called by nested functions + static int index = 0; + char *buf; + + buf = string[index & 1]; + index++; + + va_start(argptr, format); + vsnprintf(buf, sizeof(*string), format, argptr); + va_end(argptr); + + return buf; +} + +qboolean HasFlag(int var, int flag) +{ + return (var & flag) == flag; +} + +qboolean IsFlag(int var, int flag) +{ + return var == flag; +} diff --git a/utils/utils.h b/utils/utils.h index 44e18d3..2695cf3 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -1,5 +1,5 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" /// @brief Print a formated string to the console. #if CGSC(4) @@ -13,9 +13,9 @@ #endif /// @brief Get a register value. -#define GetRegisterValue(var, reg) \ -register int _register asm(reg); \ -*var = _register; +#define GetRegisterValue(var, reg) \ + register int _register asm(reg); \ + *var = _register; /// @brief Format a string. /// @param format - The string to format. diff --git a/versions/cgsc3.c b/versions/cgsc3.c index 3d2d9ed..4c8124d 100644 --- a/versions/cgsc3.c +++ b/versions/cgsc3.c @@ -1,48 +1,55 @@ -#include "cgsc3.h" -#include - -#if CGSC_EQ(3) - -struct scrVmGlob_t -{ - VariableValue eval_stack[2]; - const char *dialog_error_message; - int loading; - int starttime; - unsigned int localVarsStack[2048]; -}; - -qboolean Scr_IsInOpcodeMemory(const char *pos) { return qfalse; } -unsigned int __cdecl AllocThread(unsigned int self) { return 0; } -void VM_Execute(unsigned a, char const *b, unsigned c) { } -void Scr_AddFunc(const char *codePosValue) { } -void AddRefToObject(unsigned int id) { } -void RemoveRefToObject(unsigned int id) { } - -__attribute__((unused)) scrVmPub_t gScrVmPub = {0}; -__attribute__((unused)) struct scrVmGlob_t gScrVmGlob = {0}; -__attribute__((unused)) scrVarPub_t gScrVarPub; - -/// @brief Get the object type. -/// @param id - The object id. -/// @return -unsigned int Scr_GetObjectType(unsigned int id) -{ - assert((IGScrVarGlob[VARIABLELIST_PARENT_BEGIN + id].w.status & VAR_STAT_MASK) != VAR_STAT_FREE); - return VAR_TYPE((&IGScrVarGlob[id + VARIABLELIST_PARENT_BEGIN])); -} - -/// @brief Get the array size. -/// @param id - The array id. -/// @return -int GetArraySize(int id) -{ - VariableValueInternal *entryValue; - assert(id != 0); - - entryValue = &IGScrVarGlob[id + VARIABLELIST_PARENT_BEGIN]; - assert(VAR_TYPE(entryValue) == VAR_ARRAY); - return entryValue->u.o.u.size; -} - -#endif +#include "cgsc3.h" + +#include + +#if CGSC_EQ(3) + +struct scrVmGlob_t +{ + VariableValue eval_stack[2]; + const char *dialog_error_message; + int loading; + int starttime; + unsigned int localVarsStack[2048]; +}; + +qboolean Scr_IsInOpcodeMemory(const char *pos) +{ + return qfalse; +} +unsigned int __cdecl AllocThread(unsigned int self) +{ + return 0; +} +void VM_Execute(unsigned a, char const *b, unsigned c) { } +void Scr_AddFunc(const char *codePosValue) { } +void AddRefToObject(unsigned int id) { } +void RemoveRefToObject(unsigned int id) { } + +__attribute__((unused)) scrVmPub_t gScrVmPub = { 0 }; +__attribute__((unused)) struct scrVmGlob_t gScrVmGlob = { 0 }; +__attribute__((unused)) scrVarPub_t gScrVarPub; + +/// @brief Get the object type. +/// @param id - The object id. +/// @return +unsigned int Scr_GetObjectType(unsigned int id) +{ + assert((IGScrVarGlob[VARIABLELIST_PARENT_BEGIN + id].w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + return VAR_TYPE((&IGScrVarGlob[id + VARIABLELIST_PARENT_BEGIN])); +} + +/// @brief Get the array size. +/// @param id - The array id. +/// @return +int GetArraySize(int id) +{ + VariableValueInternal *entryValue; + assert(id != 0); + + entryValue = &IGScrVarGlob[id + VARIABLELIST_PARENT_BEGIN]; + assert(VAR_TYPE(entryValue) == VAR_ARRAY); + return entryValue->u.o.u.size; +} + +#endif diff --git a/versions/cgsc3.h b/versions/cgsc3.h index 633045f..523e211 100644 --- a/versions/cgsc3.h +++ b/versions/cgsc3.h @@ -1,46 +1,46 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" +// clang-format off #if CGSC_EQ(3) + #define IGScrVmPub scrVmPub + #define IGScrVarGlob scrVarGlob -#define IGScrVmPub scrVmPub -#define IGScrVarGlob scrVarGlob - -extern char* SL_ConvertToString(unsigned int index); -extern char* var_typename[]; - -#ifdef COD4X -enum $0E0E04F36A22A28F2C0A7A22DC12DAE9 -{ - VAR_UNDEFINED = 0x0, - VAR_BEGIN_REF = 0x1, - VAR_POINTER = 0x1, - VAR_STRING = 0x2, - VAR_ISTRING = 0x3, - VAR_VECTOR = 0x4, - VAR_END_REF = 0x5, - VAR_FLOAT = 0x5, - VAR_INTEGER = 0x6, - VAR_CODEPOS = 0x7, - VAR_PRECODEPOS = 0x8, - VAR_FUNCTION = 0x9, - VAR_STACK = 0xA, - VAR_ANIMATION = 0xB, - VAR_DEVELOPER_CODEPOS = 0xC, - VAR_INCLUDE_CODEPOS = 0xD, - VAR_THREAD = 0xE, - VAR_NOTIFY_THREAD = 0xF, - VAR_TIME_THREAD = 0x10, - VAR_CHILD_THREAD = 0x11, - VAR_OBJECT = 0x12, - VAR_DEAD_ENTITY = 0x13, - VAR_ENTITY = 0x14, - VAR_ARRAY = 0x15, - VAR_DEAD_THREAD = 0x16, - VAR_COUNT = 0x17, - VAR_THREAD_LIST = 0x18, - VAR_ENDON_LIST = 0x19 -}; -#endif + extern char *SL_ConvertToString(unsigned int index); + extern char *var_typename[]; + #ifdef COD4X + enum $0E0E04F36A22A28F2C0A7A22DC12DAE9 + { + VAR_UNDEFINED = 0x0, + VAR_BEGIN_REF = 0x1, + VAR_POINTER = 0x1, + VAR_STRING = 0x2, + VAR_ISTRING = 0x3, + VAR_VECTOR = 0x4, + VAR_END_REF = 0x5, + VAR_FLOAT = 0x5, + VAR_INTEGER = 0x6, + VAR_CODEPOS = 0x7, + VAR_PRECODEPOS = 0x8, + VAR_FUNCTION = 0x9, + VAR_STACK = 0xA, + VAR_ANIMATION = 0xB, + VAR_DEVELOPER_CODEPOS = 0xC, + VAR_INCLUDE_CODEPOS = 0xD, + VAR_THREAD = 0xE, + VAR_NOTIFY_THREAD = 0xF, + VAR_TIME_THREAD = 0x10, + VAR_CHILD_THREAD = 0x11, + VAR_OBJECT = 0x12, + VAR_DEAD_ENTITY = 0x13, + VAR_ENTITY = 0x14, + VAR_ARRAY = 0x15, + VAR_DEAD_THREAD = 0x16, + VAR_COUNT = 0x17, + VAR_THREAD_LIST = 0x18, + VAR_ENDON_LIST = 0x19 + }; + #endif #endif +// clang-format on diff --git a/versions/cgsc4.c b/versions/cgsc4.c index 3f6de85..6eb2671 100644 --- a/versions/cgsc4.c +++ b/versions/cgsc4.c @@ -1,13 +1,14 @@ -#include "cgsc4.h" -#if CGSC_EQ(4) - -/// @brief Add a function pointer to the GSC stack. -/// @param codePosValue - The code pos value. -void Scr_AddFunc(const char *codePosValue) -{ - IncInParam(); - IGScrVmPub.top->type = VAR_FUNCTION; - IGScrVmPub.top->u.codePosValue = codePosValue; -} - -#endif +#include "cgsc4.h" + +#if CGSC_EQ(4) + +/// @brief Add a function pointer to the GSC stack. +/// @param codePosValue - The code pos value. +void Scr_AddFunc(const char *codePosValue) +{ + IncInParam(); + IGScrVmPub.top->type = VAR_FUNCTION; + IGScrVmPub.top->u.codePosValue = codePosValue; +} + +#endif diff --git a/versions/cgsc4.h b/versions/cgsc4.h index 73aa570..91c1f28 100644 --- a/versions/cgsc4.h +++ b/versions/cgsc4.h @@ -1,22 +1,22 @@ #pragma once -#include "../cgsc.h" +#include "cgsc.h" +// clang-format off #if CGSC_EQ(4) + #ifdef COD4X + #include + #include + #endif -#ifdef COD4X - #include - #include -#endif - -extern struct scrVarGlob_t gScrVarGlob; -extern unsigned int Scr_AllocString(const char *s); -extern void Scr_AddIString(const char *value); -extern void Scr_AddArrayStringIndexed(unsigned int stringValue); -extern VariableValue Scr_GetArrayIndexValue(unsigned int name); -extern void IncInParam(); - -#define IGScrVmPub gScrVmPub -#define IGScrVmGlob gScrVmGlob -#define IGScrVarGlob gScrVarGlob.variableList + extern struct scrVarGlob_t gScrVarGlob; + extern unsigned int Scr_AllocString(const char *s); + extern void Scr_AddIString(const char *value); + extern void Scr_AddArrayStringIndexed(unsigned int stringValue); + extern VariableValue Scr_GetArrayIndexValue(unsigned int name); + extern void IncInParam(); + #define IGScrVmPub gScrVmPub + #define IGScrVmGlob gScrVmGlob + #define IGScrVarGlob gScrVarGlob.variableList #endif +// clang-format on