├── .gitignore ├── README.md ├── bsp.cpp ├── bsp.hpp ├── config.hpp ├── cracking.cpp ├── cracking.hpp ├── declarations.hpp ├── doit.sh ├── functions.hpp ├── gsc.cpp ├── gsc.hpp ├── gsc_bots.cpp ├── gsc_bots.hpp ├── gsc_entity.cpp ├── gsc_entity.hpp ├── gsc_exec.cpp ├── gsc_exec.hpp ├── gsc_level.cpp ├── gsc_level.hpp ├── gsc_memory.cpp ├── gsc_memory.hpp ├── gsc_mysql.cpp ├── gsc_mysql.hpp ├── gsc_player.cpp ├── gsc_player.hpp ├── gsc_sqlite.cpp ├── gsc_sqlite.hpp ├── gsc_utils.cpp ├── gsc_utils.hpp ├── gsc_weapons.cpp ├── gsc_weapons.hpp ├── jump.cpp ├── jump.hpp ├── lib └── qvsnprintf.c └── libcod.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Libcod 35 | bin/** 36 | extra/** 37 | objects_cod2_1_0/** 38 | objects_cod2_1_2/** 39 | objects_cod2_1_3/** 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Call of Duty extension *libcod* is adding new server-side functions to: 2 | 3 | - Call Of Duty 2 1.0 4 | - Call Of Duty 2 1.2c (1.2a not supported) 5 | - Call Of Duty 2 1.3 6 | 7 | Requirements: 8 | ``` 9 | g++ (multilib for x64) 10 | MySQL (optional) 11 | SQLite (optional) 12 | ``` 13 | 14 | Working with the source / Compiling: 15 | ``` 16 | ./doit.sh cod2_1_0 17 | ./doit.sh cod2_1_2 18 | ./doit.sh cod2_1_3 19 | ``` 20 | 21 | Starting the server: 22 | ``` 23 | export LD_PRELOAD="$HOME/cod2_1_0/libcod2_1_0.so" 24 | ./cod2_lnxded +set fs_game ... +set dedicated 2 ... 25 | ``` 26 | 27 | Little overview of added functions: 28 | - MySQL 29 | - SQLite 30 | - Linux shell command execution (adds tons of possibilites like executing external scripts, commands and pass their output to GSC) 31 | - setVelocity, getVelocity, addVelocity (needed for the mods: portal, surf) 32 | - keyPressed-functions for left, right, forward, backward, leanleft, leanright, jump etc., (needed for: surf, doublejump made by IzNoGod) 33 | - setAlive-function (needed for: zombots, so xmodels are damagable without damage-trigger... zombots in stockmaps) 34 | - disableGlobalPlayerCollision() also disableGlobalPlayerEject() 35 | - native bot functions (bots can move, shoot, jump, melee, ads, set stance) 36 | - weapon-functions (get/set weapon damage, firetime, maxammo without editing their files) 37 | 38 | Engine fixes: 39 | - Faster download for CoD2 1.0 40 | - Directory traversal fix 41 | - Weapon struct segfault fix 42 | - Rate Limiter 43 | 44 | Credits to CoD4x developers for many function/typedef references, thanks! 45 | 46 | Community / Help: http://killtube.org/forum.php 47 | Function documentation: https://github.com/M-itch/codscriptdoc 48 | -------------------------------------------------------------------------------- /bsp.cpp: -------------------------------------------------------------------------------- 1 | #include "bsp.hpp" 2 | 3 | #if COMPILE_BSP == 1 4 | 5 | static fileHandle_t f; 6 | 7 | void CM_DebugViewBasicDetails() 8 | { 9 | FS_Printf( f, "%s:\n\n", cm.name); 10 | FS_Printf( f, "StaticModels: %d\n", cm.numStaticModels); 11 | FS_Printf( f, "Materials: %d\n", cm.numMaterials); 12 | FS_Printf( f, "BrushSides: %d\n", cm.numBrushSides); 13 | FS_Printf( f, "Nodes: %d\n", cm.numNodes); 14 | FS_Printf( f, "Leafs: %d\n", cm.numLeafs); 15 | FS_Printf( f, "LeafbrushNodes: %d\n", cm.leafbrushNodesCount); 16 | FS_Printf( f, "LeafBrushes: %d\n", cm.numLeafBrushes); 17 | FS_Printf( f, "LeafSurfaces: %d\n", cm.numLeafSurfaces); 18 | FS_Printf( f, "Verticles: %d\n", cm.vertCount); 19 | FS_Printf( f, "Edges: %d\n", cm.edgeCount); 20 | FS_Printf( f, "TriIndices: %d\n", cm.triCount); 21 | FS_Printf( f, "CollisionBorders: %d\n", cm.borderCount); 22 | FS_Printf( f, "CollisionPartitions: %d\n", cm.partitionCount); 23 | FS_Printf( f, "CollisionAabbTrees: %d\n", cm.aabbTreeCount); 24 | FS_Printf( f, "SubModels: %d\n", cm.numSubModels); 25 | FS_Printf( f, "Brushes: %d\n", cm.numBrushes); 26 | FS_Printf( f, "Clusters: %d\n", cm.numClusters); 27 | FS_Printf( f, "dynEnts0: %d\n", cm.dynEntCount[0]); 28 | FS_Printf( f, "dynEnt1: %d\n", cm.dynEntCount[1]); 29 | FS_Printf( f, "\n"); 30 | } 31 | 32 | void CM_DebugPrintMaterialInfo() 33 | { 34 | unsigned int i; 35 | u_int32_t content = 0; 36 | u_int32_t surface = 0; 37 | 38 | FS_Printf( f, "--------------- MaterialInfo --------------------\n"); 39 | 40 | for(i = 0; i < cm.numMaterials; ++i) 41 | { 42 | FS_Printf( f, "%s surf: 0x%08x cont: 0x%08x\n", cm.materials[i].material, cm.materials[i].surfaceFlags, cm.materials[i].contentFlags); 43 | surface |= cm.materials[i].surfaceFlags; 44 | content |= cm.materials[i].contentFlags; 45 | } 46 | FS_Printf( f, "\n"); 47 | FS_Printf( f, "used surface flags: 0x%08x\n", surface); 48 | FS_Printf( f, "used content flags: 0x%08x\n", content); 49 | FS_Printf( f, "\n"); 50 | FS_Printf( f, "-------------------------------------------------\n"); 51 | } 52 | 53 | void CM_DebugCLeafBrushNodes() 54 | { 55 | unsigned int i; 56 | FS_Printf( f, "--------------- CLeafBrushNodes ------------------\n"); 57 | 58 | u_int32_t content = 0; 59 | for(i = 0; i < cm.leafbrushNodesCount; ++i) 60 | { 61 | FS_Printf( f, "Count: %d cont: 0x%08x\n", cm.leafbrushNodes[i].leafBrushCount, cm.leafbrushNodes[i].contents); 62 | content |= cm.leafbrushNodes[i].contents; 63 | } 64 | FS_Printf( f, "\n"); 65 | FS_Printf( f, "used content flags: 0x%08x\n", content); 66 | FS_Printf( f, "\n"); 67 | FS_Printf( f, "-------------------------------------------------\n"); 68 | } 69 | 70 | void CM_DebugCBrush() 71 | { 72 | unsigned int i; 73 | FS_Printf( f, "-------------------- CBrush ----------------------\n"); 74 | u_int32_t content = 0; 75 | for(i = 0; i < cm.numBrushes; ++i) 76 | { 77 | FS_Printf( f, "cont: 0x%08x\n", cm.brushes[i].contents); 78 | content |= cm.brushes[i].contents; 79 | } 80 | FS_Printf( f, "\n"); 81 | FS_Printf( f, "used content flags: 0x%08x\n", content); 82 | FS_Printf( f, "\n"); 83 | FS_Printf( f, "-------------------------------------------------\n"); 84 | } 85 | 86 | void CM_DebugCLeaf() 87 | { 88 | unsigned int i; 89 | FS_Printf( f, "-------------------- cLeaf ----------------------\n"); 90 | u_int32_t brushcontent = 0; 91 | u_int32_t terriancontent = 0; 92 | 93 | for(i = 0; i < cm.numLeafs; ++i) 94 | { 95 | FS_Printf( f, "brushContents: 0x%08x terrainContents: 0x%08x\n", cm.leafs[i].brushContents, cm.leafs[i].terrainContents); 96 | brushcontent |= cm.leafs[i].brushContents; 97 | terriancontent |= cm.leafs[i].terrainContents; 98 | } 99 | FS_Printf( f, "\n"); 100 | FS_Printf( f, "used content flags: 0x%08x 0x%08x\n", brushcontent, terriancontent); 101 | FS_Printf( f, "\n"); 102 | FS_Printf( f, "-----------------------------------------------\n"); 103 | } 104 | 105 | void CM_DebugSubModels() 106 | { 107 | unsigned int i; 108 | FS_Printf( f, "------------- SubModels.cLeaf -----------------\n"); 109 | u_int32_t brushcontent = 0; 110 | 111 | for(i = 0; i < cm.numSubModels; ++i) 112 | { 113 | FS_Printf( f, "brushContents: 0x%08x\n", cm.cmodels[i].leaf.brushContents); 114 | brushcontent |= cm.cmodels[i].leaf.brushContents; 115 | } 116 | FS_Printf( f, "\n"); 117 | FS_Printf( f, "used content flags: 0x%08x\n", brushcontent); 118 | FS_Printf( f, "\n"); 119 | FS_Printf( f, "-----------------------------------------------\n"); 120 | } 121 | 122 | void CM_WalkAABB_Trees() 123 | { 124 | int i; 125 | FS_Printf( f, "---------------- AABB-Trees -------------------\n"); 126 | CollisionAabbTree_t* tr; 127 | 128 | for(i = 0; i < cm.aabbTreeCount; ++i) 129 | { 130 | tr = &cm.aabbTrees[i]; 131 | FS_Printf( f, "AABBTree num=%d, Mat: %s, childs=%d, firstChild=%d\n", i, cm.materials[tr->materialIndex].material, tr->childCount, tr->u.firstChildIndex); 132 | } 133 | FS_Printf( f, "-----------------------------------------------\n"); 134 | } 135 | 136 | void CM_DebugDoAll_f() 137 | { 138 | if (!scrVarPub.developer) 139 | { 140 | Com_Printf("CM_DebugDoAll: developer mode needs to be enabled for debugging.\n"); 141 | return; 142 | } 143 | 144 | f = FS_FOpenFileWrite("cm_debug.log"); 145 | 146 | if (f < 1) 147 | { 148 | Com_DPrintf("CM_DebugDoAll: Couldn't write file cm_debug.log"); 149 | return; 150 | } 151 | 152 | CM_DebugViewBasicDetails(); 153 | CM_DebugPrintMaterialInfo(); 154 | CM_DebugCLeafBrushNodes(); 155 | CM_DebugCBrush(); 156 | CM_DebugCLeaf(); 157 | CM_DebugSubModels(); 158 | CM_WalkAABB_Trees(); 159 | 160 | FS_FCloseFile(f); 161 | 162 | Com_DPrintf("CM_DebugDoAll: info dumped to cm_debug.log\n"); 163 | } 164 | 165 | void CM_AddCommand() 166 | { 167 | Cmd_AddCommand("cm_dumpinfo", CM_DebugDoAll_f); 168 | } 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /bsp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_BSP_HPP_ 2 | #define _GSC_BSP_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void CM_AddCommand(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_HPP_ 2 | #define _CONFIG_HPP_ 3 | 4 | // GSC MODULES 5 | #define COMPILE_BOTS 1 6 | #define COMPILE_ENTITY 1 7 | #define COMPILE_EXEC 1 8 | #define COMPILE_LEVEL 1 9 | #define COMPILE_MEMORY 1 10 | #define COMPILE_MYSQL 1 11 | #define COMPILE_PLAYER 1 12 | #define COMPILE_SQLITE 1 13 | #define COMPILE_UTILS 1 14 | #define COMPILE_WEAPONS 1 15 | 16 | // EXPERIMENTAL FEATURES 17 | #define COMPILE_BSP 0 18 | #define COMPILE_JUMP 0 19 | 20 | // RATE LIMITER 21 | #define COMPILE_RATELIMITER 1 22 | 23 | // EXTRA STUFF 24 | #ifdef EXTRA_CONFIG_INC 25 | #include "extra/config.hpp" 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /cracking.cpp: -------------------------------------------------------------------------------- 1 | #include "cracking.hpp" 2 | 3 | void cracking_hook_function(int from, int to) 4 | { 5 | int relative = to - (from+5); // +5 is the position of next opcode 6 | memset((void *)from, 0xE9, 1); // JMP-OPCODE 7 | memcpy((void *)(from+1), &relative, 4); // set relative address with endian 8 | } 9 | 10 | void cracking_hook_call(int from, int to) 11 | { 12 | int relative = to - (from+5); // +5 is the position of next opcode 13 | memcpy((void *)(from+1), &relative, 4); // set relative address with endian 14 | } 15 | 16 | cHook::cHook(int from, int to) 17 | { 18 | this->from = from; 19 | this->to = to; 20 | } 21 | 22 | void cHook::hook() 23 | { 24 | memcpy((void *)oldCode, (void *)from, 5); 25 | cracking_hook_function(from, to); 26 | } 27 | 28 | void cHook::unhook() 29 | { 30 | memcpy((void *)from, (void *)oldCode, 5); 31 | } 32 | -------------------------------------------------------------------------------- /cracking.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CRACKING_HPP_ 2 | #define _CRACKING_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void cracking_hook_function(int from, int to); 8 | void cracking_hook_call(int from, int to); 9 | 10 | class cHook 11 | { 12 | public: 13 | int from; 14 | int to; 15 | unsigned char oldCode[5]; 16 | cHook(int from, int to); 17 | void hook(); 18 | void unhook(); 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /doit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ./doit.sh clean 4 | # ./doit.sh cod2_1_0 5 | # ./doit.sh cod2_1_2 6 | # ./doit.sh cod2_1_3 7 | 8 | cc="g++" 9 | options="-I. -m32 -fPIC -Wall" 10 | 11 | mysql_found=0 12 | mysql_link="" 13 | 14 | sqlite_found=0 15 | sqlite_link="" 16 | 17 | mysql_libpath="/usr/lib32/libmysqlclient.so" 18 | mysql_libpath2="/usr/lib/i386-linux-gnu/libmysqlclient.so" 19 | mysql_libpath3="/usr/lib/libmysqlclient.so" 20 | 21 | sqlite_libpath="/usr/lib32/libsqlite3.so" 22 | sqlite_libpath2="/usr/lib/i386-linux-gnu/libsqlite3.so" 23 | sqlite_libpath3="/usr/lib/libsqlite3.so" 24 | 25 | pthread_link="" 26 | 27 | if [ "$1" != "clean" ]; then 28 | if [ -e "$mysql_libpath" ] || [ -e "$mysql_libpath2" ] || [ -e "$mysql_libpath3" ]; then 29 | mysql_found=1 30 | mysql_link="-lmysqlclient -L/usr/lib/mysql" 31 | elif [ -d "./vendors/lib" ]; then 32 | export LD_LIBRARY_PATH_32="./vendors/lib" 33 | mysql_found=1 34 | mysql_link="-lmysqlclient -L./vendors/lib" 35 | else 36 | sed -i "/#define COMPILE_MYSQL 1/c\\#define COMPILE_MYSQL 0" config.hpp 37 | fi 38 | 39 | if [ -e "$sqlite_libpath" ] || [ -e "$sqlite_libpath2" ] || [ -e "$sqlite_libpath3" ]; then 40 | sqlite_found=1 41 | sqlite_link="-lsqlite3" 42 | else 43 | sed -i "/#define COMPILE_SQLITE 1/c\\#define COMPILE_SQLITE 0" config.hpp 44 | fi 45 | fi 46 | 47 | if [ "$1" == "clean" ]; then 48 | echo "##### CLEAN OBJECTS #####" 49 | rm objects_* -rf 50 | rm bin -rf 51 | exit 1 52 | 53 | elif [ "$1" == "cod2_1_0" ]; then 54 | constants="-D COD_VERSION=COD2_1_0" 55 | 56 | elif [ "$1" == "cod2_1_2" ]; then 57 | constants="-D COD_VERSION=COD2_1_2" 58 | 59 | elif [ "$1" == "cod2_1_3" ]; then 60 | constants="-D COD_VERSION=COD2_1_3" 61 | 62 | elif [ "$1" == "" ]; then 63 | echo "##### Please specify a command line option #####" 64 | exit 0 65 | 66 | else 67 | echo "##### Unrecognized command line option $1 #####" 68 | exit 0 69 | fi 70 | 71 | if [ -f extra/functions.hpp ]; then 72 | constants+=" -D EXTRA_FUNCTIONS_INC" 73 | fi 74 | 75 | if [ -f extra/config.hpp ]; then 76 | constants+=" -D EXTRA_CONFIG_INC" 77 | fi 78 | 79 | if [ -f extra/includes.hpp ]; then 80 | constants+=" -D EXTRA_INCLUDES_INC" 81 | fi 82 | 83 | if [ -f extra/methods.hpp ]; then 84 | constants+=" -D EXTRA_METHODS_INC" 85 | fi 86 | 87 | mkdir -p bin 88 | mkdir -p objects_"$1" 89 | 90 | echo "##### COMPILE $1 CRACKING.CPP #####" 91 | $cc $options $constants -c cracking.cpp -o objects_"$1"/cracking.opp 92 | 93 | echo "##### COMPILE $1 GSC.CPP #####" 94 | $cc $options $constants -c gsc.cpp -o objects_"$1"/gsc.opp 95 | 96 | if [ "$(< config.hpp grep '#define COMPILE_BOTS' | grep -o '[0-9]')" == "1" ]; then 97 | echo "##### COMPILE $1 GSC_BOTS.CPP #####" 98 | $cc $options $constants -c gsc_bots.cpp -o objects_"$1"/gsc_bots.opp 99 | fi 100 | 101 | if [ "$(< config.hpp grep '#define COMPILE_ENTITY' | grep -o '[0-9]')" == "1" ]; then 102 | echo "##### COMPILE $1 GSC_ENTITY.CPP #####" 103 | $cc $options $constants -c gsc_entity.cpp -o objects_"$1"/gsc_entity.opp 104 | fi 105 | 106 | if [ "$(< config.hpp grep '#define COMPILE_EXEC' | grep -o '[0-9]')" == "1" ]; then 107 | echo "##### COMPILE $1 GSC_EXEC.CPP #####" 108 | $cc $options $constants -c gsc_exec.cpp -o objects_"$1"/gsc_exec.opp 109 | pthread_link="-lpthread" 110 | fi 111 | 112 | if [ "$(< config.hpp grep '#define COMPILE_LEVEL' | grep -o '[0-9]')" == "1" ]; then 113 | echo "##### COMPILE $1 GSC_LEVEL.CPP #####" 114 | $cc $options $constants -c gsc_level.cpp -o objects_"$1"/gsc_level.opp 115 | fi 116 | 117 | if [ "$(< config.hpp grep '#define COMPILE_MEMORY' | grep -o '[0-9]')" == "1" ]; then 118 | echo "##### COMPILE $1 GSC_MEMORY.CPP #####" 119 | $cc $options $constants -c gsc_memory.cpp -o objects_"$1"/gsc_memory.opp 120 | fi 121 | 122 | if [ $mysql_found -eq 1 ]; then 123 | if [ "$(< config.hpp grep '#define COMPILE_MYSQL' | grep -o '[0-9]')" == "1" ]; then 124 | echo "##### COMPILE $1 GSC_MYSQL.CPP #####" 125 | $cc $options $constants -c gsc_mysql.cpp -o objects_"$1"/gsc_mysql.opp 126 | pthread_link="-lpthread" 127 | fi 128 | else 129 | echo "##### WARNING: MySQL lib not found, MySQL compilation skipped #####" 130 | fi 131 | 132 | if [ "$(< config.hpp grep '#define COMPILE_PLAYER' | grep -o '[0-9]')" == "1" ]; then 133 | echo "##### COMPILE $1 GSC_PLAYER.CPP #####" 134 | $cc $options $constants -c gsc_player.cpp -o objects_"$1"/gsc_player.opp 135 | fi 136 | 137 | if [ $sqlite_found -eq 1 ]; then 138 | if [ "$(< config.hpp grep '#define COMPILE_SQLITE' | grep -o '[0-9]')" == "1" ]; then 139 | echo "##### COMPILE $1 GSC_SQLITE.CPP #####" 140 | $cc $options $constants -c gsc_sqlite.cpp -o objects_"$1"/gsc_sqlite.opp 141 | pthread_link="-lpthread" 142 | fi 143 | else 144 | echo "##### WARNING: SQLite lib not found, SQLite compilation skipped #####" 145 | fi 146 | 147 | if [ "$(< config.hpp grep '#define COMPILE_UTILS' | grep -o '[0-9]')" == "1" ]; then 148 | echo "##### COMPILE $1 GSC_UTILS.CPP #####" 149 | $cc $options $constants -c gsc_utils.cpp -o objects_"$1"/gsc_utils.opp 150 | fi 151 | 152 | if [ "$(< config.hpp grep '#define COMPILE_WEAPONS' | grep -o '[0-9]')" == "1" ]; then 153 | echo "##### COMPILE $1 GSC_WEAPONS.CPP #####" 154 | $cc $options $constants -c gsc_weapons.cpp -o objects_"$1"/gsc_weapons.opp 155 | fi 156 | 157 | if [ "$(< config.hpp grep '#define COMPILE_BSP' | grep -o '[0-9]')" == "1" ]; then 158 | echo "##### COMPILE $1 BSP.CPP #####" 159 | $cc $options $constants -c bsp.cpp -o objects_"$1"/bsp.opp 160 | fi 161 | 162 | if [ "$(< config.hpp grep '#define COMPILE_JUMP' | grep -o '[0-9]')" == "1" ]; then 163 | echo "##### COMPILE $1 JUMP.CPP #####" 164 | $cc $options $constants -c jump.cpp -o objects_"$1"/jump.opp 165 | fi 166 | 167 | echo "##### COMPILE $1 LIBCOD.CPP #####" 168 | $cc $options $constants -c libcod.cpp -o objects_"$1"/libcod.opp 169 | 170 | echo "##### COMPILE $1 QVSNPRINTF.C #####" 171 | $cc $options $constants -c lib/qvsnprintf.c -o objects_"$1"/qvsnprintf.opp 172 | 173 | if [ -d extra ]; then 174 | echo "##### COMPILE $1 EXTRAS #####" 175 | ( 176 | cd extra || return 177 | for F in *.cpp; 178 | do 179 | echo "###### COMPILE $1 EXTRA: $F #####" 180 | $cc $options $constants -c "$F" -o ../objects_"$1"/"${F%.cpp}".opp; 181 | done 182 | ) 183 | fi 184 | 185 | echo "##### LINKING lib$1.so #####" 186 | objects="$(ls objects_$1/*.opp)" 187 | $cc -m32 -shared -L/lib32 -o bin/lib"$1".so -ldl $objects $pthread_link $mysql_link $sqlite_link 188 | rm objects_"$1" -r 189 | 190 | if [ $mysql_found -eq 0 ]; then 191 | sed -i "/#define COMPILE_MYSQL 0/c\\#define COMPILE_MYSQL 1" config.hpp 192 | fi 193 | 194 | if [ $sqlite_found -eq 0 ]; then 195 | sed -i "/#define COMPILE_SQLITE 0/c\\#define COMPILE_SQLITE 1" config.hpp 196 | fi 197 | -------------------------------------------------------------------------------- /gsc.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc.hpp" 2 | 3 | const char *stackGetParamTypeAsString(int param) 4 | { 5 | if (param >= Scr_GetNumParam()) 6 | return "UNDEFINED"; 7 | 8 | VariableValue *var; 9 | var = &scrVmPub.top[-param]; 10 | 11 | switch (var->type) 12 | { 13 | case 0: 14 | return "UNDEFINED"; 15 | 16 | case 1: 17 | return "OBJECT"; 18 | 19 | case 2: 20 | return "STRING"; 21 | 22 | case 3: 23 | return "LOCALIZED_STRING"; 24 | 25 | case 4: 26 | return "VECTOR"; 27 | 28 | case 5: 29 | return "FLOAT"; 30 | 31 | case 6: 32 | return "INT"; 33 | 34 | case 7: 35 | return "CODEPOS"; 36 | 37 | case 8: 38 | return "PRECODEPOS"; 39 | 40 | case 9: 41 | return "FUNCTION"; 42 | 43 | case 10: 44 | return "STACK"; 45 | 46 | case 11: 47 | return "ANIMATION"; 48 | 49 | case 12: 50 | return "DEVELOPER_CODEPOS"; 51 | 52 | case 13: 53 | return "INCLUDE_CODEPOS"; 54 | 55 | case 14: 56 | return "THREAD_LIST"; 57 | 58 | case 15: 59 | return "THREAD_1"; 60 | 61 | case 16: 62 | return "THREAD_2"; 63 | 64 | case 17: 65 | return "THREAD_3"; 66 | 67 | case 18: 68 | return "THREAD_4"; 69 | 70 | case 19: 71 | return "STRUCT"; 72 | 73 | case 20: 74 | return "REMOVED_ENTITY"; 75 | 76 | case 21: 77 | return "ENTITY"; 78 | 79 | case 22: 80 | return "ARRAY"; 81 | 82 | case 23: 83 | return "REMOVED_THREAD"; 84 | 85 | default: 86 | return "UNKNOWN TYPE"; 87 | } 88 | } 89 | 90 | void NULL_FUNC(void) {} 91 | 92 | scr_function_t scriptFunctions[] = 93 | { 94 | #if COD_VERSION == COD2_1_0 95 | {"endparty", NULL_FUNC, 0}, 96 | #endif 97 | 98 | #if COMPILE_EXEC == 1 99 | {"exec", gsc_exec, 0}, 100 | {"exec_async_create", gsc_exec_async_create, 0}, 101 | {"exec_async_create_nosave", gsc_exec_async_create_nosave, 0}, 102 | {"exec_async_checkdone", gsc_exec_async_checkdone, 0}, 103 | #endif 104 | 105 | #if COMPILE_LEVEL == 1 106 | {"getnumberofstaticmodels", gsc_level_getnumberofstaticmodels, 0}, 107 | {"getstaticmodelname", gsc_level_getstaticmodelname, 0}, 108 | {"getstaticmodelorigin", gsc_level_getstaticmodelorigin, 0}, 109 | #endif 110 | 111 | #if COMPILE_MEMORY == 1 112 | {"memory_malloc", gsc_memory_malloc, 0}, 113 | {"memory_free", gsc_memory_free, 0}, 114 | {"memory_int_get", gsc_memory_int_get, 0}, 115 | {"memory_int_set", gsc_memory_int_set, 0}, 116 | {"memory_memset", gsc_memory_memset, 0}, 117 | {"binarybuffer_new", gsc_binarybuffer_new, 0}, 118 | {"binarybuffer_free", gsc_binarybuffer_free, 0}, 119 | {"binarybuffer_seek", gsc_binarybuffer_seek, 0}, 120 | {"binarybuffer_write", gsc_binarybuffer_write, 0}, 121 | {"binarybuffer_read", gsc_binarybuffer_read, 0}, 122 | #endif 123 | 124 | #if COMPILE_MYSQL == 1 125 | {"mysql_init", gsc_mysql_init, 0}, 126 | {"mysql_real_connect", gsc_mysql_real_connect, 0}, 127 | {"mysql_close", gsc_mysql_close, 0}, 128 | {"mysql_query", gsc_mysql_query, 0}, 129 | {"mysql_errno", gsc_mysql_errno, 0}, 130 | {"mysql_error", gsc_mysql_error, 0}, 131 | {"mysql_affected_rows", gsc_mysql_affected_rows, 0}, 132 | {"mysql_store_result", gsc_mysql_store_result, 0}, 133 | {"mysql_num_rows", gsc_mysql_num_rows, 0}, 134 | {"mysql_num_fields", gsc_mysql_num_fields, 0}, 135 | {"mysql_field_seek", gsc_mysql_field_seek, 0}, 136 | {"mysql_fetch_field", gsc_mysql_fetch_field, 0}, 137 | {"mysql_fetch_row", gsc_mysql_fetch_row, 0}, 138 | {"mysql_free_result", gsc_mysql_free_result, 0}, 139 | {"mysql_real_escape_string", gsc_mysql_real_escape_string, 0}, 140 | {"mysql_async_create_query", gsc_mysql_async_create_query, 0}, 141 | {"mysql_async_create_query_nosave", gsc_mysql_async_create_query_nosave, 0}, 142 | {"mysql_async_getdone_list", gsc_mysql_async_getdone_list, 0}, 143 | {"mysql_async_getresult_and_free", gsc_mysql_async_getresult_and_free, 0}, 144 | {"mysql_async_initializer", gsc_mysql_async_initializer, 0}, 145 | {"mysql_reuse_connection", gsc_mysql_reuse_connection, 0}, 146 | #endif 147 | 148 | #if COMPILE_PLAYER == 1 149 | {"kick2", gsc_kick_slot, 0}, 150 | #endif 151 | 152 | #if COMPILE_SQLITE == 1 153 | {"sqlite_open", gsc_sqlite_open, 0}, 154 | {"sqlite_query", gsc_sqlite_query, 0}, 155 | {"sqlite_close", gsc_sqlite_close, 0}, 156 | {"sqlite_escape_string", gsc_sqlite_escape_string, 0}, 157 | {"sqlite_databases_count", gsc_sqlite_databases_count, 0}, 158 | {"sqlite_tasks_count", gsc_sqlite_tasks_count, 0}, 159 | {"async_sqlite_initialize", gsc_async_sqlite_initialize, 0}, 160 | {"async_sqlite_create_query", gsc_async_sqlite_create_query, 0}, 161 | {"async_sqlite_create_query_nosave", gsc_async_sqlite_create_query_nosave, 0}, 162 | {"async_sqlite_checkdone", gsc_async_sqlite_checkdone, 0}, 163 | #endif 164 | 165 | #if COMPILE_UTILS == 1 166 | {"printf", gsc_utils_printf, 0}, 167 | {"printoutofband", gsc_utils_outofbandprint, 0}, 168 | {"getarraykeys", gsc_utils_getarraykeys, 0}, 169 | {"getascii", gsc_utils_getAscii, 0}, 170 | {"toupper", gsc_utils_toupper, 0}, 171 | {"system", gsc_utils_system, 0}, 172 | {"exponent", gsc_utils_exponent, 0}, 173 | {"round", gsc_utils_round, 0}, 174 | {"file_link", gsc_utils_file_link, 0}, 175 | {"file_unlink", gsc_utils_file_unlink, 0}, 176 | {"file_exists", gsc_utils_file_exists, 0}, 177 | {"fs_loaddir", gsc_utils_FS_LoadDir, 0}, 178 | {"gettype", gsc_utils_getType, 0}, 179 | {"float", gsc_utils_float, 0}, 180 | {"cmd_executestring", gsc_utils_ExecuteString, 0}, 181 | {"sendgameservercommand", gsc_utils_sendgameservercommand, 0}, 182 | {"scandir", gsc_utils_scandir, 0}, 183 | {"fopen", gsc_utils_fopen, 0}, 184 | {"fread", gsc_utils_fread, 0}, 185 | {"fwrite", gsc_utils_fwrite, 0}, 186 | {"fclose", gsc_utils_fclose, 0}, 187 | {"fsize", gsc_utils_fsize, 0}, 188 | {"ftime", gsc_utils_ftime, 0}, 189 | {"sprintf", gsc_utils_sprintf, 0}, 190 | {"getsystemtime", gsc_utils_getsystemtime, 0}, 191 | {"getserverstarttime", gsc_utils_getserverstarttime, 0}, 192 | {"getlocaltime", gsc_utils_getlocaltime, 0}, 193 | {"g_findconfigstringindex", gsc_G_FindConfigstringIndex, 0}, 194 | {"g_findconfigstringindexoriginal", gsc_G_FindConfigstringIndexOriginal, 0}, 195 | {"getconfigstring", gsc_get_configstring, 0}, 196 | {"setconfigstring", gsc_set_configstring, 0}, 197 | {"makelocalizedstring", gsc_make_localized_string, 0}, 198 | {"sqrt", gsc_utils_sqrt, 0}, 199 | {"sqrtinv", gsc_utils_sqrtInv, 0}, 200 | {"getlasttestclientnumber", gsc_utils_getlasttestclientnumber, 0}, 201 | {"bullethiteffect", gsc_utils_bullethiteffect, 0}, 202 | {"vectorscale", gsc_utils_vectorscale, 0}, 203 | {"remove_file", gsc_utils_remove_file, 0}, 204 | {"putchar", gsc_utils_putchar, 0}, 205 | {"remotecommand", gsc_utils_remotecommand, 0}, 206 | #endif 207 | 208 | #if COMPILE_WEAPONS == 1 209 | {"getweaponmaxammo", gsc_weapons_getweaponmaxammo, 0}, 210 | {"setweaponmaxammo", gsc_weapons_setweaponmaxammo, 0}, 211 | {"getweaponclipsize", gsc_weapons_getweaponclipsize, 0}, 212 | {"setweaponclipsize", gsc_weapons_setweaponclipsize, 0}, 213 | {"getweapondamage", gsc_weapons_getweapondamage, 0}, 214 | {"setweapondamage", gsc_weapons_setweapondamage, 0}, 215 | {"getweaponmeleedamage", gsc_weapons_getweaponmeleedamage, 0}, 216 | {"setweaponmeleedamage", gsc_weapons_setweaponmeleedamage, 0}, 217 | {"getweaponfiretime", gsc_weapons_getweaponfiretime, 0}, 218 | {"setweaponfiretime", gsc_weapons_setweaponfiretime, 0}, 219 | {"getweaponmeleetime", gsc_weapons_getweaponmeleetime, 0}, 220 | {"setweaponmeleetime", gsc_weapons_setweaponmeleetime, 0}, 221 | {"getweaponreloadtime", gsc_weapons_getweaponreloadtime, 0}, 222 | {"setweaponreloadtime", gsc_weapons_setweaponreloadtime, 0}, 223 | {"getweaponreloademptytime", gsc_weapons_getweaponreloademptytime, 0}, 224 | {"setweaponreloademptytime", gsc_weapons_setweaponreloademptytime, 0}, 225 | {"getweaponcookable", gsc_weapons_getweaponcookable, 0}, 226 | {"setweaponcookable", gsc_weapons_setweaponcookable, 0}, 227 | {"getweaponhitlocmultiplier", gsc_weapons_getweaponhitlocmultiplier, 0}, 228 | {"setweaponhitlocmultiplier", gsc_weapons_setweaponhitlocmultiplier, 0}, 229 | {"getloadedweapons", gsc_weapons_getloadedweapons, 0}, 230 | #endif 231 | 232 | #ifdef EXTRA_FUNCTIONS_INC 233 | #include "extra/functions.hpp" 234 | #endif 235 | 236 | {NULL, NULL, 0} /* terminator */ 237 | }; 238 | 239 | xfunction_t Scr_GetCustomFunction(const char **fname, qboolean *fdev) 240 | { 241 | xfunction_t m = Scr_GetFunction(fname, fdev); 242 | 243 | if (m) 244 | return m; 245 | 246 | for (int i = 0; scriptFunctions[i].name; i++) 247 | { 248 | if (strcasecmp(*fname, scriptFunctions[i].name)) 249 | continue; 250 | 251 | scr_function_t func = scriptFunctions[i]; 252 | 253 | *fname = func.name; 254 | *fdev = func.developer; 255 | 256 | return func.call; 257 | } 258 | 259 | return NULL; 260 | } 261 | 262 | scr_method_t scriptMethods[] = 263 | { 264 | #if COMPILE_BOTS == 1 265 | {"setwalkdir", gsc_bots_set_walkdir, 0}, 266 | {"setlean", gsc_bots_set_lean, 0}, 267 | {"setbotstance", gsc_bots_set_stance, 0}, 268 | {"thrownade", gsc_bots_thrownade, 0}, 269 | {"fireweapon", gsc_bots_fireweapon, 0}, 270 | {"meleeweapon", gsc_bots_meleeweapon, 0}, 271 | {"reloadweapon", gsc_bots_reloadweapon, 0}, 272 | {"adsaim", gsc_bots_adsaim, 0}, 273 | {"switchtoweaponid", gsc_bots_switchtoweaponid, 0}, 274 | #endif 275 | 276 | #if COMPILE_ENTITY == 1 277 | {"setalive", gsc_entity_setalive, 0}, 278 | {"setbounds", gsc_entity_setbounds, 0}, 279 | #endif 280 | 281 | #if COMPILE_PLAYER == 1 282 | {"getstance", gsc_player_stance_get, 0}, 283 | {"setstance", gsc_player_stance_set, 0}, 284 | {"setvelocity", gsc_player_velocity_set, 0}, 285 | {"addvelocity", gsc_player_velocity_add, 0}, 286 | {"getvelocity", gsc_player_velocity_get, 0}, 287 | {"aimbuttonpressed", gsc_player_button_ads, 0}, 288 | {"leftbuttonpressed", gsc_player_button_left, 0}, 289 | {"rightbuttonpressed", gsc_player_button_right, 0}, 290 | {"forwardbuttonpressed", gsc_player_button_forward, 0}, 291 | {"backbuttonpressed", gsc_player_button_back, 0}, 292 | {"leanleftbuttonpressed", gsc_player_button_leanleft, 0}, 293 | {"leanrightbuttonpressed", gsc_player_button_leanright, 0}, 294 | {"jumpbuttonpressed", gsc_player_button_jump, 0}, 295 | {"reloadbuttonpressed", gsc_player_button_reload, 0}, 296 | {"fragbuttonpressed", gsc_player_button_frag, 0}, 297 | {"smokebuttonpressed", gsc_player_button_smoke, 0}, 298 | {"getip", gsc_player_getip, 0}, 299 | {"getping", gsc_player_getping, 0}, 300 | {"getspectatorclient", gsc_player_spectatorclient_get, 0}, 301 | {"clientcommand", gsc_player_clientcommand, 0}, 302 | {"getlastconnecttime", gsc_player_getlastconnecttime, 0}, 303 | {"getlastmsg", gsc_player_getlastmsg, 0}, 304 | {"getaddresstype", gsc_player_addresstype, 0}, 305 | {"getclientstate", gsc_player_getclientstate, 0}, 306 | {"renameclient", gsc_player_renameclient, 0}, 307 | {"get_userinfo", gsc_player_get_userinfo, 0}, 308 | {"set_userinfo", gsc_player_set_userinfo, 0}, 309 | {"printoutofband", gsc_player_outofbandprint, 0}, 310 | {"connectionlesspacket", gsc_player_connectionlesspacket, 0}, 311 | {"clientuserinfochanged", gsc_player_clientuserinfochanged, 0}, 312 | {"resetnextreliabletime", gsc_player_resetnextreliabletime, 0}, 313 | {"setg_speed", gsc_player_setg_speed, 0}, 314 | {"setg_gravity", gsc_player_setg_gravity, 0}, 315 | {"setweaponfiremeleedelay", gsc_player_setweaponfiremeleedelay, 0}, 316 | {"setanim", gsc_player_set_anim, 0}, 317 | {"getjumpslowdowntimer", gsc_player_getjumpslowdowntimer, 0}, 318 | {"clearjumpstate", gsc_player_clearjumpstate, 0}, 319 | {"getcooktime", gsc_player_getcooktime, 0}, 320 | {"setguid", gsc_player_setguid, 0}, 321 | {"clienthasclientmuted", gsc_player_clienthasclientmuted, 0}, 322 | {"getlastgamestatesize", gsc_player_getlastgamestatesize, 0}, 323 | {"getfps", gsc_player_getfps, 0}, 324 | {"ismantling", gsc_player_ismantling, 0}, 325 | {"isonladder", gsc_player_isonladder, 0}, 326 | {"isusingturret", gsc_player_isusingturret, 0}, 327 | {"isbot", gsc_player_isbot, 0}, 328 | {"disableitempickup", gsc_player_disableitempickup, 0}, 329 | {"enableitempickup", gsc_player_enableitempickup, 0}, 330 | {"getcurrentoffhandslotammo", gsc_player_getcurrentoffhandslotammo, 0}, 331 | #if COMPILE_JUMP == 1 332 | {"setjump_height", gsc_player_setjump_height, 0}, 333 | {"setjump_slowdownenable", gsc_player_setjump_slowdownenable, 0}, 334 | #endif 335 | #endif 336 | 337 | #if COMPILE_SQLITE == 1 338 | {"async_sqlite_create_entity_query", gsc_async_sqlite_create_entity_query, 0}, 339 | {"async_sqlite_create_entity_query_nosave", gsc_async_sqlite_create_entity_query_nosave, 0}, 340 | #endif 341 | 342 | #ifdef EXTRA_METHODS_INC 343 | #include "extra/methods.hpp" 344 | #endif 345 | 346 | {NULL, NULL, 0} /* terminator */ 347 | }; 348 | 349 | xmethod_t Scr_GetCustomMethod(const char **fname, qboolean *fdev) 350 | { 351 | xmethod_t m = Scr_GetMethod(fname, fdev); 352 | 353 | if (m) 354 | return m; 355 | 356 | for (int i = 0; scriptMethods[i].name; i++) 357 | { 358 | if (strcasecmp(*fname, scriptMethods[i].name)) 359 | continue; 360 | 361 | scr_method_t func = scriptMethods[i]; 362 | 363 | *fname = func.name; 364 | *fdev = func.developer; 365 | 366 | return func.call; 367 | } 368 | 369 | return NULL; 370 | } 371 | 372 | int stackGetParamType(int param) 373 | { 374 | if (param >= Scr_GetNumParam()) 375 | return STACK_UNDEFINED; 376 | 377 | VariableValue *var; 378 | var = &scrVmPub.top[-param]; 379 | 380 | return var->type; 381 | } 382 | 383 | void stackError(const char *format, ...) 384 | { 385 | char errorMessage[COD2_MAX_STRINGLENGTH]; 386 | va_list va; 387 | 388 | va_start(va, format); 389 | Q_vsnprintf(errorMessage, sizeof(errorMessage), format, va); 390 | va_end(va); 391 | 392 | errorMessage[COD2_MAX_STRINGLENGTH - 1] = '\0'; 393 | 394 | Scr_Error(errorMessage); 395 | } 396 | 397 | int stackGetParams(const char *params, ...) 398 | { 399 | va_list args; 400 | va_start(args, params); 401 | 402 | int errors = 0; 403 | 404 | for (size_t i = 0; i < strlen(params); i++) 405 | { 406 | switch (params[i]) 407 | { 408 | case ' ': // ignore param 409 | break; 410 | 411 | case 'i': 412 | { 413 | int *tmp = va_arg(args, int *); 414 | if ( ! stackGetParamInt(i, tmp)) 415 | { 416 | Com_DPrintf("\nstackGetParams() Param %i is not an int\n", i); 417 | errors++; 418 | } 419 | break; 420 | } 421 | 422 | case 'v': 423 | { 424 | float *tmp = va_arg(args, float *); 425 | if ( ! stackGetParamVector(i, tmp)) 426 | { 427 | Com_DPrintf("\nstackGetParams() Param %i is not a vector\n", i); 428 | errors++; 429 | } 430 | break; 431 | } 432 | 433 | case 'f': 434 | { 435 | float *tmp = va_arg(args, float *); 436 | if ( ! stackGetParamFloat(i, tmp)) 437 | { 438 | Com_DPrintf("\nstackGetParams() Param %i is not a float\n", i); 439 | errors++; 440 | } 441 | break; 442 | } 443 | 444 | case 's': 445 | { 446 | char **tmp = va_arg(args, char **); 447 | if ( ! stackGetParamString(i, tmp)) 448 | { 449 | Com_DPrintf("\nstackGetParams() Param %i is not a string\n", i); 450 | errors++; 451 | } 452 | break; 453 | } 454 | 455 | case 'c': 456 | { 457 | unsigned int *tmp = va_arg(args, unsigned int *); 458 | if ( ! stackGetParamConstString(i, tmp)) 459 | { 460 | Com_DPrintf("\nstackGetParams() Param %i is not a const string\n", i); 461 | errors++; 462 | } 463 | break; 464 | } 465 | 466 | default: 467 | errors++; 468 | Com_DPrintf("\nUnknown identifier [%s] passed to stackGetParams()\n", params[i]); 469 | break; 470 | } 471 | } 472 | 473 | va_end(args); 474 | return errors == 0; // success if no errors 475 | } 476 | 477 | int stackGetParamInt(int param, int *value) 478 | { 479 | if (param >= Scr_GetNumParam()) 480 | return 0; 481 | 482 | VariableValue *var; 483 | var = &scrVmPub.top[-param]; 484 | 485 | if (var->type == STACK_FLOAT) 486 | { 487 | *value = var->u.floatValue; 488 | return 1; 489 | } 490 | 491 | if (var->type != STACK_INT) 492 | return 0; 493 | 494 | *value = var->u.intValue; 495 | 496 | return 1; 497 | } 498 | 499 | int stackGetParamFunction(int param, int *value) 500 | { 501 | if (param >= Scr_GetNumParam()) 502 | return 0; 503 | 504 | VariableValue *var; 505 | var = &scrVmPub.top[-param]; 506 | 507 | if (var->type != STACK_FUNCTION) 508 | return 0; 509 | 510 | *value = var->u.codePosValue - scrVarPub.programBuffer; 511 | 512 | return 1; 513 | } 514 | 515 | int stackGetParamString(int param, char **value) 516 | { 517 | if (param >= Scr_GetNumParam()) 518 | return 0; 519 | 520 | VariableValue *var; 521 | var = &scrVmPub.top[-param]; 522 | 523 | if (var->type != STACK_STRING) 524 | return 0; 525 | 526 | *value = SL_ConvertToString(var->u.stringValue); 527 | 528 | return 1; 529 | } 530 | 531 | int stackGetParamConstString(int param, unsigned int *value) 532 | { 533 | if (param >= Scr_GetNumParam()) 534 | return 0; 535 | 536 | VariableValue *var; 537 | var = &scrVmPub.top[-param]; 538 | 539 | if (var->type != STACK_STRING) 540 | return 0; 541 | 542 | *value = var->u.stringValue; 543 | 544 | return 1; 545 | } 546 | 547 | int stackGetParamVector(int param, vec3_t value) 548 | { 549 | if (param >= Scr_GetNumParam()) 550 | return 0; 551 | 552 | VariableValue *var; 553 | var = &scrVmPub.top[-param]; 554 | 555 | if (var->type != STACK_VECTOR) 556 | return 0; 557 | 558 | VectorCopy(var->u.vectorValue, value); 559 | 560 | return 1; 561 | } 562 | 563 | int stackGetParamFloat(int param, float *value) 564 | { 565 | if (param >= Scr_GetNumParam()) 566 | return 0; 567 | 568 | VariableValue *var; 569 | var = &scrVmPub.top[-param]; 570 | 571 | if (var->type == STACK_INT) 572 | { 573 | *value = var->u.intValue; 574 | return 1; 575 | } 576 | 577 | if (var->type != STACK_FLOAT) 578 | return 0; 579 | 580 | *value = var->u.floatValue; 581 | 582 | return 1; 583 | } 584 | 585 | int stackGetParamObject(int param, unsigned int *value) 586 | { 587 | if (param >= Scr_GetNumParam()) 588 | return 0; 589 | 590 | VariableValue *var; 591 | var = &scrVmPub.top[-param]; 592 | 593 | if (var->type != STACK_OBJECT) 594 | return 0; 595 | 596 | *value = var->u.pointerValue; 597 | 598 | return 1; 599 | } 600 | 601 | /** 602 | * @brief Base time in seconds 603 | */ 604 | time_t sys_timeBase = 0; 605 | 606 | /** 607 | * @brief Current time in ms, using sys_timeBase as origin 608 | */ 609 | uint64_t Sys_Milliseconds64(void) 610 | { 611 | struct timeval tp; 612 | 613 | gettimeofday(&tp, NULL); 614 | 615 | if (!sys_timeBase) 616 | { 617 | sys_timeBase = tp.tv_sec; 618 | return tp.tv_usec / 1000; 619 | } 620 | 621 | return (tp.tv_sec - sys_timeBase) * 1000 + tp.tv_usec / 1000; 622 | } 623 | -------------------------------------------------------------------------------- /gsc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_HPP_ 2 | #define _GSC_HPP_ 3 | 4 | #define COD2_1_0 210 5 | #define COD2_1_2 212 6 | #define COD2_1_3 213 7 | 8 | #define COD2_MAX_STRINGLENGTH 1024 9 | 10 | /* default stuff */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include // dlcall 17 | #include // va_args 18 | #include //link, unlink, usleep 19 | #include // dir stuff 20 | #include // mprotect 21 | #include // stacktrace 22 | #include // offsetof 23 | #include // fsize 24 | #include // getsystemtime 25 | #include // milliseconds 26 | #include // isdigit 27 | 28 | #include "config.hpp" 29 | #include "declarations.hpp" 30 | #include "functions.hpp" 31 | #include "cracking.hpp" 32 | 33 | #if COMPILE_BOTS == 1 34 | #include "gsc_bots.hpp" 35 | #endif 36 | 37 | #if COMPILE_BSP == 1 38 | #include "bsp.hpp" 39 | #endif 40 | 41 | #if COMPILE_ENTITY == 1 42 | #include "gsc_entity.hpp" 43 | #endif 44 | 45 | #if COMPILE_EXEC == 1 46 | #include "gsc_exec.hpp" 47 | #endif 48 | 49 | #if COMPILE_JUMP == 1 50 | #include "jump.hpp" 51 | #endif 52 | 53 | #if COMPILE_LEVEL == 1 54 | #include "gsc_level.hpp" 55 | #endif 56 | 57 | #if COMPILE_MEMORY == 1 58 | #include "gsc_memory.hpp" 59 | #endif 60 | 61 | #if COMPILE_MYSQL == 1 62 | #include "gsc_mysql.hpp" 63 | #endif 64 | 65 | #if COMPILE_PLAYER == 1 66 | #include "gsc_player.hpp" 67 | #endif 68 | 69 | #if COMPILE_SQLITE == 1 70 | #include "gsc_sqlite.hpp" 71 | #endif 72 | 73 | #if COMPILE_UTILS == 1 74 | #include "gsc_utils.hpp" 75 | #endif 76 | 77 | #if COMPILE_WEAPONS == 1 78 | #include "gsc_weapons.hpp" 79 | #endif 80 | 81 | #ifdef EXTRA_INCLUDES_INC 82 | #include "extra/includes.hpp" 83 | #endif 84 | 85 | #define STACK_UNDEFINED 0 86 | #define STACK_OBJECT 1 87 | #define STACK_STRING 2 88 | #define STACK_LOCALIZED_STRING 3 89 | #define STACK_VECTOR 4 90 | #define STACK_FLOAT 5 91 | #define STACK_INT 6 92 | #define STACK_CODEPOS 7 93 | #define STACK_PRECODEPOS 8 94 | #define STACK_FUNCTION 9 95 | #define STACK_STACK 10 96 | #define STACK_ANIMATION 11 97 | #define STACK_DEVELOPER_CODEPOS 12 98 | #define STACK_INCLUDE_CODEPOS 13 99 | #define STACK_THREAD_LIST 14 100 | #define STACK_THREAD_1 15 101 | #define STACK_THREAD_2 16 102 | #define STACK_THREAD_3 17 103 | #define STACK_THREAD_4 18 104 | #define STACK_STRUCT 19 105 | #define STACK_REMOVED_ENTITY 20 106 | #define STACK_ENTITY 21 107 | #define STACK_ARRAY 22 108 | #define STACK_REMOVED_THREAD 23 109 | 110 | #define stackPushUndefined Scr_AddUndefined 111 | #define stackPushBool Scr_AddBool 112 | #define stackPushInt Scr_AddInt 113 | #define stackPushFloat Scr_AddFloat 114 | #define stackPushString Scr_AddString 115 | #define stackPushVector Scr_AddVector 116 | #define stackPushEntity Scr_AddEntity 117 | #define stackPushArray Scr_MakeArray 118 | #define stackPushArrayLast Scr_AddArray 119 | #define stackPushObject Scr_AddObject 120 | 121 | #ifndef Q_vsnprintf 122 | int Q_vsnprintf(char *s0, size_t size, const char *fmt, va_list args); 123 | #endif 124 | 125 | int stackGetParamType(int param); 126 | const char *stackGetParamTypeAsString(int param); 127 | 128 | int stackGetParams(const char *params, ...); 129 | void stackError(const char *format, ...); 130 | 131 | int stackGetParamInt(int param, int *value); 132 | int stackGetParamFunction(int param, int *value); 133 | int stackGetParamString(int param, char **value); 134 | int stackGetParamConstString(int param, unsigned int *value); 135 | int stackGetParamVector(int param, vec3_t value); 136 | int stackGetParamFloat(int param, float *value); 137 | int stackGetParamObject(int param, unsigned int *value); 138 | 139 | xfunction_t Scr_GetCustomFunction(const char **fname, qboolean *fdev); 140 | xmethod_t Scr_GetCustomMethod(const char **fname, qboolean *fdev); 141 | 142 | uint64_t Sys_Milliseconds64(void); 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /gsc_bots.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_bots.hpp" 2 | 3 | #if COMPILE_BOTS == 1 4 | 5 | void gsc_bots_set_walkdir(scr_entref_t id) 6 | { 7 | char *dir; 8 | 9 | if ( ! stackGetParams("s", &dir)) 10 | { 11 | stackError("gsc_bots_set_walkdir() argument is undefined or has a wrong type"); 12 | stackPushUndefined(); 13 | return; 14 | } 15 | 16 | if (id >= MAX_CLIENTS) 17 | { 18 | stackError("gsc_bots_set_walkdir() entity %i is not a player", id); 19 | stackPushUndefined(); 20 | return; 21 | } 22 | 23 | client_t *client = &svs.clients[id]; 24 | 25 | if (client->netchan.remoteAddress.type != NA_BOT) 26 | { 27 | stackError("gsc_bots_set_walkdir() player %i is not a bot", id); 28 | stackPushUndefined(); 29 | return; 30 | } 31 | 32 | extern char bot_forwardmove[MAX_CLIENTS]; 33 | extern char bot_rightmove[MAX_CLIENTS]; 34 | 35 | if (strcmp(dir, "none") == 0) 36 | { 37 | bot_forwardmove[id] = KEY_MASK_NONE; 38 | bot_rightmove[id] = KEY_MASK_NONE; 39 | } 40 | else if (strcmp(dir, "forward") == 0) 41 | bot_forwardmove[id] = KEY_MASK_FORWARD; 42 | else if (strcmp(dir, "back") == 0) 43 | bot_forwardmove[id] = KEY_MASK_BACK; 44 | else if (strcmp(dir, "right") == 0) 45 | bot_rightmove[id] = KEY_MASK_MOVERIGHT; 46 | else if (strcmp(dir, "left") == 0) 47 | bot_rightmove[id] = KEY_MASK_MOVELEFT; 48 | else 49 | { 50 | stackError("gsc_bots_set_walkdir() invalid argument '%s'. Valid arguments are: 'none' 'forward' 'back' 'right' 'left'", dir); 51 | stackPushUndefined(); 52 | return; 53 | } 54 | 55 | stackPushBool(qtrue); 56 | } 57 | 58 | void gsc_bots_set_lean(scr_entref_t id) 59 | { 60 | char *lean; 61 | 62 | if ( ! stackGetParams("s", &lean)) 63 | { 64 | stackError("gsc_bots_set_lean() argument is undefined or has a wrong type"); 65 | stackPushUndefined(); 66 | return; 67 | } 68 | 69 | if (id >= MAX_CLIENTS) 70 | { 71 | stackError("gsc_bots_set_lean() entity %i is not a player", id); 72 | stackPushUndefined(); 73 | return; 74 | } 75 | 76 | client_t *client = &svs.clients[id]; 77 | 78 | if (client->netchan.remoteAddress.type != NA_BOT) 79 | { 80 | stackError("gsc_bots_set_lean() player %i is not a bot", id); 81 | stackPushUndefined(); 82 | return; 83 | } 84 | 85 | extern int bot_buttons[MAX_CLIENTS]; 86 | 87 | if (strcmp(lean, "none") == 0) 88 | bot_buttons[id] &= ~(KEY_MASK_LEANLEFT | KEY_MASK_LEANRIGHT); 89 | else if (strcmp(lean, "left") == 0) 90 | bot_buttons[id] |= KEY_MASK_LEANLEFT; 91 | else if (strcmp(lean, "right") == 0) 92 | bot_buttons[id] |= KEY_MASK_LEANRIGHT; 93 | else 94 | { 95 | stackError("gsc_bots_set_lean() invalid argument '%s'. Valid arguments are: 'right' 'left'", lean); 96 | stackPushUndefined(); 97 | return; 98 | } 99 | 100 | stackPushBool(qtrue); 101 | } 102 | 103 | void gsc_bots_set_stance(scr_entref_t id) 104 | { 105 | char *stance; 106 | 107 | if ( ! stackGetParams("s", &stance)) 108 | { 109 | stackError("gsc_bots_set_stance() argument is undefined or has a wrong type"); 110 | stackPushUndefined(); 111 | return; 112 | } 113 | 114 | if (id >= MAX_CLIENTS) 115 | { 116 | stackError("gsc_bots_set_stance() entity %i is not a player", id); 117 | stackPushUndefined(); 118 | return; 119 | } 120 | 121 | client_t *client = &svs.clients[id]; 122 | 123 | if (client->netchan.remoteAddress.type != NA_BOT) 124 | { 125 | stackError("gsc_bots_set_stance() player %i is not a bot", id); 126 | stackPushUndefined(); 127 | return; 128 | } 129 | 130 | extern int bot_buttons[MAX_CLIENTS]; 131 | 132 | if (strcmp(stance, "stand") == 0) 133 | bot_buttons[id] &= ~(KEY_MASK_CROUCH | KEY_MASK_PRONE | KEY_MASK_JUMP); 134 | else if (strcmp(stance, "crouch") == 0) 135 | bot_buttons[id] |= KEY_MASK_CROUCH; 136 | else if (strcmp(stance, "prone") == 0) 137 | bot_buttons[id] |= KEY_MASK_PRONE; 138 | else if (strcmp(stance, "jump") == 0) 139 | bot_buttons[id] |= KEY_MASK_JUMP; 140 | else 141 | { 142 | stackError("gsc_bots_set_stance() invalid argument '%s'. Valid arguments are: 'stand' 'crouch' 'prone' 'jump'", stance); 143 | stackPushUndefined(); 144 | return; 145 | } 146 | 147 | stackPushBool(qtrue); 148 | } 149 | 150 | void gsc_bots_thrownade(scr_entref_t id) 151 | { 152 | int grenade; 153 | 154 | if ( ! stackGetParams("i", &grenade)) 155 | { 156 | stackError("gsc_bots_thrownade() argument is undefined or has a wrong type"); 157 | stackPushUndefined(); 158 | return; 159 | } 160 | 161 | if (id >= MAX_CLIENTS) 162 | { 163 | stackError("gsc_bots_thrownade() entity %i is not a player", id); 164 | stackPushUndefined(); 165 | return; 166 | } 167 | 168 | client_t *client = &svs.clients[id]; 169 | 170 | if (client->netchan.remoteAddress.type != NA_BOT) 171 | { 172 | stackError("gsc_bots_thrownade() player %i is not a bot", id); 173 | stackPushUndefined(); 174 | return; 175 | } 176 | 177 | extern int bot_buttons[MAX_CLIENTS]; 178 | 179 | if (!grenade) 180 | bot_buttons[id] &= ~KEY_MASK_FRAG; 181 | else 182 | bot_buttons[id] |= KEY_MASK_FRAG; 183 | 184 | stackPushBool(qtrue); 185 | } 186 | 187 | void gsc_bots_fireweapon(scr_entref_t id) 188 | { 189 | int shoot; 190 | 191 | if ( ! stackGetParams("i", &shoot)) 192 | { 193 | stackError("gsc_bots_fireweapon() argument is undefined or has a wrong type"); 194 | stackPushUndefined(); 195 | return; 196 | } 197 | 198 | if (id >= MAX_CLIENTS) 199 | { 200 | stackError("gsc_bots_fireweapon() entity %i is not a player", id); 201 | stackPushUndefined(); 202 | return; 203 | } 204 | 205 | client_t *client = &svs.clients[id]; 206 | 207 | if (client->netchan.remoteAddress.type != NA_BOT) 208 | { 209 | stackError("gsc_bots_fireweapon() player %i is not a bot", id); 210 | stackPushUndefined(); 211 | return; 212 | } 213 | 214 | extern int bot_buttons[MAX_CLIENTS]; 215 | 216 | if (!shoot) 217 | bot_buttons[id] &= ~KEY_MASK_FIRE; 218 | else 219 | bot_buttons[id] |= KEY_MASK_FIRE; 220 | 221 | stackPushBool(qtrue); 222 | } 223 | 224 | void gsc_bots_meleeweapon(scr_entref_t id) 225 | { 226 | int melee; 227 | 228 | if ( ! stackGetParams("i", &melee)) 229 | { 230 | stackError("gsc_bots_meleeweapon() argument is undefined or has a wrong type"); 231 | stackPushUndefined(); 232 | return; 233 | } 234 | 235 | if (id >= MAX_CLIENTS) 236 | { 237 | stackError("gsc_bots_meleeweapon() entity %i is not a player", id); 238 | stackPushUndefined(); 239 | return; 240 | } 241 | 242 | client_t *client = &svs.clients[id]; 243 | 244 | if (client->netchan.remoteAddress.type != NA_BOT) 245 | { 246 | stackError("gsc_bots_meleeweapon() player %i is not a bot", id); 247 | stackPushUndefined(); 248 | return; 249 | } 250 | 251 | extern int bot_buttons[MAX_CLIENTS]; 252 | 253 | if (!melee) 254 | bot_buttons[id] &= ~KEY_MASK_MELEE; 255 | else 256 | bot_buttons[id] |= KEY_MASK_MELEE; 257 | 258 | stackPushBool(qtrue); 259 | } 260 | 261 | void gsc_bots_reloadweapon(scr_entref_t id) 262 | { 263 | int reload; 264 | 265 | if ( ! stackGetParams("i", &reload)) 266 | { 267 | stackError("gsc_bots_reloadweapon() argument is undefined or has a wrong type"); 268 | stackPushUndefined(); 269 | return; 270 | } 271 | 272 | if (id >= MAX_CLIENTS) 273 | { 274 | stackError("gsc_bots_reloadweapon() entity %i is not a player", id); 275 | stackPushUndefined(); 276 | return; 277 | } 278 | 279 | client_t *client = &svs.clients[id]; 280 | 281 | if (client->netchan.remoteAddress.type != NA_BOT) 282 | { 283 | stackError("gsc_bots_reloadweapon() player %i is not a bot", id); 284 | stackPushUndefined(); 285 | return; 286 | } 287 | 288 | extern int bot_buttons[MAX_CLIENTS]; 289 | 290 | if (!reload) 291 | bot_buttons[id] &= ~KEY_MASK_RELOAD; 292 | else 293 | bot_buttons[id] |= KEY_MASK_RELOAD; 294 | 295 | stackPushBool(qtrue); 296 | } 297 | 298 | void gsc_bots_adsaim(scr_entref_t id) 299 | { 300 | int ads; 301 | 302 | if ( ! stackGetParams("i", &ads)) 303 | { 304 | stackError("gsc_bots_adsaim() argument is undefined or has a wrong type"); 305 | stackPushUndefined(); 306 | return; 307 | } 308 | 309 | if (id >= MAX_CLIENTS) 310 | { 311 | stackError("gsc_bots_adsaim() entity %i is not a player", id); 312 | stackPushUndefined(); 313 | return; 314 | } 315 | 316 | client_t *client = &svs.clients[id]; 317 | 318 | if (client->netchan.remoteAddress.type != NA_BOT) 319 | { 320 | stackError("gsc_bots_adsaim() player %i is not a bot", id); 321 | stackPushUndefined(); 322 | return; 323 | } 324 | 325 | extern int bot_buttons[MAX_CLIENTS]; 326 | 327 | if (!ads) 328 | bot_buttons[id] &= ~KEY_MASK_ADS_MODE; 329 | else 330 | bot_buttons[id] |= KEY_MASK_ADS_MODE; 331 | 332 | stackPushBool(qtrue); 333 | } 334 | 335 | void gsc_bots_switchtoweaponid(scr_entref_t id) 336 | { 337 | int weaponid; 338 | 339 | if ( ! stackGetParams("i", &weaponid)) 340 | { 341 | stackError("gsc_bots_switchtoweaponid() argument is undefined or has a wrong type"); 342 | stackPushUndefined(); 343 | return; 344 | } 345 | 346 | if (id >= MAX_CLIENTS) 347 | { 348 | stackError("gsc_bots_switchtoweaponid() entity %i is not a player", id); 349 | stackPushUndefined(); 350 | return; 351 | } 352 | 353 | client_t *client = &svs.clients[id]; 354 | 355 | if (client->netchan.remoteAddress.type != NA_BOT) 356 | { 357 | stackError("gsc_bots_switchtoweaponid() player %i is not a bot", id); 358 | stackPushUndefined(); 359 | return; 360 | } 361 | 362 | extern int bot_weapon[MAX_CLIENTS]; 363 | 364 | bot_weapon[id] = weaponid; 365 | 366 | stackPushBool(qtrue); 367 | } 368 | 369 | #endif 370 | -------------------------------------------------------------------------------- /gsc_bots.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_BOTS_HPP_ 2 | #define _GSC_BOTS_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_bots_set_walkdir(scr_entref_t id); 8 | void gsc_bots_set_lean(scr_entref_t id); 9 | void gsc_bots_set_stance(scr_entref_t id); 10 | void gsc_bots_thrownade(scr_entref_t id); 11 | void gsc_bots_fireweapon(scr_entref_t id); 12 | void gsc_bots_meleeweapon(scr_entref_t id); 13 | void gsc_bots_reloadweapon(scr_entref_t id); 14 | void gsc_bots_adsaim(scr_entref_t id); 15 | void gsc_bots_switchtoweaponid(scr_entref_t id); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /gsc_entity.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_entity.hpp" 2 | 3 | #if COMPILE_ENTITY == 1 4 | 5 | void gsc_entity_setalive(scr_entref_t id) 6 | { 7 | int isAlive; 8 | 9 | if ( ! stackGetParams("i", &isAlive)) 10 | { 11 | stackError("gsc_entity_setalive() argument is undefined or has a wrong type"); 12 | stackPushUndefined(); 13 | return; 14 | } 15 | 16 | gentity_t *entity = &g_entities[id]; 17 | 18 | entity->takedamage = isAlive; 19 | stackPushBool(qtrue); 20 | } 21 | 22 | void gsc_entity_setbounds(scr_entref_t id) 23 | { 24 | float width, height; 25 | 26 | if ( ! stackGetParams("ff", &width, &height)) 27 | { 28 | stackError("gsc_entity_setbounds() one or more arguments is undefined or has a wrong type"); 29 | stackPushUndefined(); 30 | return; 31 | } 32 | 33 | gentity_t *entity = &g_entities[id]; 34 | 35 | vec3_t mins = {-height, -width, -width}; 36 | vec3_t maxs = {width, width, height}; 37 | 38 | VectorCopy(mins, entity->r.mins); 39 | VectorCopy(maxs, entity->r.maxs); 40 | 41 | stackPushBool(qtrue); 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /gsc_entity.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_ENTITY_HPP_ 2 | #define _GSC_ENTITY_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_entity_setalive(scr_entref_t id); 8 | void gsc_entity_setbounds(scr_entref_t id); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /gsc_exec.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_exec.hpp" 2 | 3 | #if COMPILE_EXEC == 1 4 | 5 | #include 6 | 7 | enum 8 | { 9 | INT_VALUE, 10 | FLOAT_VALUE, 11 | STRING_VALUE, 12 | VECTOR_VALUE, 13 | OBJECT_VALUE 14 | }; 15 | 16 | struct exec_outputline 17 | { 18 | char content[COD2_MAX_STRINGLENGTH]; 19 | exec_outputline *next; 20 | }; 21 | 22 | struct exec_async_task 23 | { 24 | exec_async_task *prev; 25 | exec_async_task *next; 26 | char command[COD2_MAX_STRINGLENGTH]; 27 | int callback; 28 | bool done; 29 | bool save; 30 | bool error; 31 | exec_outputline *output; 32 | unsigned int levelId; 33 | bool hasargument; 34 | int valueType; 35 | int intValue; 36 | float floatValue; 37 | char stringValue[COD2_MAX_STRINGLENGTH]; 38 | vec3_t vectorValue; 39 | unsigned int objectValue; 40 | }; 41 | 42 | exec_async_task *first_exec_async_task = NULL; 43 | 44 | void gsc_exec() 45 | { 46 | char *command; 47 | 48 | if (!stackGetParamString(0, &command)) 49 | { 50 | stackError("gsc_exec() argument is undefined or has wrong type"); 51 | stackPushUndefined(); 52 | return; 53 | } 54 | 55 | Com_DPrintf("gsc_exec() executing: %s\n", command); 56 | 57 | FILE *fp; 58 | 59 | fp = popen(command, "r"); 60 | 61 | if (fp == NULL) 62 | { 63 | stackPushUndefined(); 64 | return; 65 | } 66 | 67 | char c; 68 | int curpos = 0; 69 | char content[COD2_MAX_STRINGLENGTH]; 70 | 71 | stackPushArray(); 72 | 73 | while ((c = getc(fp)) != EOF) 74 | { 75 | if (c == '\n' || curpos == COD2_MAX_STRINGLENGTH - 1) 76 | { 77 | content[curpos] = '\0'; 78 | stackPushString(content); 79 | stackPushArrayLast(); 80 | curpos = 0; 81 | } 82 | else 83 | { 84 | content[curpos] = c; 85 | curpos++; 86 | } 87 | } 88 | 89 | content[curpos] = '\0'; 90 | 91 | stackPushString(content); 92 | stackPushArrayLast(); 93 | 94 | pclose(fp); 95 | } 96 | 97 | void *exec_async(void *input_c) 98 | { 99 | exec_async_task *task = (exec_async_task*)input_c; 100 | FILE *fp; 101 | 102 | fp = popen(task->command, "r"); 103 | 104 | if (fp == NULL) 105 | { 106 | task->error = true; 107 | return NULL; 108 | } 109 | 110 | if (task->save) 111 | { 112 | exec_outputline *output = new exec_outputline; 113 | task->output = output; 114 | output->next = NULL; 115 | 116 | char c; 117 | int curpos = 0; 118 | 119 | while ((c = getc(fp)) != EOF) 120 | { 121 | if (c == '\n' || curpos == COD2_MAX_STRINGLENGTH - 1) 122 | { 123 | output->content[curpos] = '\0'; 124 | output->next = new exec_outputline; 125 | output = output->next; 126 | output->next = NULL; 127 | curpos = 0; 128 | } 129 | else 130 | { 131 | output->content[curpos] = c; 132 | curpos++; 133 | } 134 | } 135 | 136 | output->content[curpos] = '\0'; 137 | } 138 | else 139 | while(getc(fp) != EOF); //make thread wait for function to finish 140 | 141 | pclose(fp); 142 | task->done = true; 143 | return NULL; 144 | } 145 | 146 | void gsc_exec_async_create() 147 | { 148 | char *command; 149 | int callback; 150 | 151 | if (!stackGetParamString(0, &command)) 152 | { 153 | stackError("gsc_exec_async_create() argument is undefined or has wrong type"); 154 | stackPushUndefined(); 155 | return; 156 | } 157 | 158 | Com_DPrintf("gsc_exec_async_create() executing: %s\n", command); 159 | 160 | exec_async_task *current = first_exec_async_task; 161 | 162 | while (current != NULL && current->next != NULL) 163 | current = current->next; 164 | 165 | exec_async_task *newtask = new exec_async_task; 166 | 167 | strncpy(newtask->command, command, COD2_MAX_STRINGLENGTH - 1); 168 | newtask->command[COD2_MAX_STRINGLENGTH - 1] = '\0'; 169 | newtask->output = NULL; 170 | newtask->prev = current; 171 | newtask->next = NULL; 172 | 173 | if (!stackGetParamFunction(1, &callback)) 174 | newtask->callback = 0; 175 | else 176 | newtask->callback = callback; 177 | 178 | newtask->done = false; 179 | newtask->save = true; 180 | newtask->error = false; 181 | newtask->levelId = scrVarPub.levelId; 182 | newtask->hasargument = true; 183 | 184 | int valueInt; 185 | float valueFloat; 186 | char *valueString; 187 | vec3_t valueVector; 188 | unsigned int valueObject; 189 | 190 | if (stackGetParamInt(2, &valueInt)) 191 | { 192 | newtask->valueType = INT_VALUE; 193 | newtask->intValue = valueInt; 194 | } 195 | else if (stackGetParamFloat(2, &valueFloat)) 196 | { 197 | newtask->valueType = FLOAT_VALUE; 198 | newtask->floatValue = valueFloat; 199 | } 200 | else if (stackGetParamString(2, &valueString)) 201 | { 202 | newtask->valueType = STRING_VALUE; 203 | strcpy(newtask->stringValue, valueString); 204 | } 205 | else if (stackGetParamVector(2, valueVector)) 206 | { 207 | newtask->valueType = VECTOR_VALUE; 208 | newtask->vectorValue[0] = valueVector[0]; 209 | newtask->vectorValue[1] = valueVector[1]; 210 | newtask->vectorValue[2] = valueVector[2]; 211 | } 212 | else if (stackGetParamObject(2, &valueObject)) 213 | { 214 | newtask->valueType = OBJECT_VALUE; 215 | newtask->objectValue = valueObject; 216 | } 217 | else 218 | newtask->hasargument = false; 219 | 220 | if (current != NULL) 221 | current->next = newtask; 222 | else 223 | first_exec_async_task = newtask; 224 | 225 | pthread_t exec_doer; 226 | 227 | if (pthread_create(&exec_doer, NULL, exec_async, newtask) != 0) 228 | { 229 | stackError("gsc_exec_async_create() error creating exec async handler thread!"); 230 | stackPushUndefined(); 231 | return; 232 | } 233 | 234 | if (pthread_detach(exec_doer) != 0) 235 | { 236 | stackError("gsc_exec_async_create() error detaching exec async handler thread!"); 237 | stackPushUndefined(); 238 | return; 239 | } 240 | 241 | stackPushInt(1); 242 | } 243 | 244 | void gsc_exec_async_create_nosave() 245 | { 246 | char *command; 247 | int callback; 248 | 249 | if (!stackGetParamString(0, &command)) 250 | { 251 | stackError("gsc_exec_async_create_nosave() argument is undefined or has wrong type"); 252 | stackPushUndefined(); 253 | return; 254 | } 255 | 256 | Com_DPrintf("gsc_exec_async_create_nosave() executing: %s\n", command); 257 | 258 | exec_async_task *current = first_exec_async_task; 259 | 260 | while (current != NULL && current->next != NULL) 261 | current = current->next; 262 | 263 | exec_async_task *newtask = new exec_async_task; 264 | 265 | strncpy(newtask->command, command, COD2_MAX_STRINGLENGTH - 1); 266 | newtask->command[COD2_MAX_STRINGLENGTH - 1] = '\0'; 267 | newtask->output = NULL; 268 | newtask->prev = current; 269 | newtask->next = NULL; 270 | 271 | if (!stackGetParamFunction(1, &callback)) 272 | newtask->callback = 0; 273 | else 274 | newtask->callback = callback; 275 | 276 | newtask->done = false; 277 | newtask->save = false; 278 | newtask->error = false; 279 | newtask->levelId = scrVarPub.levelId; 280 | newtask->hasargument = true; 281 | 282 | int valueInt; 283 | float valueFloat; 284 | char *valueString; 285 | vec3_t valueVector; 286 | unsigned int valueObject; 287 | 288 | if (stackGetParamInt(2, &valueInt)) 289 | { 290 | newtask->valueType = INT_VALUE; 291 | newtask->intValue = valueInt; 292 | } 293 | else if (stackGetParamFloat(2, &valueFloat)) 294 | { 295 | newtask->valueType = FLOAT_VALUE; 296 | newtask->floatValue = valueFloat; 297 | } 298 | else if (stackGetParamString(2, &valueString)) 299 | { 300 | newtask->valueType = STRING_VALUE; 301 | strcpy(newtask->stringValue, valueString); 302 | } 303 | else if (stackGetParamVector(2, valueVector)) 304 | { 305 | newtask->valueType = VECTOR_VALUE; 306 | newtask->vectorValue[0] = valueVector[0]; 307 | newtask->vectorValue[1] = valueVector[1]; 308 | newtask->vectorValue[2] = valueVector[2]; 309 | } 310 | else if (stackGetParamObject(2, &valueObject)) 311 | { 312 | newtask->valueType = OBJECT_VALUE; 313 | newtask->objectValue = valueObject; 314 | } 315 | else 316 | newtask->hasargument = false; 317 | 318 | if (current != NULL) 319 | current->next = newtask; 320 | else 321 | first_exec_async_task = newtask; 322 | 323 | pthread_t exec_doer; 324 | 325 | if (pthread_create(&exec_doer, NULL, exec_async, newtask) != 0) 326 | { 327 | stackError("gsc_exec_async_create_nosave() error creating exec async handler thread!"); 328 | stackPushUndefined(); 329 | return; 330 | } 331 | 332 | if (pthread_detach(exec_doer) != 0) 333 | { 334 | stackError("gsc_exec_async_create_nosave() error detaching exec async handler thread!"); 335 | stackPushUndefined(); 336 | return; 337 | } 338 | 339 | stackPushInt(1); 340 | } 341 | 342 | void gsc_exec_async_checkdone() 343 | { 344 | exec_async_task *current = first_exec_async_task; 345 | 346 | while (current != NULL) 347 | { 348 | exec_async_task *task = current; 349 | current = current->next; 350 | 351 | if (task->done) 352 | { 353 | //push to cod 354 | if (Scr_IsSystemActive() && task->save && task->callback && !task->error && (scrVarPub.levelId == task->levelId)) 355 | { 356 | if (task->hasargument) 357 | { 358 | switch(task->valueType) 359 | { 360 | case INT_VALUE: 361 | stackPushInt(task->intValue); 362 | break; 363 | 364 | case FLOAT_VALUE: 365 | stackPushFloat(task->floatValue); 366 | break; 367 | 368 | case STRING_VALUE: 369 | stackPushString(task->stringValue); 370 | break; 371 | 372 | case VECTOR_VALUE: 373 | stackPushVector(task->vectorValue); 374 | break; 375 | 376 | case OBJECT_VALUE: 377 | stackPushObject(task->objectValue); 378 | break; 379 | 380 | default: 381 | stackPushUndefined(); 382 | break; 383 | } 384 | } 385 | 386 | stackPushArray(); 387 | exec_outputline *output = task->output; 388 | 389 | while (output != NULL) 390 | { 391 | exec_outputline *next = output->next; 392 | stackPushString(output->content); 393 | stackPushArrayLast(); 394 | delete output; 395 | output = next; 396 | } 397 | 398 | short ret = Scr_ExecThread(task->callback, task->save + task->hasargument); 399 | Scr_FreeThread(ret); 400 | } 401 | 402 | //free task 403 | if (task->next != NULL) 404 | task->next->prev = task->prev; 405 | 406 | if (task->prev != NULL) 407 | task->prev->next = task->next; 408 | else 409 | first_exec_async_task = task->next; 410 | 411 | delete task; 412 | } 413 | } 414 | } 415 | 416 | #endif 417 | -------------------------------------------------------------------------------- /gsc_exec.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_EXEC_HPP_ 2 | #define _GSC_EXEC_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_exec(); 8 | void gsc_exec_async_create(); 9 | void gsc_exec_async_create_nosave(); 10 | void gsc_exec_async_checkdone(); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /gsc_level.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_level.hpp" 2 | 3 | #if COMPILE_LEVEL == 1 4 | 5 | void gsc_level_getnumberofstaticmodels() 6 | { 7 | stackPushInt(cm.numStaticModels); 8 | } 9 | 10 | void gsc_level_getstaticmodelname() 11 | { 12 | int index; 13 | 14 | if ( ! stackGetParams("i", &index)) 15 | { 16 | stackError("gsc_level_getstaticmodelname() argument is undefined or has a wrong type"); 17 | stackPushUndefined(); 18 | return; 19 | } 20 | 21 | if (index < 0 || index >= (int)cm.numStaticModels) 22 | { 23 | stackError("gsc_level_getstaticmodelname() index is out of range"); 24 | stackPushUndefined(); 25 | return; 26 | } 27 | 28 | stackPushString(cm.staticModelList[index].xmodel->name); 29 | } 30 | 31 | void gsc_level_getstaticmodelorigin() 32 | { 33 | int index; 34 | 35 | if ( ! stackGetParams("i", &index)) 36 | { 37 | stackError("gsc_level_getstaticmodelorigin() argument is undefined or has a wrong type"); 38 | stackPushUndefined(); 39 | return; 40 | } 41 | 42 | if (index < 0 || index >= (int)cm.numStaticModels) 43 | { 44 | stackError("gsc_level_getstaticmodelorigin() index is out of range"); 45 | stackPushUndefined(); 46 | return; 47 | } 48 | 49 | stackPushVector(cm.staticModelList[index].origin); 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /gsc_level.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_LEVEL_HPP_ 2 | #define _GSC_LEVEL_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_level_getnumberofstaticmodels(); 8 | void gsc_level_getstaticmodelname(); 9 | void gsc_level_getstaticmodelorigin(); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /gsc_memory.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_memory.hpp" 2 | 3 | #if COMPILE_MEMORY == 1 4 | 5 | void gsc_memory_malloc() 6 | { 7 | int bytes; 8 | 9 | if ( ! stackGetParams("i", &bytes)) 10 | { 11 | stackError("gsc_memory_malloc() argument is undefined or has a wrong type"); 12 | stackPushUndefined(); 13 | return; 14 | } 15 | 16 | stackPushInt((int) malloc(bytes)); 17 | } 18 | 19 | void gsc_memory_free() 20 | { 21 | int memory; 22 | 23 | if ( ! stackGetParams("i", &memory)) 24 | { 25 | stackError("gsc_memory_free() argument is undefined or has a wrong type"); 26 | stackPushUndefined(); 27 | return; 28 | } 29 | 30 | free((void*)memory); 31 | stackPushInt(0); 32 | } 33 | 34 | void gsc_memory_int_get() 35 | { 36 | int memory; 37 | 38 | if ( ! stackGetParams("i", &memory)) 39 | { 40 | stackError("gsc_memory_int_get() argument is undefined or has a wrong type"); 41 | stackPushUndefined(); 42 | return; 43 | } 44 | 45 | stackPushInt(*(int*)memory); 46 | } 47 | 48 | void gsc_memory_int_set() 49 | { 50 | int memory, value; 51 | 52 | if ( ! stackGetParams("ii", &memory, &value)) 53 | { 54 | stackError("gsc_memory_int_set() one or more arguments is undefined or has a wrong type"); 55 | stackPushUndefined(); 56 | return; 57 | } 58 | 59 | *(int*)memory = value; 60 | stackPushInt(1); 61 | } 62 | 63 | void gsc_memory_memset() 64 | { 65 | int memory, value, bytes; 66 | 67 | if ( ! stackGetParams("iii", &memory, &value, &bytes)) 68 | { 69 | stackError("gsc_memory_memset() one or more arguments is undefined or has a wrong type"); 70 | stackPushUndefined(); 71 | return; 72 | } 73 | 74 | memset((void*)memory, value, bytes); 75 | stackPushInt(1); 76 | } 77 | 78 | #include 79 | struct binarybuffer 80 | { 81 | int address; 82 | int pos; 83 | std::vector *strings; 84 | }; 85 | 86 | void gsc_binarybuffer_new() 87 | { 88 | int address; 89 | if ( ! stackGetParams("i", &address)) 90 | { 91 | stackError("gsc_binarybuffer_new() argument is undefined or has a wrong type"); 92 | stackPushUndefined(); 93 | return; 94 | } 95 | struct binarybuffer *bb = (struct binarybuffer *)malloc(sizeof(struct binarybuffer)); 96 | bb->address = address; 97 | bb->pos = 0; 98 | bb->strings = new std::vector(); 99 | stackPushInt((int)bb); 100 | } 101 | 102 | void gsc_binarybuffer_free() 103 | { 104 | struct binarybuffer *bb; 105 | if ( ! stackGetParams("i", &bb)) 106 | { 107 | stackError("gsc_binarybuffer_free() argument is undefined or has a wrong type"); 108 | stackPushUndefined(); 109 | return; 110 | } 111 | for (std::vector::const_iterator i = bb->strings->begin(); i != bb->strings->end(); i++) 112 | free(*i); 113 | delete bb->strings; 114 | free(bb); 115 | stackPushInt(1); 116 | } 117 | 118 | void gsc_binarybuffer_seek() 119 | { 120 | struct binarybuffer *bb; 121 | int pos; 122 | if ( ! stackGetParams("ii", &bb, &pos)) 123 | { 124 | stackError("gsc_binarybuffer_seek() one or more arguments is undefined or has a wrong type"); 125 | stackPushUndefined(); 126 | return; 127 | } 128 | bb->pos = pos; 129 | stackPushInt(1); 130 | } 131 | 132 | void gsc_binarybuffer_write() 133 | { 134 | struct binarybuffer *bb; 135 | char *type; 136 | if ( ! stackGetParams("is", &bb, &type)) 137 | { 138 | stackError("gsc_binarybuffer_write() one or more arguments is undefined or has a wrong type"); 139 | stackPushUndefined(); 140 | return; 141 | } 142 | switch (type[0]) 143 | { 144 | case 'i': 145 | { 146 | int tmp_int; 147 | stackGetParamInt(2, &tmp_int); 148 | *(int *)(bb->address + bb->pos) = tmp_int; 149 | bb->pos += 4; 150 | break; 151 | } 152 | case 'f': 153 | { 154 | float tmp_float; 155 | stackGetParamFloat(2, &tmp_float); 156 | *(float *)(bb->address + bb->pos) = tmp_float; 157 | bb->pos += 4; 158 | break; 159 | } 160 | case 'd': 161 | { 162 | float tmp_float; 163 | stackGetParamFloat(2, &tmp_float); 164 | *(double *)(bb->address + bb->pos) = (double)tmp_float; 165 | bb->pos += 8; 166 | break; 167 | } 168 | case 's': 169 | { 170 | char *tmp_str; 171 | stackGetParamString(2, &tmp_str); 172 | char *copy = (char *)malloc(strlen(tmp_str) + 1); 173 | strcpy(copy, tmp_str); 174 | bb->strings->push_back(copy); 175 | *(char **)(bb->address + bb->pos) = copy; 176 | bb->pos += 4; 177 | break; 178 | } 179 | case 'c': 180 | { 181 | char *tmp_str; 182 | stackGetParamString(2, &tmp_str); 183 | *(char *)(bb->address + bb->pos) = tmp_str[0]; 184 | bb->pos += 1; 185 | break; 186 | } 187 | case 'v': 188 | { 189 | float tmp_vector[3]; 190 | stackGetParamVector(2, tmp_vector); 191 | *(float *)(bb->address + bb->pos + 0) = tmp_vector[0]; 192 | *(float *)(bb->address + bb->pos + 4) = tmp_vector[1]; 193 | *(float *)(bb->address + bb->pos + 8) = tmp_vector[2]; 194 | bb->pos += 12; 195 | break; 196 | } 197 | } 198 | stackPushInt(1); 199 | } 200 | 201 | void gsc_binarybuffer_read() 202 | { 203 | struct binarybuffer *bb; 204 | char *type; 205 | if ( ! stackGetParams("is", &bb, &type)) 206 | { 207 | stackError("gsc_binarybuffer_read() one or more arguments is undefined or has a wrong type"); 208 | stackPushUndefined(); 209 | return; 210 | } 211 | switch (type[0]) 212 | { 213 | case 'i': 214 | { 215 | int tmp_int; 216 | tmp_int = *(int *)(bb->address + bb->pos); 217 | bb->pos += 4; 218 | stackPushInt(tmp_int); 219 | return; 220 | } 221 | case 'f': 222 | { 223 | float tmp_float; 224 | tmp_float = *(float *)(bb->address + bb->pos); 225 | bb->pos += 4; 226 | stackPushFloat(tmp_float); 227 | return; 228 | } 229 | case 'd': 230 | { 231 | float tmp_float; 232 | tmp_float = (float)*(double *)(bb->address + bb->pos); 233 | bb->pos += 8; 234 | stackPushFloat(tmp_float); 235 | return; 236 | } 237 | case 's': 238 | { 239 | char *tmp_str; 240 | tmp_str = *(char **)(bb->address + bb->pos); 241 | bb->pos += 4; 242 | stackPushString(tmp_str); 243 | return; 244 | } 245 | case 'c': 246 | { 247 | char tmp_str[2]; 248 | tmp_str[0] = *(char *)(bb->address + bb->pos); 249 | tmp_str[1] = '\0'; 250 | bb->pos += 1; 251 | stackPushString(tmp_str); 252 | return; 253 | } 254 | case 'v': 255 | { 256 | float *tmp_vector; 257 | tmp_vector = (float *)(bb->address + bb->pos + 0); 258 | bb->pos += 12; 259 | stackPushVector(tmp_vector); 260 | return; 261 | } 262 | } 263 | stackPushUndefined(); 264 | } 265 | #endif 266 | -------------------------------------------------------------------------------- /gsc_memory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_MEMORY_HPP_ 2 | #define _GSC_MEMORY_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_memory_malloc(); 8 | void gsc_memory_free(); 9 | void gsc_memory_int_get(); 10 | void gsc_memory_int_set(); 11 | void gsc_memory_memset(); 12 | void gsc_binarybuffer_new(); 13 | void gsc_binarybuffer_free(); 14 | void gsc_binarybuffer_seek(); 15 | void gsc_binarybuffer_write(); 16 | void gsc_binarybuffer_read(); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /gsc_mysql.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_mysql.hpp" 2 | 3 | #if COMPILE_MYSQL == 1 4 | 5 | #include 6 | #include 7 | 8 | struct mysql_async_task 9 | { 10 | mysql_async_task *prev; 11 | mysql_async_task *next; 12 | int id; 13 | MYSQL_RES *result; 14 | bool done; 15 | bool started; 16 | bool save; 17 | char query[COD2_MAX_STRINGLENGTH + 1]; 18 | }; 19 | 20 | struct mysql_async_connection 21 | { 22 | mysql_async_connection *prev; 23 | mysql_async_connection *next; 24 | mysql_async_task* task; 25 | MYSQL *connection; 26 | }; 27 | 28 | mysql_async_connection *first_async_connection = NULL; 29 | mysql_async_task *first_async_task = NULL; 30 | MYSQL *cod_mysql_connection = NULL; 31 | pthread_mutex_t lock_async_mysql; 32 | 33 | void *mysql_async_execute_query(void *input_c) //cannot be called from gsc, is threaded. 34 | { 35 | mysql_async_connection *c = (mysql_async_connection *) input_c; 36 | int res = mysql_query(c->connection, c->task->query); 37 | if(!res && c->task->save) 38 | c->task->result = mysql_store_result(c->connection); 39 | else if(res) 40 | { 41 | //mysql show error here? 42 | } 43 | c->task->done = true; 44 | c->task = NULL; 45 | return NULL; 46 | } 47 | 48 | void *mysql_async_query_handler(void* input_nothing) //is threaded after initialize 49 | { 50 | static bool started = false; 51 | if(started) 52 | { 53 | Com_DPrintf("mysql_async_query_handler() async handler already started. Returning\n"); 54 | return NULL; 55 | } 56 | started = true; 57 | mysql_async_connection *c = first_async_connection; 58 | if(c == NULL) 59 | { 60 | Com_DPrintf("mysql_async_query_handler() async handler started before any connection was initialized\n"); //this should never happen 61 | started = false; 62 | return NULL; 63 | } 64 | mysql_async_task *q; 65 | while(true) 66 | { 67 | pthread_mutex_lock(&lock_async_mysql); 68 | q = first_async_task; 69 | c = first_async_connection; 70 | while(q != NULL) 71 | { 72 | if(!q->started) 73 | { 74 | while(c != NULL && c->task != NULL) 75 | c = c->next; 76 | if(c == NULL) 77 | { 78 | //out of free connections 79 | break; 80 | } 81 | q->started = true; 82 | c->task = q; 83 | pthread_t query_doer; 84 | int error = pthread_create(&query_doer, NULL, mysql_async_execute_query, c); 85 | if(error) 86 | { 87 | Com_DPrintf("error: %i\n", error); 88 | Com_DPrintf("Error detaching async handler thread\n"); 89 | return NULL; 90 | } 91 | pthread_detach(query_doer); 92 | c = c->next; 93 | } 94 | q = q->next; 95 | } 96 | pthread_mutex_unlock(&lock_async_mysql); 97 | usleep(10000); 98 | } 99 | return NULL; 100 | } 101 | 102 | int mysql_async_query_initializer(char *sql, bool save) //cannot be called from gsc, helper function 103 | { 104 | static int id = 0; 105 | id++; 106 | pthread_mutex_lock(&lock_async_mysql); 107 | mysql_async_task *current = first_async_task; 108 | while(current != NULL && current->next != NULL) 109 | current = current->next; 110 | mysql_async_task *newtask = new mysql_async_task; 111 | newtask->id = id; 112 | strncpy(newtask->query, sql, COD2_MAX_STRINGLENGTH); 113 | newtask->prev = current; 114 | newtask->result = NULL; 115 | newtask->save = save; 116 | newtask->done = false; 117 | newtask->next = NULL; 118 | newtask->started = false; 119 | if(current != NULL) 120 | current->next = newtask; 121 | else 122 | first_async_task = newtask; 123 | pthread_mutex_unlock(&lock_async_mysql); 124 | return id; 125 | } 126 | 127 | void gsc_mysql_async_create_query_nosave() 128 | { 129 | char *query; 130 | if ( ! stackGetParams("s", &query)) 131 | { 132 | stackError("gsc_mysql_async_create_query_nosave() argument is undefined or has a wrong type"); 133 | stackPushUndefined(); 134 | return; 135 | } 136 | int id = mysql_async_query_initializer(query, false); 137 | stackPushInt(id); 138 | return; 139 | } 140 | 141 | void gsc_mysql_async_create_query() 142 | { 143 | char *query; 144 | if ( ! stackGetParams("s", &query)) 145 | { 146 | stackError("gsc_mysql_async_create_query() argument is undefined or has a wrong type"); 147 | stackPushUndefined(); 148 | return; 149 | } 150 | int id = mysql_async_query_initializer(query, true); 151 | stackPushInt(id); 152 | return; 153 | } 154 | 155 | void gsc_mysql_async_getdone_list() 156 | { 157 | pthread_mutex_lock(&lock_async_mysql); 158 | mysql_async_task *current = first_async_task; 159 | stackPushArray(); 160 | while(current != NULL) 161 | { 162 | if(current->done) 163 | { 164 | stackPushInt((int)current->id); 165 | stackPushArrayLast(); 166 | } 167 | current = current->next; 168 | } 169 | pthread_mutex_unlock(&lock_async_mysql); 170 | } 171 | 172 | void gsc_mysql_async_getresult_and_free() //same as above, but takes the id of a function instead and returns 0 (not done), undefined (not found) or the mem address of result 173 | { 174 | int id; 175 | if(!stackGetParams("i", &id)) 176 | { 177 | stackError("gsc_mysql_async_getresult_and_free() argument is undefined or has a wrong type"); 178 | stackPushUndefined(); 179 | return; 180 | } 181 | pthread_mutex_lock(&lock_async_mysql); 182 | mysql_async_task *c = first_async_task; 183 | if(c != NULL) 184 | { 185 | while(c != NULL && c->id != id) 186 | c = c->next; 187 | } 188 | if(c != NULL) 189 | { 190 | if(!c->done) 191 | { 192 | stackPushUndefined(); //should never happend, query not done yet 193 | pthread_mutex_unlock(&lock_async_mysql); 194 | return; 195 | } 196 | if(c->next != NULL) 197 | c->next->prev = c->prev; 198 | if(c->prev != NULL) 199 | c->prev->next = c->next; 200 | else 201 | first_async_task = c->next; 202 | if(c->save) 203 | { 204 | int ret = (int)c->result; 205 | stackPushInt(ret); 206 | } 207 | else 208 | stackPushInt(0); 209 | delete c; 210 | pthread_mutex_unlock(&lock_async_mysql); 211 | return; 212 | } 213 | else 214 | { 215 | stackError("gsc_mysql_async_getresult_and_free() mysql async query id not found"); 216 | stackPushUndefined(); 217 | pthread_mutex_unlock(&lock_async_mysql); 218 | return; 219 | } 220 | } 221 | 222 | void gsc_mysql_async_initializer()//returns array with mysql connection handlers 223 | { 224 | if(first_async_connection != NULL) 225 | { 226 | Com_DPrintf("gsc_mysql_async_initializer() async mysql already initialized. Returning before adding additional connections\n"); 227 | stackPushUndefined(); 228 | return; 229 | } 230 | if(pthread_mutex_init(&lock_async_mysql, NULL) != 0) 231 | { 232 | Com_DPrintf("Async mutex initialization failed\n"); 233 | stackPushUndefined(); 234 | return; 235 | } 236 | int port, connection_count; 237 | char *host, *user, *pass, *db; 238 | 239 | if ( ! stackGetParams("ssssii", &host, &user, &pass, &db, &port, &connection_count)) 240 | { 241 | stackError("gsc_mysql_async_initializer() one or more arguments is undefined or has a wrong type"); 242 | stackPushUndefined(); 243 | return; 244 | } 245 | if(connection_count <= 0) 246 | { 247 | stackError("gsc_mysql_async_initializer() need a positive connection_count in mysql_async_initializer"); 248 | stackPushUndefined(); 249 | return; 250 | } 251 | int i; 252 | stackPushArray(); 253 | mysql_async_connection *current = first_async_connection; 254 | for(i = 0; i < connection_count; i++) 255 | { 256 | mysql_async_connection *newconnection = new mysql_async_connection; 257 | newconnection->next = NULL; 258 | newconnection->connection = mysql_init(NULL); 259 | newconnection->connection = mysql_real_connect((MYSQL*)newconnection->connection, host, user, pass, db, port, NULL, 0); 260 | bool reconnect = true; 261 | mysql_options(newconnection->connection, MYSQL_OPT_RECONNECT, &reconnect); 262 | newconnection->task = NULL; 263 | if(current == NULL) 264 | { 265 | newconnection->prev = NULL; 266 | first_async_connection = newconnection; 267 | } 268 | else 269 | { 270 | while(current->next != NULL) 271 | current = current->next; 272 | current->next = newconnection; 273 | newconnection->prev = current; 274 | } 275 | current = newconnection; 276 | stackPushInt((int)newconnection->connection); 277 | stackPushArrayLast(); 278 | } 279 | pthread_t async_handler; 280 | if(pthread_create(&async_handler, NULL, mysql_async_query_handler, NULL)) 281 | { 282 | stackError("gsc_mysql_async_initializer() error detaching async handler thread"); 283 | return; 284 | } 285 | pthread_detach(async_handler); 286 | } 287 | 288 | void gsc_mysql_init() 289 | { 290 | MYSQL *my = mysql_init(NULL); 291 | stackPushInt((int) my); 292 | } 293 | 294 | void gsc_mysql_reuse_connection() 295 | { 296 | if(cod_mysql_connection == NULL) 297 | { 298 | stackPushUndefined(); 299 | return; 300 | } 301 | else 302 | { 303 | stackPushInt((int) cod_mysql_connection); 304 | return; 305 | } 306 | } 307 | 308 | void gsc_mysql_real_connect() 309 | { 310 | int mysql, port; 311 | char *host, *user, *pass, *db; 312 | 313 | if ( ! stackGetParams("issssi", &mysql, &host, &user, &pass, &db, &port)) 314 | { 315 | stackError("gsc_mysql_real_connect() one or more arguments is undefined or has a wrong type"); 316 | stackPushUndefined(); 317 | return; 318 | } 319 | 320 | mysql = (int) mysql_real_connect((MYSQL *)mysql, host, user, pass, db, port, NULL, 0); 321 | bool reconnect = true; 322 | mysql_options((MYSQL*)mysql, MYSQL_OPT_RECONNECT, &reconnect); 323 | if(cod_mysql_connection == NULL) 324 | cod_mysql_connection = (MYSQL*) mysql; 325 | stackPushInt(mysql); 326 | } 327 | 328 | void gsc_mysql_close() 329 | { 330 | int mysql; 331 | 332 | if ( ! stackGetParams("i", &mysql)) 333 | { 334 | stackError("gsc_mysql_close() argument is undefined or has a wrong type"); 335 | stackPushUndefined(); 336 | return; 337 | } 338 | 339 | mysql_close((MYSQL *)mysql); 340 | stackPushInt(0); 341 | } 342 | 343 | void gsc_mysql_query() 344 | { 345 | int mysql; 346 | char *query; 347 | 348 | if ( ! stackGetParams("is", &mysql, &query)) 349 | { 350 | stackError("gsc_mysql_query() one or more arguments is undefined or has a wrong type"); 351 | stackPushUndefined(); 352 | return; 353 | } 354 | 355 | int ret = mysql_query((MYSQL *)mysql, query); 356 | stackPushInt(ret); 357 | } 358 | 359 | void gsc_mysql_errno() 360 | { 361 | int mysql; 362 | 363 | if ( ! stackGetParams("i", &mysql)) 364 | { 365 | stackError("gsc_mysql_errno() argument is undefined or has a wrong type"); 366 | stackPushUndefined(); 367 | return; 368 | } 369 | 370 | int ret = mysql_errno((MYSQL *)mysql); 371 | stackPushInt(ret); 372 | } 373 | 374 | void gsc_mysql_error() 375 | { 376 | int mysql; 377 | 378 | if ( ! stackGetParams("i", &mysql)) 379 | { 380 | stackError("gsc_mysql_error() argument is undefined or has a wrong type"); 381 | stackPushUndefined(); 382 | return; 383 | } 384 | 385 | char *ret = (char *)mysql_error((MYSQL *)mysql); 386 | stackPushString(ret); 387 | } 388 | 389 | void gsc_mysql_affected_rows() 390 | { 391 | int mysql; 392 | 393 | if ( ! stackGetParams("i", &mysql)) 394 | { 395 | stackError("gsc_mysql_affected_rows() argument is undefined or has a wrong type"); 396 | stackPushUndefined(); 397 | return; 398 | } 399 | 400 | int ret = mysql_affected_rows((MYSQL *)mysql); 401 | stackPushInt(ret); 402 | } 403 | 404 | void gsc_mysql_store_result() 405 | { 406 | int mysql; 407 | 408 | if ( ! stackGetParams("i", &mysql)) 409 | { 410 | stackError("gsc_mysql_store_result() argument is undefined or has a wrong type"); 411 | stackPushUndefined(); 412 | return; 413 | } 414 | 415 | MYSQL_RES *result = mysql_store_result((MYSQL *)mysql); 416 | stackPushInt((int) result); 417 | } 418 | 419 | void gsc_mysql_num_rows() 420 | { 421 | int result; 422 | 423 | if ( ! stackGetParams("i", &result)) 424 | { 425 | stackError("gsc_mysql_num_rows() argument is undefined or has a wrong type"); 426 | stackPushUndefined(); 427 | return; 428 | } 429 | 430 | int ret = mysql_num_rows((MYSQL_RES *)result); 431 | stackPushInt(ret); 432 | } 433 | 434 | void gsc_mysql_num_fields() 435 | { 436 | int result; 437 | 438 | if ( ! stackGetParams("i", &result)) 439 | { 440 | stackError("gsc_mysql_num_fields() argument is undefined or has a wrong type"); 441 | stackPushUndefined(); 442 | return; 443 | } 444 | 445 | int ret = mysql_num_fields((MYSQL_RES *)result); 446 | stackPushInt(ret); 447 | } 448 | 449 | void gsc_mysql_field_seek() 450 | { 451 | int result; 452 | int offset; 453 | 454 | if ( ! stackGetParams("ii", &result, &offset)) 455 | { 456 | stackError("gsc_mysql_field_seek() one or more arguments is undefined or has a wrong type"); 457 | stackPushUndefined(); 458 | return; 459 | } 460 | 461 | int ret = mysql_field_seek((MYSQL_RES *)result, offset); 462 | stackPushInt(ret); 463 | } 464 | 465 | void gsc_mysql_fetch_field() 466 | { 467 | int result; 468 | 469 | if ( ! stackGetParams("i", &result)) 470 | { 471 | stackError("gsc_mysql_fetch_field() argument is undefined or has a wrong type"); 472 | stackPushUndefined(); 473 | return; 474 | } 475 | 476 | MYSQL_FIELD *field = mysql_fetch_field((MYSQL_RES *)result); 477 | if (field == NULL) 478 | { 479 | stackPushUndefined(); 480 | return; 481 | } 482 | char *ret = field->name; 483 | stackPushString(ret); 484 | } 485 | 486 | void gsc_mysql_fetch_row() 487 | { 488 | int result; 489 | 490 | if ( ! stackGetParams("i", &result)) 491 | { 492 | stackError("gsc_mysql_fetch_row() argument is undefined or has a wrong type"); 493 | stackPushUndefined(); 494 | return; 495 | } 496 | 497 | MYSQL_ROW row = mysql_fetch_row((MYSQL_RES *)result); 498 | if (!row) 499 | { 500 | stackPushUndefined(); 501 | return; 502 | } 503 | 504 | stackPushArray(); 505 | 506 | int numfields = mysql_num_fields((MYSQL_RES *)result); 507 | for (int i=0; i= MAX_CLIENTS) 17 | { 18 | stackError("gsc_player_velocity_set() entity %i is not a player", id); 19 | stackPushUndefined(); 20 | return; 21 | } 22 | 23 | playerState_t *ps = SV_GameClientNum(id); 24 | VectorCopy(velocity, ps->velocity); 25 | stackPushBool(qtrue); 26 | } 27 | 28 | void gsc_player_velocity_add(scr_entref_t id) 29 | { 30 | vec3_t velocity; 31 | 32 | if ( ! stackGetParams("v", &velocity)) 33 | { 34 | stackError("gsc_player_velocity_add() argument is undefined or has a wrong type"); 35 | stackPushUndefined(); 36 | return; 37 | } 38 | 39 | if (id >= MAX_CLIENTS) 40 | { 41 | stackError("gsc_player_velocity_add() entity %i is not a player", id); 42 | stackPushUndefined(); 43 | return; 44 | } 45 | 46 | playerState_t *ps = SV_GameClientNum(id); 47 | VectorAdd(ps->velocity, velocity, ps->velocity); 48 | stackPushBool(qtrue); 49 | } 50 | 51 | void gsc_player_velocity_get(scr_entref_t id) 52 | { 53 | if (id >= MAX_CLIENTS) 54 | { 55 | stackError("gsc_player_velocity_get() entity %i is not a player", id); 56 | stackPushUndefined(); 57 | return; 58 | } 59 | 60 | playerState_t *ps = SV_GameClientNum(id); 61 | stackPushVector(ps->velocity); 62 | } 63 | 64 | void gsc_player_clientuserinfochanged(scr_entref_t id) 65 | { 66 | if (id >= MAX_CLIENTS) 67 | { 68 | stackError("gsc_player_clientuserinfochanged() entity %i is not a player", id); 69 | stackPushUndefined(); 70 | return; 71 | } 72 | 73 | ClientUserinfoChanged(id); 74 | stackPushBool(qtrue); 75 | } 76 | 77 | void gsc_player_get_userinfo(scr_entref_t id) 78 | { 79 | char *key; 80 | 81 | if ( ! stackGetParams("s", &key)) 82 | { 83 | stackError("gsc_player_get_userinfo() argument is undefined or has a wrong type"); 84 | stackPushUndefined(); 85 | return; 86 | } 87 | 88 | if (id >= MAX_CLIENTS) 89 | { 90 | stackError("gsc_player_get_userinfo() entity %i is not a player", id); 91 | stackPushUndefined(); 92 | return; 93 | } 94 | 95 | client_t *client = &svs.clients[id]; 96 | char *val = Info_ValueForKey(client->userinfo, key); 97 | 98 | if (strlen(val)) 99 | stackPushString(val); 100 | else 101 | stackPushUndefined(); 102 | } 103 | 104 | void gsc_player_set_userinfo(scr_entref_t id) 105 | { 106 | char *key, *value; 107 | 108 | if ( ! stackGetParams("ss", &key, &value)) 109 | { 110 | stackError("gsc_player_set_userinfo() one or more arguments is undefined or has a wrong type"); 111 | stackPushUndefined(); 112 | return; 113 | } 114 | 115 | if (id >= MAX_CLIENTS) 116 | { 117 | stackError("gsc_player_set_userinfo() entity %i is not a player", id); 118 | stackPushUndefined(); 119 | return; 120 | } 121 | 122 | client_t *client = &svs.clients[id]; 123 | Info_SetValueForKey(client->userinfo, key, value); 124 | stackPushBool(qtrue); 125 | } 126 | 127 | void gsc_player_button_ads(scr_entref_t id) 128 | { 129 | if (id >= MAX_CLIENTS) 130 | { 131 | stackError("gsc_player_button_ads() entity %i is not a player", id); 132 | stackPushUndefined(); 133 | return; 134 | } 135 | 136 | client_t *client = &svs.clients[id]; 137 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_ADS_MODE ? qtrue : qfalse); 138 | } 139 | 140 | void gsc_player_button_left(scr_entref_t id) 141 | { 142 | if (id >= MAX_CLIENTS) 143 | { 144 | stackError("gsc_player_button_left() entity %i is not a player", id); 145 | stackPushUndefined(); 146 | return; 147 | } 148 | 149 | client_t *client = &svs.clients[id]; 150 | stackPushBool(client->lastUsercmd.rightmove == KEY_MASK_MOVELEFT ? qtrue : qfalse); 151 | } 152 | 153 | void gsc_player_button_right(scr_entref_t id) 154 | { 155 | if (id >= MAX_CLIENTS) 156 | { 157 | stackError("gsc_player_button_right() entity %i is not a player", id); 158 | stackPushUndefined(); 159 | return; 160 | } 161 | 162 | client_t *client = &svs.clients[id]; 163 | stackPushBool(client->lastUsercmd.rightmove == KEY_MASK_MOVERIGHT ? qtrue : qfalse); 164 | } 165 | 166 | void gsc_player_button_forward(scr_entref_t id) 167 | { 168 | if (id >= MAX_CLIENTS) 169 | { 170 | stackError("gsc_player_button_forward() entity %i is not a player", id); 171 | stackPushUndefined(); 172 | return; 173 | } 174 | 175 | client_t *client = &svs.clients[id]; 176 | stackPushBool(client->lastUsercmd.forwardmove == KEY_MASK_FORWARD ? qtrue : qfalse); 177 | } 178 | 179 | void gsc_player_button_back(scr_entref_t id) 180 | { 181 | if (id >= MAX_CLIENTS) 182 | { 183 | stackError("gsc_player_button_back() entity %i is not a player", id); 184 | stackPushUndefined(); 185 | return; 186 | } 187 | 188 | client_t *client = &svs.clients[id]; 189 | stackPushBool(client->lastUsercmd.forwardmove == KEY_MASK_BACK ? qtrue : qfalse); 190 | } 191 | 192 | void gsc_player_button_leanleft(scr_entref_t id) 193 | { 194 | if (id >= MAX_CLIENTS) 195 | { 196 | stackError("gsc_player_button_leanleft() entity %i is not a player", id); 197 | stackPushUndefined(); 198 | return; 199 | } 200 | 201 | client_t *client = &svs.clients[id]; 202 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_LEANLEFT ? qtrue : qfalse); 203 | } 204 | 205 | void gsc_player_button_leanright(scr_entref_t id) 206 | { 207 | if (id >= MAX_CLIENTS) 208 | { 209 | stackError("gsc_player_button_leanright() entity %i is not a player", id); 210 | stackPushUndefined(); 211 | return; 212 | } 213 | 214 | client_t *client = &svs.clients[id]; 215 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_LEANRIGHT ? qtrue : qfalse); 216 | } 217 | 218 | void gsc_player_button_reload(scr_entref_t id) 219 | { 220 | if (id >= MAX_CLIENTS) 221 | { 222 | stackError("gsc_player_button_reload() entity %i is not a player", id); 223 | stackPushUndefined(); 224 | return; 225 | } 226 | 227 | client_t *client = &svs.clients[id]; 228 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_RELOAD ? qtrue : qfalse); 229 | } 230 | 231 | void gsc_player_button_jump(scr_entref_t id) 232 | { 233 | if (id >= MAX_CLIENTS) 234 | { 235 | stackError("gsc_player_button_jump() entity %i is not a player", id); 236 | stackPushUndefined(); 237 | return; 238 | } 239 | 240 | client_t *client = &svs.clients[id]; 241 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_JUMP ? qtrue : qfalse); 242 | } 243 | 244 | void gsc_player_button_frag(scr_entref_t id) 245 | { 246 | if (id >= MAX_CLIENTS) 247 | { 248 | stackError("gsc_player_button_frag() entity %i is not a player", id); 249 | stackPushUndefined(); 250 | return; 251 | } 252 | 253 | client_t *client = &svs.clients[id]; 254 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_FRAG ? qtrue : qfalse); 255 | } 256 | 257 | void gsc_player_button_smoke(scr_entref_t id) 258 | { 259 | if (id >= MAX_CLIENTS) 260 | { 261 | stackError("gsc_player_button_smoke() entity %i is not a player", id); 262 | stackPushUndefined(); 263 | return; 264 | } 265 | 266 | client_t *client = &svs.clients[id]; 267 | stackPushBool(client->lastUsercmd.buttons & KEY_MASK_SMOKE ? qtrue : qfalse); 268 | } 269 | 270 | void gsc_player_stance_get(scr_entref_t id) 271 | { 272 | if (id >= MAX_CLIENTS) 273 | { 274 | stackError("gsc_player_stance_get() entity %i is not a player", id); 275 | stackPushUndefined(); 276 | return; 277 | } 278 | 279 | playerState_t *ps = SV_GameClientNum(id); 280 | 281 | if (ps->pm_flags & PMF_CROUCH) 282 | stackPushString("duck"); 283 | else if (ps->pm_flags & PMF_PRONE) 284 | stackPushString("lie"); 285 | else 286 | stackPushString("stand"); 287 | } 288 | 289 | void gsc_player_stance_set(scr_entref_t id) 290 | { 291 | char *stance; 292 | 293 | if ( ! stackGetParams("s", &stance)) 294 | { 295 | stackError("gsc_player_stance_set() argument is undefined or has a wrong type"); 296 | stackPushUndefined(); 297 | return; 298 | } 299 | 300 | gentity_t *entity = &g_entities[id]; 301 | 302 | if (entity->client == NULL) 303 | { 304 | stackError("gsc_player_stance_set() entity %i is not a player", id); 305 | stackPushUndefined(); 306 | return; 307 | } 308 | 309 | int event; 310 | 311 | if (strcmp(stance, "stand") == 0) 312 | event = EV_STANCE_FORCE_STAND; 313 | else if (strcmp(stance, "crouch") == 0) 314 | event = EV_STANCE_FORCE_CROUCH; 315 | else if (strcmp(stance, "prone") == 0) 316 | event = EV_STANCE_FORCE_PRONE; 317 | else 318 | { 319 | stackError("gsc_player_stance_set() invalid argument '%s'. Valid arguments are: 'stand' 'crouch' 'prone'", stance); 320 | stackPushUndefined(); 321 | return; 322 | } 323 | 324 | G_AddPredictableEvent(entity, event, 0); 325 | stackPushBool(qtrue); 326 | } 327 | 328 | void gsc_player_spectatorclient_get(scr_entref_t id) 329 | { 330 | gentity_t *entity = &g_entities[id]; 331 | 332 | if (entity->client == NULL) 333 | { 334 | stackError("gsc_player_spectatorclient_get() entity %i is not a player", id); 335 | stackPushUndefined(); 336 | return; 337 | } 338 | 339 | if (entity->client->spectatorClient == -1) 340 | stackPushUndefined(); 341 | else 342 | stackPushEntity(&g_entities[entity->client->spectatorClient]); 343 | } 344 | 345 | void gsc_player_getip(scr_entref_t id) 346 | { 347 | if (id >= MAX_CLIENTS) 348 | { 349 | stackError("gsc_player_getip() entity %i is not a player", id); 350 | stackPushUndefined(); 351 | return; 352 | } 353 | 354 | client_t *client = &svs.clients[id]; 355 | 356 | char tmp[16]; 357 | snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", client->netchan.remoteAddress.ip[0], client->netchan.remoteAddress.ip[1], client->netchan.remoteAddress.ip[2], client->netchan.remoteAddress.ip[3]); 358 | 359 | stackPushString(tmp); 360 | } 361 | 362 | void gsc_player_getping(scr_entref_t id) 363 | { 364 | if (id >= MAX_CLIENTS) 365 | { 366 | stackError("gsc_player_getping() entity %i is not a player", id); 367 | stackPushUndefined(); 368 | return; 369 | } 370 | 371 | client_t *client = &svs.clients[id]; 372 | stackPushInt(client->ping); 373 | } 374 | 375 | void gsc_player_clientcommand(scr_entref_t id) 376 | { 377 | if (id >= MAX_CLIENTS) 378 | { 379 | stackError("gsc_player_clientcommand() entity %i is not a player", id); 380 | stackPushUndefined(); 381 | return; 382 | } 383 | 384 | ClientCommand(id); 385 | stackPushBool(qtrue); 386 | } 387 | 388 | void gsc_player_getlastconnecttime(scr_entref_t id) 389 | { 390 | if (id >= MAX_CLIENTS) 391 | { 392 | stackError("gsc_player_getlastconnecttime() entity %i is not a player", id); 393 | stackPushUndefined(); 394 | return; 395 | } 396 | 397 | client_t *client = &svs.clients[id]; 398 | stackPushInt(client->lastConnectTime); 399 | } 400 | 401 | void gsc_player_getlastmsg(scr_entref_t id) 402 | { 403 | if (id >= MAX_CLIENTS) 404 | { 405 | stackError("gsc_player_getlastmsg() entity %i is not a player", id); 406 | stackPushUndefined(); 407 | return; 408 | } 409 | 410 | client_t *client = &svs.clients[id]; 411 | stackPushInt(svs.time - client->lastPacketTime); 412 | } 413 | 414 | void gsc_player_getclientstate(scr_entref_t id) 415 | { 416 | if (id >= MAX_CLIENTS) 417 | { 418 | stackError("gsc_player_getclientstate() entity %i is not a player", id); 419 | stackPushUndefined(); 420 | return; 421 | } 422 | 423 | client_t *client = &svs.clients[id]; 424 | stackPushInt(client->state); 425 | } 426 | 427 | void gsc_player_addresstype(scr_entref_t id) 428 | { 429 | if (id >= MAX_CLIENTS) 430 | { 431 | stackError("gsc_player_addresstype() entity %i is not a player", id); 432 | stackPushUndefined(); 433 | return; 434 | } 435 | 436 | client_t *client = &svs.clients[id]; 437 | stackPushInt(client->netchan.remoteAddress.type); 438 | } 439 | 440 | void gsc_player_renameclient(scr_entref_t id) 441 | { 442 | char *name; 443 | 444 | if ( ! stackGetParams("s", &name)) 445 | { 446 | stackError("gsc_player_renameclient() argument is undefined or has a wrong type"); 447 | stackPushUndefined(); 448 | return; 449 | } 450 | 451 | if (strlen(name) > 32) 452 | { 453 | stackError("gsc_player_renameclient() player name is longer than 32 characters"); 454 | stackPushUndefined(); 455 | return; 456 | } 457 | 458 | if (id >= MAX_CLIENTS) 459 | { 460 | stackError("gsc_player_renameclient() entity %i is not a player", id); 461 | stackPushUndefined(); 462 | return; 463 | } 464 | 465 | client_t *client = &svs.clients[id]; 466 | 467 | Info_SetValueForKey(client->userinfo, "name", name); 468 | strcpy(client->name, name); 469 | 470 | stackPushBool(qtrue); 471 | } 472 | 473 | void gsc_player_outofbandprint(scr_entref_t id) 474 | { 475 | char *cmd; 476 | 477 | if ( ! stackGetParams("s", &cmd)) 478 | { 479 | stackError("gsc_player_outofbandprint() argument is undefined or has a wrong type"); 480 | stackPushUndefined(); 481 | return; 482 | } 483 | 484 | if (id >= MAX_CLIENTS) 485 | { 486 | stackError("gsc_player_outofbandprint() entity %i is not a player", id); 487 | stackPushUndefined(); 488 | return; 489 | } 490 | 491 | client_t *client = &svs.clients[id]; 492 | NET_OutOfBandPrint(NS_SERVER, client->netchan.remoteAddress, cmd); 493 | stackPushBool(qtrue); 494 | } 495 | 496 | void gsc_player_connectionlesspacket(scr_entref_t id) 497 | { 498 | char *cmd; 499 | 500 | if ( ! stackGetParams("s", &cmd)) 501 | { 502 | stackError("gsc_player_connectionlesspacket() argument is undefined or has a wrong type"); 503 | stackPushUndefined(); 504 | return; 505 | } 506 | 507 | if (id >= MAX_CLIENTS) 508 | { 509 | stackError("gsc_player_connectionlesspacket() entity %i is not a player", id); 510 | stackPushUndefined(); 511 | return; 512 | } 513 | 514 | client_t *client = &svs.clients[id]; 515 | 516 | byte bufData[131072]; 517 | msg_t msg; 518 | 519 | MSG_Init(&msg, bufData, sizeof(bufData)); 520 | 521 | MSG_WriteByte(&msg, svc_nop); 522 | MSG_WriteShort(&msg, 0); 523 | MSG_WriteLong(&msg, -1); 524 | MSG_WriteString(&msg, cmd); 525 | 526 | SV_ConnectionlessPacket(client->netchan.remoteAddress, &msg); 527 | stackPushBool(qtrue); 528 | } 529 | 530 | void gsc_player_resetnextreliabletime(scr_entref_t id) 531 | { 532 | if (id >= MAX_CLIENTS) 533 | { 534 | stackError("gsc_player_resetnextreliabletime() entity %i is not a player", id); 535 | stackPushUndefined(); 536 | return; 537 | } 538 | 539 | client_t *client = &svs.clients[id]; 540 | client->floodprotect = 0; 541 | stackPushBool(qtrue); 542 | } 543 | 544 | void gsc_player_ismantling(scr_entref_t id) 545 | { 546 | if (id >= MAX_CLIENTS) 547 | { 548 | stackError("gsc_player_ismantling() entity %i is not a player", id); 549 | stackPushUndefined(); 550 | return; 551 | } 552 | 553 | playerState_t *ps = SV_GameClientNum(id); 554 | stackPushBool(ps->pm_flags & PMF_MANTLE ? qtrue : qfalse); 555 | } 556 | 557 | void gsc_player_isonladder(scr_entref_t id) 558 | { 559 | if (id >= MAX_CLIENTS) 560 | { 561 | stackError("gsc_player_isonladder() entity %i is not a player", id); 562 | stackPushUndefined(); 563 | return; 564 | } 565 | 566 | playerState_t *ps = SV_GameClientNum(id); 567 | stackPushBool(ps->pm_flags & PMF_LADDER ? qtrue : qfalse); 568 | } 569 | 570 | void gsc_player_isusingturret(scr_entref_t id) 571 | { 572 | gentity_t *entity = &g_entities[id]; 573 | 574 | if (entity->client == NULL) 575 | { 576 | stackError("gsc_player_isusingturret() entity %i is not a player", id); 577 | stackPushUndefined(); 578 | return; 579 | } 580 | 581 | stackPushBool(entity->s.eFlags & EF_USETURRET ? qtrue : qfalse); 582 | } 583 | 584 | void gsc_player_getjumpslowdowntimer(scr_entref_t id) 585 | { 586 | if (id >= MAX_CLIENTS) 587 | { 588 | stackError("gsc_player_getjumpslowdowntimer() entity %i is not a player", id); 589 | stackPushUndefined(); 590 | return; 591 | } 592 | 593 | playerState_t *ps = SV_GameClientNum(id); 594 | stackPushInt(ps->pm_time); 595 | } 596 | 597 | void gsc_player_clearjumpstate(scr_entref_t id) 598 | { 599 | if (id >= MAX_CLIENTS) 600 | { 601 | stackError("gsc_player_clearjumpstate() entity %i is not a player", id); 602 | stackPushUndefined(); 603 | return; 604 | } 605 | 606 | playerState_t *ps = SV_GameClientNum(id); 607 | 608 | ps->pm_flags &= ~(PMF_JUMPING|PMF_SLIDING); 609 | ps->pm_time = 0; 610 | ps->jumpTime = 0; 611 | ps->jumpOriginZ = 0; 612 | } 613 | 614 | void gsc_player_setg_speed(scr_entref_t id) 615 | { 616 | int speed; 617 | 618 | if ( ! stackGetParams("i", &speed)) 619 | { 620 | stackError("gsc_player_setg_speed() argument is undefined or has a wrong type"); 621 | stackPushUndefined(); 622 | return; 623 | } 624 | 625 | if (id >= MAX_CLIENTS) 626 | { 627 | stackError("gsc_player_setg_speed() entity %i is not a player", id); 628 | stackPushUndefined(); 629 | return; 630 | } 631 | 632 | extern int player_g_speed[MAX_CLIENTS]; 633 | 634 | if (speed < 0) 635 | { 636 | stackError("gsc_player_setg_speed() param must be equal or above zero"); 637 | stackPushUndefined(); 638 | return; 639 | } 640 | 641 | player_g_speed[id] = speed; 642 | stackPushBool(qtrue); 643 | } 644 | 645 | void gsc_player_setg_gravity(scr_entref_t id) 646 | { 647 | int gravity; 648 | 649 | if ( ! stackGetParams("i", &gravity)) 650 | { 651 | stackError("gsc_player_setg_gravity() argument is undefined or has a wrong type"); 652 | stackPushUndefined(); 653 | return; 654 | } 655 | 656 | if (id >= MAX_CLIENTS) 657 | { 658 | stackError("gsc_player_setg_gravity() entity %i is not a player", id); 659 | stackPushUndefined(); 660 | return; 661 | } 662 | 663 | extern int player_g_gravity[MAX_CLIENTS]; 664 | 665 | if (gravity < 0) 666 | { 667 | stackError("gsc_player_setg_gravity() param must be equal or above zero"); 668 | stackPushUndefined(); 669 | return; 670 | } 671 | 672 | player_g_gravity[id] = gravity; 673 | stackPushBool(qtrue); 674 | } 675 | 676 | void gsc_player_setweaponfiremeleedelay(scr_entref_t id) 677 | { 678 | int delay; 679 | 680 | if ( ! stackGetParams("i", &delay)) 681 | { 682 | stackError("gsc_player_setweaponfiremeleedelay() argument is undefined or has a wrong type"); 683 | stackPushUndefined(); 684 | return; 685 | } 686 | 687 | if (id >= MAX_CLIENTS) 688 | { 689 | stackError("gsc_player_setweaponfiremeleedelay() entity %i is not a player", id); 690 | stackPushUndefined(); 691 | return; 692 | } 693 | 694 | if (delay < 0) 695 | { 696 | stackError("gsc_player_setweaponfiremeleedelay() param must be equal or above zero"); 697 | stackPushUndefined(); 698 | return; 699 | } 700 | 701 | playerState_t *ps = SV_GameClientNum(id); 702 | ps->weaponDelay = delay; 703 | stackPushBool(qtrue); 704 | } 705 | 706 | void gsc_player_set_anim(scr_entref_t id) 707 | { 708 | char *animation; 709 | 710 | if ( ! stackGetParams("s", &animation)) 711 | { 712 | stackError("gsc_player_set_anim() argument is undefined or has a wrong type"); 713 | stackPushUndefined(); 714 | return; 715 | } 716 | 717 | gentity_t *entity = &g_entities[id]; 718 | 719 | if (entity->s.eType == ET_CORPSE) 720 | { 721 | int index = BG_AnimationIndexForString(animation); 722 | entity->s.legsAnim = index; 723 | stackPushBool(qtrue); 724 | return; 725 | } 726 | 727 | if (entity->client == NULL) 728 | { 729 | stackError("gsc_player_set_anim() entity %i is not a player", id); 730 | stackPushUndefined(); 731 | return; 732 | } 733 | 734 | extern int custom_animation[MAX_CLIENTS]; 735 | int animationIndex = 0; 736 | 737 | if (strcmp(animation, "none") != 0) 738 | animationIndex = BG_AnimationIndexForString(animation); 739 | 740 | custom_animation[id] = animationIndex; 741 | stackPushBool(qtrue); 742 | } 743 | 744 | void gsc_player_getcooktime(scr_entref_t id) 745 | { 746 | if (id >= MAX_CLIENTS) 747 | { 748 | stackError("gsc_player_getcooktime() entity %i is not a player", id); 749 | stackPushUndefined(); 750 | return; 751 | } 752 | 753 | playerState_t *ps = SV_GameClientNum(id); 754 | stackPushInt(ps->grenadeTimeLeft); 755 | } 756 | 757 | void gsc_kick_slot() 758 | { 759 | int id; 760 | char* msg; 761 | char tmp[128]; 762 | 763 | if ( ! stackGetParams("is", &id, &msg)) 764 | { 765 | stackError("gsc_kick_slot() one or more arguments is undefined or has a wrong type"); 766 | stackPushUndefined(); 767 | return; 768 | } 769 | 770 | if (id >= MAX_CLIENTS) 771 | { 772 | stackError("gsc_kick_slot() entity %i is not a player", id); 773 | stackPushUndefined(); 774 | return; 775 | } 776 | 777 | client_t *client = &svs.clients[id]; 778 | 779 | if (client == NULL) 780 | { 781 | stackPushUndefined(); 782 | return; 783 | } 784 | 785 | if (client->netchan.remoteAddress.type == NA_LOOPBACK) 786 | { 787 | stackPushUndefined(); 788 | return; 789 | } 790 | 791 | strncpy(tmp, msg, sizeof(tmp)); 792 | tmp[sizeof(tmp)] = '\0'; 793 | 794 | SV_DropClient(client, tmp); 795 | stackPushBool(qtrue); 796 | } 797 | 798 | void gsc_player_setguid(scr_entref_t id) 799 | { 800 | int guid; 801 | 802 | if ( ! stackGetParams("i", &guid)) 803 | { 804 | stackError("gsc_player_setguid() argument is undefined or has a wrong type"); 805 | stackPushUndefined(); 806 | return; 807 | } 808 | 809 | if (id >= MAX_CLIENTS) 810 | { 811 | stackError("gsc_player_setguid() entity %i is not a player", id); 812 | stackPushUndefined(); 813 | return; 814 | } 815 | 816 | client_t *client = &svs.clients[id]; 817 | client->guid = guid; 818 | stackPushBool(qtrue); 819 | } 820 | 821 | void gsc_player_clienthasclientmuted(scr_entref_t id) 822 | { 823 | int id2; 824 | 825 | if ( ! stackGetParams("i", &id2)) 826 | { 827 | stackError("gsc_player_clienthasclientmuted() argument is undefined or has a wrong type"); 828 | stackPushUndefined(); 829 | return; 830 | } 831 | 832 | if (id >= MAX_CLIENTS) 833 | { 834 | stackError("gsc_player_clienthasclientmuted() entity %i is not a player", id); 835 | stackPushUndefined(); 836 | return; 837 | } 838 | 839 | stackPushInt(SV_ClientHasClientMuted(id, id2)); 840 | } 841 | 842 | void gsc_player_getlastgamestatesize(scr_entref_t id) 843 | { 844 | if (id >= MAX_CLIENTS) 845 | { 846 | stackError("gsc_player_getlastgamestatesize() entity %i is not a player", id); 847 | stackPushUndefined(); 848 | return; 849 | } 850 | 851 | extern int gamestate_size[MAX_CLIENTS]; 852 | stackPushInt(gamestate_size[id]); 853 | } 854 | 855 | void gsc_player_getfps(scr_entref_t id) 856 | { 857 | if (id >= MAX_CLIENTS) 858 | { 859 | stackError("gsc_player_getfps() entity %i is not a player", id); 860 | stackPushUndefined(); 861 | return; 862 | } 863 | 864 | extern int clientfps[MAX_CLIENTS]; 865 | stackPushInt(clientfps[id]); 866 | } 867 | 868 | void gsc_player_isbot(scr_entref_t id) 869 | { 870 | if (id >= MAX_CLIENTS) 871 | { 872 | stackError("gsc_player_isbot() entity %i is not a player", id); 873 | stackPushUndefined(); 874 | return; 875 | } 876 | 877 | client_t *client = &svs.clients[id]; 878 | stackPushBool(client->bot); 879 | } 880 | 881 | void gsc_player_disableitempickup(scr_entref_t id) 882 | { 883 | if (id >= MAX_CLIENTS) 884 | { 885 | stackError("gsc_player_disableitempickup() entity %i is not a player", id); 886 | stackPushUndefined(); 887 | return; 888 | } 889 | 890 | extern int player_disableitempickup[MAX_CLIENTS]; 891 | player_disableitempickup[id] = 1; 892 | stackPushBool(qtrue); 893 | } 894 | 895 | void gsc_player_enableitempickup(scr_entref_t id) 896 | { 897 | if (id >= MAX_CLIENTS) 898 | { 899 | stackError("gsc_player_enableitempickup() entity %i is not a player", id); 900 | stackPushUndefined(); 901 | return; 902 | } 903 | 904 | extern int player_disableitempickup[MAX_CLIENTS]; 905 | player_disableitempickup[id] = 0; 906 | stackPushBool(qtrue); 907 | } 908 | 909 | void gsc_player_getcurrentoffhandslotammo(scr_entref_t id) 910 | { 911 | if (id >= MAX_CLIENTS) 912 | { 913 | stackError("gsc_player_getcurrentoffhandslotammo() entity %i is not a player", id); 914 | stackPushUndefined(); 915 | return; 916 | } 917 | 918 | playerState_t *ps = SV_GameClientNum(id); 919 | stackPushInt(ps->ammoclip[ps->offHandIndex - 1]); 920 | } 921 | 922 | #if COMPILE_JUMP == 1 923 | void gsc_player_setjump_height(scr_entref_t id) 924 | { 925 | float jump_height; 926 | 927 | if ( ! stackGetParams("f", &jump_height)) 928 | { 929 | stackError("gsc_player_setjump_height() argument is undefined or has a wrong type"); 930 | stackPushUndefined(); 931 | return; 932 | } 933 | 934 | if (id >= MAX_CLIENTS) 935 | { 936 | stackError("gsc_player_setjump_height() entity %i is not a player", id); 937 | stackPushUndefined(); 938 | return; 939 | } 940 | 941 | extern bool player_jump_height_enabled[MAX_CLIENTS]; 942 | extern float player_jump_height[MAX_CLIENTS]; 943 | 944 | if (jump_height < 0) 945 | player_jump_height_enabled[id] = false; 946 | else 947 | { 948 | player_jump_height_enabled[id] = true; 949 | player_jump_height[id] = jump_height; 950 | } 951 | stackPushBool(qtrue); 952 | } 953 | 954 | void gsc_player_setjump_slowdownenable(scr_entref_t id) 955 | { 956 | int slowdown; 957 | 958 | if ( ! stackGetParams("i", &slowdown)) 959 | { 960 | stackError("gsc_player_setjump_slowdownenable() argument is undefined or has a wrong type"); 961 | stackPushUndefined(); 962 | return; 963 | } 964 | 965 | if (id >= MAX_CLIENTS) 966 | { 967 | stackError("gsc_player_setjump_slowdownenable() entity %i is not a player", id); 968 | stackPushUndefined(); 969 | return; 970 | } 971 | 972 | extern bool player_jump_slowdownenable_enabled[MAX_CLIENTS]; 973 | extern bool player_jump_slowdownenable[MAX_CLIENTS]; 974 | 975 | if (slowdown == -1) 976 | player_jump_slowdownenable_enabled[id] = false; 977 | else 978 | { 979 | player_jump_slowdownenable_enabled[id] = true; 980 | player_jump_slowdownenable[id] = slowdown; 981 | } 982 | stackPushBool(qtrue); 983 | } 984 | #endif 985 | 986 | #endif 987 | -------------------------------------------------------------------------------- /gsc_player.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_PLAYER_HPP_ 2 | #define _GSC_PLAYER_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_player_velocity_set(scr_entref_t id); 8 | void gsc_player_velocity_add(scr_entref_t id); 9 | void gsc_player_velocity_get(scr_entref_t id); 10 | void gsc_player_button_ads(scr_entref_t id); 11 | void gsc_player_button_left(scr_entref_t id); 12 | void gsc_player_button_right(scr_entref_t id); 13 | void gsc_player_button_forward(scr_entref_t id); 14 | void gsc_player_button_back(scr_entref_t id); 15 | void gsc_player_button_leanleft(scr_entref_t id); 16 | void gsc_player_button_leanright(scr_entref_t id); 17 | void gsc_player_button_jump(scr_entref_t id); 18 | void gsc_player_button_reload(scr_entref_t id); 19 | void gsc_player_button_frag(scr_entref_t id); 20 | void gsc_player_button_smoke(scr_entref_t id); 21 | void gsc_player_stance_get(scr_entref_t id); 22 | void gsc_player_stance_set(scr_entref_t id); 23 | void gsc_player_spectatorclient_get(scr_entref_t id); 24 | void gsc_player_get_userinfo(scr_entref_t id); 25 | void gsc_player_set_userinfo(scr_entref_t id); 26 | void gsc_player_getip(scr_entref_t id); 27 | void gsc_player_getping(scr_entref_t id); 28 | void gsc_player_clientuserinfochanged(scr_entref_t id); 29 | void gsc_player_clientcommand(scr_entref_t id); 30 | void gsc_player_getlastconnecttime(scr_entref_t id); 31 | void gsc_player_getlastmsg(scr_entref_t id); 32 | void gsc_player_getclientstate(scr_entref_t id); 33 | void gsc_player_addresstype(scr_entref_t id); 34 | void gsc_player_renameclient(scr_entref_t id); 35 | void gsc_player_outofbandprint(scr_entref_t id); 36 | void gsc_player_connectionlesspacket(scr_entref_t id); 37 | void gsc_player_resetnextreliabletime(scr_entref_t id); 38 | void gsc_player_ismantling(scr_entref_t id); 39 | void gsc_player_isonladder(scr_entref_t id); 40 | void gsc_player_isusingturret(scr_entref_t id); 41 | void gsc_player_getjumpslowdowntimer(scr_entref_t id); 42 | void gsc_player_clearjumpstate(scr_entref_t id); 43 | void gsc_player_setg_speed(scr_entref_t id); 44 | void gsc_player_setg_gravity(scr_entref_t id); 45 | void gsc_player_setweaponfiremeleedelay(scr_entref_t id); 46 | void gsc_player_set_anim(scr_entref_t id); 47 | void gsc_player_getcooktime(scr_entref_t id); 48 | void gsc_player_setguid(scr_entref_t id); 49 | void gsc_player_clienthasclientmuted(scr_entref_t id); 50 | void gsc_player_getlastgamestatesize(scr_entref_t id); 51 | void gsc_player_getfps(scr_entref_t id); 52 | void gsc_player_isbot(scr_entref_t id); 53 | void gsc_player_disableitempickup(scr_entref_t id); 54 | void gsc_player_enableitempickup(scr_entref_t id); 55 | void gsc_player_getcurrentoffhandslotammo(scr_entref_t id); 56 | 57 | // jump functions 58 | void gsc_player_setjump_slowdownenable(scr_entref_t id); 59 | void gsc_player_setjump_height(scr_entref_t id); 60 | 61 | // player functions without entity 62 | void gsc_kick_slot(); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /gsc_sqlite.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_sqlite.hpp" 2 | 3 | #if COMPILE_SQLITE == 1 4 | 5 | #include 6 | #include 7 | 8 | #define MAX_SQLITE_FIELDS 128 9 | #define MAX_SQLITE_ROWS 128 10 | #define MAX_SQLITE_ROW_LENGTH 256 11 | #define MAX_SQLITE_TASKS 512 12 | #define MAX_SQLITE_DB_STORES 64 13 | 14 | #define SQLITE_TIMEOUT 2000 15 | 16 | enum 17 | { 18 | INT_VALUE, 19 | FLOAT_VALUE, 20 | STRING_VALUE, 21 | VECTOR_VALUE, 22 | OBJECT_VALUE 23 | }; 24 | 25 | struct async_sqlite_task 26 | { 27 | async_sqlite_task *prev; 28 | async_sqlite_task *next; 29 | sqlite3 *db; 30 | sqlite3_stmt *statement; 31 | char query[COD2_MAX_STRINGLENGTH]; 32 | char row[MAX_SQLITE_FIELDS][MAX_SQLITE_ROWS][MAX_SQLITE_ROW_LENGTH]; 33 | int result; 34 | int fields_size; 35 | int rows_size; 36 | int callback; 37 | bool done; 38 | bool save; 39 | bool error; 40 | bool remove; 41 | char errorMessage[COD2_MAX_STRINGLENGTH]; 42 | bool hasargument; 43 | int valueType; 44 | int intValue; 45 | float floatValue; 46 | char stringValue[COD2_MAX_STRINGLENGTH]; 47 | vec3_t vectorValue; 48 | unsigned int objectValue; 49 | bool hasentity; 50 | gentity_t *gentity; 51 | }; 52 | 53 | struct sqlite_db_store 54 | { 55 | sqlite_db_store *prev; 56 | sqlite_db_store *next; 57 | sqlite3 *db; 58 | }; 59 | 60 | async_sqlite_task *first_async_sqlite_task = NULL; 61 | sqlite_db_store *first_sqlite_db_store = NULL; 62 | pthread_mutex_t async_sqlite_mutex_lock; 63 | int async_sqlite_initialized = 0; 64 | 65 | void free_sqlite_db_stores_and_tasks() 66 | { 67 | pthread_mutex_lock(&async_sqlite_mutex_lock); 68 | 69 | async_sqlite_task *current = first_async_sqlite_task; 70 | 71 | while (current != NULL) 72 | { 73 | async_sqlite_task *task = current; 74 | current = current->next; 75 | 76 | if (task->statement != NULL) 77 | sqlite3_finalize(task->statement); 78 | 79 | if (task->next != NULL) 80 | task->next->prev = task->prev; 81 | 82 | if (task->prev != NULL) 83 | task->prev->next = task->next; 84 | else 85 | first_async_sqlite_task = task->next; 86 | 87 | delete task; 88 | } 89 | 90 | sqlite_db_store *current_store = first_sqlite_db_store; 91 | 92 | while (current_store != NULL) 93 | { 94 | sqlite_db_store *store = current_store; 95 | current_store = current_store->next; 96 | 97 | if (store->db != NULL) 98 | sqlite3_close(store->db); 99 | 100 | if (store->next != NULL) 101 | store->next->prev = store->prev; 102 | 103 | if (store->prev != NULL) 104 | store->prev->next = store->next; 105 | else 106 | first_sqlite_db_store = store->next; 107 | 108 | delete store; 109 | } 110 | 111 | pthread_mutex_unlock(&async_sqlite_mutex_lock); 112 | } 113 | 114 | void *async_sqlite_query_handler(void*) 115 | { 116 | while(1) 117 | { 118 | pthread_mutex_lock(&async_sqlite_mutex_lock); 119 | 120 | async_sqlite_task *current = first_async_sqlite_task; 121 | 122 | while (current != NULL) 123 | { 124 | async_sqlite_task *task = current; 125 | current = current->next; 126 | 127 | if (!task->done) 128 | { 129 | task->result = sqlite3_prepare_v2(task->db, task->query, COD2_MAX_STRINGLENGTH, &task->statement, 0); 130 | 131 | if (task->result != SQLITE_OK) 132 | { 133 | task->error = true; 134 | strncpy(task->errorMessage, sqlite3_errmsg(task->db), COD2_MAX_STRINGLENGTH - 1); 135 | task->errorMessage[COD2_MAX_STRINGLENGTH - 1] = '\0'; 136 | } 137 | 138 | if (!task->error) 139 | { 140 | task->result = sqlite3_step(task->statement); 141 | task->fields_size = 0; 142 | 143 | while (task->result != SQLITE_DONE) 144 | { 145 | if (task->result == SQLITE_ROW) 146 | { 147 | if (task->save && task->callback) 148 | { 149 | if (task->fields_size >= MAX_SQLITE_FIELDS) 150 | break; 151 | 152 | task->rows_size = 0; 153 | 154 | for (int i = 0; i < sqlite3_column_count(task->statement); i++) 155 | { 156 | if (task->rows_size >= MAX_SQLITE_ROWS) 157 | break; 158 | 159 | const unsigned char *text = sqlite3_column_text(task->statement, i); 160 | 161 | if (text != NULL) 162 | { 163 | strncpy(task->row[task->fields_size][task->rows_size], reinterpret_cast(text), MAX_SQLITE_ROW_LENGTH - 1); 164 | task->row[task->fields_size][task->rows_size][MAX_SQLITE_ROW_LENGTH - 1] = '\0'; 165 | } 166 | 167 | task->rows_size++; 168 | } 169 | 170 | task->fields_size++; 171 | } 172 | } 173 | else 174 | { 175 | task->error = true; 176 | strncpy(task->errorMessage, sqlite3_errmsg(task->db), COD2_MAX_STRINGLENGTH - 1); 177 | task->errorMessage[COD2_MAX_STRINGLENGTH - 1] = '\0'; 178 | break; 179 | } 180 | 181 | task->result = sqlite3_step(task->statement); 182 | } 183 | 184 | sqlite3_finalize(task->statement); 185 | } 186 | 187 | task->done = true; 188 | } 189 | } 190 | 191 | pthread_mutex_unlock(&async_sqlite_mutex_lock); 192 | 193 | usleep(10000); 194 | } 195 | 196 | return NULL; 197 | } 198 | 199 | void gsc_async_sqlite_initialize() 200 | { 201 | if (!async_sqlite_initialized) 202 | { 203 | if (pthread_mutex_init(&async_sqlite_mutex_lock, NULL) != 0) 204 | { 205 | stackError("gsc_async_sqlite_initialize() failed to initialize async_sqlite_mutex_lock mutex!"); 206 | stackPushUndefined(); 207 | return; 208 | } 209 | 210 | pthread_t async_handler; 211 | 212 | if (pthread_create(&async_handler, NULL, async_sqlite_query_handler, NULL) != 0) 213 | { 214 | stackError("gsc_async_sqlite_initialize() error creating async handler thread!"); 215 | stackPushUndefined(); 216 | return; 217 | } 218 | 219 | if (pthread_detach(async_handler) != 0) 220 | { 221 | stackError("gsc_async_sqlite_initialize() error detaching async handler thread!"); 222 | stackPushUndefined(); 223 | return; 224 | } 225 | 226 | async_sqlite_initialized = 1; 227 | } 228 | else 229 | Com_DPrintf("gsc_async_sqlite_initialize() async handler already initialized.\n"); 230 | 231 | stackPushInt(async_sqlite_initialized); 232 | } 233 | 234 | void gsc_async_sqlite_create_query() 235 | { 236 | int db; 237 | char *query; 238 | 239 | if ( ! stackGetParams("is", &db, &query)) 240 | { 241 | stackError("gsc_async_sqlite_create_query() one or more arguments is undefined or has a wrong type"); 242 | stackPushUndefined(); 243 | return; 244 | } 245 | 246 | if (!async_sqlite_initialized) 247 | { 248 | stackError("gsc_async_sqlite_create_query() async handler has not been initialized"); 249 | stackPushUndefined(); 250 | return; 251 | } 252 | 253 | async_sqlite_task *current = first_async_sqlite_task; 254 | 255 | int task_count = 0; 256 | 257 | while (current != NULL && current->next != NULL) 258 | { 259 | if (task_count >= MAX_SQLITE_TASKS - 2) 260 | { 261 | stackError("gsc_async_sqlite_create_query() exceeded async task limit"); 262 | stackPushUndefined(); 263 | return; 264 | } 265 | 266 | current = current->next; 267 | task_count++; 268 | } 269 | 270 | async_sqlite_task *newtask = new async_sqlite_task; 271 | 272 | newtask->prev = current; 273 | newtask->next = NULL; 274 | 275 | newtask->db = (sqlite3 *)db; 276 | 277 | strncpy(newtask->query, query, COD2_MAX_STRINGLENGTH - 1); 278 | newtask->query[COD2_MAX_STRINGLENGTH - 1] = '\0'; 279 | 280 | int callback; 281 | 282 | if (!stackGetParamFunction(2, &callback)) 283 | newtask->callback = 0; 284 | else 285 | newtask->callback = callback; 286 | 287 | newtask->done = false; 288 | newtask->save = true; 289 | newtask->error = false; 290 | newtask->remove = false; 291 | newtask->hasargument = true; 292 | newtask->hasentity = false; 293 | newtask->gentity = NULL; 294 | 295 | int valueInt; 296 | float valueFloat; 297 | char *valueString; 298 | vec3_t valueVector; 299 | unsigned int valueObject; 300 | 301 | if (stackGetParamInt(3, &valueInt)) 302 | { 303 | newtask->valueType = INT_VALUE; 304 | newtask->intValue = valueInt; 305 | } 306 | else if (stackGetParamFloat(3, &valueFloat)) 307 | { 308 | newtask->valueType = FLOAT_VALUE; 309 | newtask->floatValue = valueFloat; 310 | } 311 | else if (stackGetParamString(3, &valueString)) 312 | { 313 | newtask->valueType = STRING_VALUE; 314 | strcpy(newtask->stringValue, valueString); 315 | } 316 | else if (stackGetParamVector(3, valueVector)) 317 | { 318 | newtask->valueType = VECTOR_VALUE; 319 | newtask->vectorValue[0] = valueVector[0]; 320 | newtask->vectorValue[1] = valueVector[1]; 321 | newtask->vectorValue[2] = valueVector[2]; 322 | } 323 | else if (stackGetParamObject(3, &valueObject)) 324 | { 325 | newtask->valueType = OBJECT_VALUE; 326 | newtask->objectValue = valueObject; 327 | } 328 | else 329 | newtask->hasargument = false; 330 | 331 | if (current != NULL) 332 | current->next = newtask; 333 | else 334 | first_async_sqlite_task = newtask; 335 | 336 | stackPushBool(qtrue); 337 | } 338 | 339 | void gsc_async_sqlite_create_query_nosave() 340 | { 341 | int db; 342 | char *query; 343 | 344 | if ( ! stackGetParams("is", &db, &query)) 345 | { 346 | stackError("gsc_async_sqlite_create_query_nosave() one or more arguments is undefined or has a wrong type"); 347 | stackPushUndefined(); 348 | return; 349 | } 350 | 351 | if (!async_sqlite_initialized) 352 | { 353 | stackError("gsc_async_sqlite_create_query_nosave() async handler has not been initialized"); 354 | stackPushUndefined(); 355 | return; 356 | } 357 | 358 | async_sqlite_task *current = first_async_sqlite_task; 359 | 360 | int task_count = 0; 361 | 362 | while (current != NULL && current->next != NULL) 363 | { 364 | if (task_count >= MAX_SQLITE_TASKS - 2) 365 | { 366 | stackError("gsc_async_sqlite_create_query_nosave() exceeded async task limit"); 367 | stackPushUndefined(); 368 | return; 369 | } 370 | 371 | current = current->next; 372 | task_count++; 373 | } 374 | 375 | async_sqlite_task *newtask = new async_sqlite_task; 376 | 377 | newtask->prev = current; 378 | newtask->next = NULL; 379 | 380 | newtask->db = (sqlite3 *)db; 381 | 382 | strncpy(newtask->query, query, COD2_MAX_STRINGLENGTH - 1); 383 | newtask->query[COD2_MAX_STRINGLENGTH - 1] = '\0'; 384 | 385 | int callback; 386 | 387 | if (!stackGetParamFunction(2, &callback)) 388 | newtask->callback = 0; 389 | else 390 | newtask->callback = callback; 391 | 392 | newtask->done = false; 393 | newtask->save = false; 394 | newtask->error = false; 395 | newtask->remove = false; 396 | newtask->hasargument = true; 397 | newtask->hasentity = false; 398 | newtask->gentity = NULL; 399 | 400 | int valueInt; 401 | float valueFloat; 402 | char *valueString; 403 | vec3_t valueVector; 404 | unsigned int valueObject; 405 | 406 | if (stackGetParamInt(3, &valueInt)) 407 | { 408 | newtask->valueType = INT_VALUE; 409 | newtask->intValue = valueInt; 410 | } 411 | else if (stackGetParamFloat(3, &valueFloat)) 412 | { 413 | newtask->valueType = FLOAT_VALUE; 414 | newtask->floatValue = valueFloat; 415 | } 416 | else if (stackGetParamString(3, &valueString)) 417 | { 418 | newtask->valueType = STRING_VALUE; 419 | strcpy(newtask->stringValue, valueString); 420 | } 421 | else if (stackGetParamVector(3, valueVector)) 422 | { 423 | newtask->valueType = VECTOR_VALUE; 424 | newtask->vectorValue[0] = valueVector[0]; 425 | newtask->vectorValue[1] = valueVector[1]; 426 | newtask->vectorValue[2] = valueVector[2]; 427 | } 428 | else if (stackGetParamObject(3, &valueObject)) 429 | { 430 | newtask->valueType = OBJECT_VALUE; 431 | newtask->objectValue = valueObject; 432 | } 433 | else 434 | newtask->hasargument = false; 435 | 436 | if (current != NULL) 437 | current->next = newtask; 438 | else 439 | first_async_sqlite_task = newtask; 440 | 441 | stackPushBool(qtrue); 442 | } 443 | 444 | void gsc_async_sqlite_create_entity_query(scr_entref_t entid) 445 | { 446 | int db; 447 | char *query; 448 | 449 | if ( ! stackGetParams("is", &db, &query)) 450 | { 451 | stackError("gsc_async_sqlite_create_entity_query() one or more arguments is undefined or has a wrong type"); 452 | stackPushUndefined(); 453 | return; 454 | } 455 | 456 | if (!async_sqlite_initialized) 457 | { 458 | stackError("gsc_async_sqlite_create_entity_query() async handler has not been initialized"); 459 | stackPushUndefined(); 460 | return; 461 | } 462 | 463 | async_sqlite_task *current = first_async_sqlite_task; 464 | 465 | int task_count = 0; 466 | 467 | while (current != NULL && current->next != NULL) 468 | { 469 | if (task_count >= MAX_SQLITE_TASKS - 2) 470 | { 471 | stackError("gsc_async_sqlite_create_entity_query() exceeded async task limit"); 472 | stackPushUndefined(); 473 | return; 474 | } 475 | 476 | current = current->next; 477 | task_count++; 478 | } 479 | 480 | async_sqlite_task *newtask = new async_sqlite_task; 481 | 482 | newtask->prev = current; 483 | newtask->next = NULL; 484 | 485 | newtask->db = (sqlite3 *)db; 486 | 487 | strncpy(newtask->query, query, COD2_MAX_STRINGLENGTH - 1); 488 | newtask->query[COD2_MAX_STRINGLENGTH - 1] = '\0'; 489 | 490 | int callback; 491 | 492 | if (!stackGetParamFunction(2, &callback)) 493 | newtask->callback = 0; 494 | else 495 | newtask->callback = callback; 496 | 497 | newtask->done = false; 498 | newtask->save = true; 499 | newtask->error = false; 500 | newtask->remove = false; 501 | newtask->hasargument = true; 502 | newtask->hasentity = true; 503 | newtask->gentity = &g_entities[entid]; 504 | 505 | int valueInt; 506 | float valueFloat; 507 | char *valueString; 508 | vec3_t valueVector; 509 | unsigned int valueObject; 510 | 511 | if (stackGetParamInt(3, &valueInt)) 512 | { 513 | newtask->valueType = INT_VALUE; 514 | newtask->intValue = valueInt; 515 | } 516 | else if (stackGetParamFloat(3, &valueFloat)) 517 | { 518 | newtask->valueType = FLOAT_VALUE; 519 | newtask->floatValue = valueFloat; 520 | } 521 | else if (stackGetParamString(3, &valueString)) 522 | { 523 | newtask->valueType = STRING_VALUE; 524 | strcpy(newtask->stringValue, valueString); 525 | } 526 | else if (stackGetParamVector(3, valueVector)) 527 | { 528 | newtask->valueType = VECTOR_VALUE; 529 | newtask->vectorValue[0] = valueVector[0]; 530 | newtask->vectorValue[1] = valueVector[1]; 531 | newtask->vectorValue[2] = valueVector[2]; 532 | } 533 | else if (stackGetParamObject(3, &valueObject)) 534 | { 535 | newtask->valueType = OBJECT_VALUE; 536 | newtask->objectValue = valueObject; 537 | } 538 | else 539 | newtask->hasargument = false; 540 | 541 | if (current != NULL) 542 | current->next = newtask; 543 | else 544 | first_async_sqlite_task = newtask; 545 | 546 | stackPushBool(qtrue); 547 | } 548 | 549 | void gsc_async_sqlite_create_entity_query_nosave(scr_entref_t entid) 550 | { 551 | int db; 552 | char *query; 553 | 554 | if ( ! stackGetParams("is", &db, &query)) 555 | { 556 | stackError("gsc_async_sqlite_create_entity_query_nosave() one or more arguments is undefined or has a wrong type"); 557 | stackPushUndefined(); 558 | return; 559 | } 560 | 561 | if (!async_sqlite_initialized) 562 | { 563 | stackError("gsc_async_sqlite_create_entity_query_nosave() async handler has not been initialized"); 564 | stackPushUndefined(); 565 | return; 566 | } 567 | 568 | async_sqlite_task *current = first_async_sqlite_task; 569 | 570 | int task_count = 0; 571 | 572 | while (current != NULL && current->next != NULL) 573 | { 574 | if (task_count >= MAX_SQLITE_TASKS - 2) 575 | { 576 | stackError("gsc_async_sqlite_create_entity_query_nosave() exceeded async task limit"); 577 | stackPushUndefined(); 578 | return; 579 | } 580 | 581 | current = current->next; 582 | task_count++; 583 | } 584 | 585 | async_sqlite_task *newtask = new async_sqlite_task; 586 | 587 | newtask->prev = current; 588 | newtask->next = NULL; 589 | 590 | newtask->db = (sqlite3 *)db; 591 | 592 | strncpy(newtask->query, query, COD2_MAX_STRINGLENGTH - 1); 593 | newtask->query[COD2_MAX_STRINGLENGTH - 1] = '\0'; 594 | 595 | int callback; 596 | 597 | if (!stackGetParamFunction(2, &callback)) 598 | newtask->callback = 0; 599 | else 600 | newtask->callback = callback; 601 | 602 | newtask->done = false; 603 | newtask->save = false; 604 | newtask->error = false; 605 | newtask->remove = false; 606 | newtask->hasargument = true; 607 | newtask->hasentity = true; 608 | newtask->gentity = &g_entities[entid]; 609 | 610 | int valueInt; 611 | float valueFloat; 612 | char *valueString; 613 | vec3_t valueVector; 614 | unsigned int valueObject; 615 | 616 | if (stackGetParamInt(3, &valueInt)) 617 | { 618 | newtask->valueType = INT_VALUE; 619 | newtask->intValue = valueInt; 620 | } 621 | else if (stackGetParamFloat(3, &valueFloat)) 622 | { 623 | newtask->valueType = FLOAT_VALUE; 624 | newtask->floatValue = valueFloat; 625 | } 626 | else if (stackGetParamString(3, &valueString)) 627 | { 628 | newtask->valueType = STRING_VALUE; 629 | strcpy(newtask->stringValue, valueString); 630 | } 631 | else if (stackGetParamVector(3, valueVector)) 632 | { 633 | newtask->valueType = VECTOR_VALUE; 634 | newtask->vectorValue[0] = valueVector[0]; 635 | newtask->vectorValue[1] = valueVector[1]; 636 | newtask->vectorValue[2] = valueVector[2]; 637 | } 638 | else if (stackGetParamObject(3, &valueObject)) 639 | { 640 | newtask->valueType = OBJECT_VALUE; 641 | newtask->objectValue = valueObject; 642 | } 643 | else 644 | newtask->hasargument = false; 645 | 646 | if (current != NULL) 647 | current->next = newtask; 648 | else 649 | first_async_sqlite_task = newtask; 650 | 651 | stackPushBool(qtrue); 652 | } 653 | 654 | void gsc_async_sqlite_checkdone() 655 | { 656 | async_sqlite_task *current = first_async_sqlite_task; 657 | 658 | while (current != NULL) 659 | { 660 | async_sqlite_task *task = current; 661 | current = current->next; 662 | 663 | if (!task->remove) 664 | { 665 | if (task->done) 666 | { 667 | if (!task->error) 668 | { 669 | if (task->save && task->callback) 670 | { 671 | if (task->hasentity) 672 | { 673 | if (task->gentity != NULL) 674 | { 675 | if (task->hasargument) 676 | { 677 | switch(task->valueType) 678 | { 679 | case INT_VALUE: 680 | stackPushInt(task->intValue); 681 | break; 682 | 683 | case FLOAT_VALUE: 684 | stackPushFloat(task->floatValue); 685 | break; 686 | 687 | case STRING_VALUE: 688 | stackPushString(task->stringValue); 689 | break; 690 | 691 | case VECTOR_VALUE: 692 | stackPushVector(task->vectorValue); 693 | break; 694 | 695 | case OBJECT_VALUE: 696 | stackPushObject(task->objectValue); 697 | break; 698 | 699 | default: 700 | stackPushUndefined(); 701 | break; 702 | } 703 | } 704 | 705 | stackPushArray(); 706 | 707 | for (int i = 0; i < task->fields_size; i++) 708 | { 709 | stackPushArray(); 710 | 711 | for (int x = 0; x < task->rows_size; x++) 712 | { 713 | if (task->row[i][x] != NULL) 714 | { 715 | stackPushString(task->row[i][x]); 716 | stackPushArrayLast(); 717 | } 718 | } 719 | 720 | stackPushArrayLast(); 721 | } 722 | 723 | short ret = Scr_ExecEntThread(task->gentity, task->callback, task->save + task->hasargument); 724 | Scr_FreeThread(ret); 725 | } 726 | } 727 | else 728 | { 729 | if (task->hasargument) 730 | { 731 | switch(task->valueType) 732 | { 733 | case INT_VALUE: 734 | stackPushInt(task->intValue); 735 | break; 736 | 737 | case FLOAT_VALUE: 738 | stackPushFloat(task->floatValue); 739 | break; 740 | 741 | case STRING_VALUE: 742 | stackPushString(task->stringValue); 743 | break; 744 | 745 | case VECTOR_VALUE: 746 | stackPushVector(task->vectorValue); 747 | break; 748 | 749 | default: 750 | stackPushUndefined(); 751 | break; 752 | } 753 | } 754 | 755 | stackPushArray(); 756 | 757 | for (int i = 0; i < task->fields_size; i++) 758 | { 759 | stackPushArray(); 760 | 761 | for (int x = 0; x < task->rows_size; x++) 762 | { 763 | stackPushString(task->row[i][x]); 764 | stackPushArrayLast(); 765 | } 766 | 767 | stackPushArrayLast(); 768 | } 769 | 770 | short ret = Scr_ExecThread(task->callback, task->save + task->hasargument); 771 | Scr_FreeThread(ret); 772 | } 773 | } 774 | } 775 | else if (task->query && task->errorMessage) 776 | stackError("gsc_async_sqlite_checkdone() query error in '%s' - '%s'", task->query, task->errorMessage); 777 | 778 | task->remove = true; 779 | } 780 | } 781 | else 782 | { 783 | if (pthread_mutex_trylock(&async_sqlite_mutex_lock) == 0) 784 | { 785 | if (task->next != NULL) 786 | task->next->prev = task->prev; 787 | 788 | if (task->prev != NULL) 789 | task->prev->next = task->next; 790 | else 791 | first_async_sqlite_task = task->next; 792 | 793 | delete task; 794 | 795 | pthread_mutex_unlock(&async_sqlite_mutex_lock); 796 | } 797 | } 798 | } 799 | } 800 | 801 | void gsc_sqlite_open() 802 | { 803 | char *database; 804 | 805 | if ( ! stackGetParams("s", &database)) 806 | { 807 | stackError("gsc_sqlite_open() argument is undefined or has a wrong type"); 808 | stackPushUndefined(); 809 | return; 810 | } 811 | 812 | sqlite3 *db; 813 | 814 | int rc = sqlite3_open(database, &db); 815 | 816 | if (rc != SQLITE_OK) 817 | { 818 | stackError("gsc_sqlite_open() cannot open database: %s", sqlite3_errmsg(db)); 819 | stackPushUndefined(); 820 | return; 821 | } 822 | 823 | rc = sqlite3_busy_timeout(db, SQLITE_TIMEOUT); 824 | 825 | if (rc != SQLITE_OK) 826 | { 827 | stackError("gsc_sqlite_open() cannot set database busy timeout: %s", sqlite3_errmsg(db)); 828 | sqlite3_close(db); 829 | stackPushUndefined(); 830 | return; 831 | } 832 | 833 | sqlite_db_store *current = first_sqlite_db_store; 834 | 835 | int store_count = 0; 836 | 837 | while (current != NULL && current->next != NULL) 838 | { 839 | if (store_count >= MAX_SQLITE_DB_STORES - 2) 840 | { 841 | stackError("gsc_sqlite_open() exceeded db store limit"); 842 | sqlite3_close(db); 843 | stackPushUndefined(); 844 | return; 845 | } 846 | 847 | current = current->next; 848 | store_count++; 849 | } 850 | 851 | sqlite_db_store *newstore = new sqlite_db_store; 852 | 853 | newstore->prev = current; 854 | newstore->next = NULL; 855 | 856 | newstore->db = db; 857 | 858 | if (current != NULL) 859 | current->next = newstore; 860 | else 861 | first_sqlite_db_store = newstore; 862 | 863 | stackPushInt((int)db); 864 | } 865 | 866 | void gsc_sqlite_query() 867 | { 868 | int db; 869 | char *query; 870 | 871 | if ( ! stackGetParams("is", &db, &query)) 872 | { 873 | stackError("gsc_sqlite_query() one or more arguments is undefined or has a wrong type"); 874 | stackPushUndefined(); 875 | return; 876 | } 877 | 878 | sqlite3_stmt *statement; 879 | int result; 880 | 881 | result = sqlite3_prepare_v2((sqlite3 *)db, query, COD2_MAX_STRINGLENGTH, &statement, 0); 882 | 883 | if (result != SQLITE_OK) 884 | { 885 | stackError("gsc_sqlite_query() failed to fetch query data: %s", sqlite3_errmsg((sqlite3 *)db)); 886 | stackPushUndefined(); 887 | } 888 | 889 | stackPushArray(); 890 | 891 | result = sqlite3_step(statement); 892 | 893 | while (result != SQLITE_DONE) 894 | { 895 | if (result == SQLITE_ROW) 896 | { 897 | stackPushArray(); 898 | 899 | for (int i = 0; i < sqlite3_column_count(statement); i++) 900 | { 901 | const unsigned char *text = sqlite3_column_text(statement, i); 902 | 903 | if (text != NULL) 904 | { 905 | stackPushString(reinterpret_cast(text)); 906 | stackPushArrayLast(); 907 | } 908 | } 909 | 910 | stackPushArrayLast(); 911 | } 912 | else 913 | { 914 | stackError("gsc_sqlite_query() failed to execute query: %s", sqlite3_errmsg((sqlite3 *)db)); 915 | stackPushUndefined(); 916 | sqlite3_finalize(statement); 917 | return; 918 | } 919 | 920 | result = sqlite3_step(statement); 921 | } 922 | 923 | sqlite3_finalize(statement); 924 | } 925 | 926 | void gsc_sqlite_close() 927 | { 928 | int db; 929 | 930 | if ( ! stackGetParams("i", &db)) 931 | { 932 | stackError("gsc_sqlite_close() argument is undefined or has a wrong type"); 933 | stackPushUndefined(); 934 | return; 935 | } 936 | 937 | int rc = sqlite3_close((sqlite3 *)db); 938 | 939 | if (rc != SQLITE_OK) 940 | { 941 | stackError("gsc_sqlite_close() cannot close database: %s", sqlite3_errmsg((sqlite3 *)db)); 942 | stackPushUndefined(); 943 | return; 944 | } 945 | 946 | sqlite_db_store *current = first_sqlite_db_store; 947 | 948 | while (current != NULL) 949 | { 950 | sqlite_db_store *store = current; 951 | current = current->next; 952 | 953 | if (store->db == (sqlite3 *)db) 954 | { 955 | if (store->next != NULL) 956 | store->next->prev = store->prev; 957 | 958 | if (store->prev != NULL) 959 | store->prev->next = store->next; 960 | else 961 | first_sqlite_db_store = store->next; 962 | 963 | delete store; 964 | } 965 | } 966 | 967 | stackPushBool(qtrue); 968 | } 969 | 970 | void gsc_sqlite_escape_string() 971 | { 972 | char *string; 973 | 974 | if ( ! stackGetParams("s", &string)) 975 | { 976 | stackError("gsc_sqlite_escape_string() argument is undefined or has a wrong type"); 977 | stackPushUndefined(); 978 | return; 979 | } 980 | 981 | char *result = sqlite3_mprintf("%q", string); 982 | 983 | stackPushString(result); 984 | sqlite3_free(result); 985 | } 986 | 987 | void gsc_sqlite_databases_count() 988 | { 989 | sqlite_db_store *current = first_sqlite_db_store; 990 | 991 | int store_count = 0; 992 | 993 | while (current != NULL) 994 | { 995 | current = current->next; 996 | store_count++; 997 | } 998 | 999 | stackPushInt(store_count); 1000 | } 1001 | 1002 | void gsc_sqlite_tasks_count() 1003 | { 1004 | async_sqlite_task *current = first_async_sqlite_task; 1005 | 1006 | int task_count = 0; 1007 | 1008 | while (current != NULL) 1009 | { 1010 | current = current->next; 1011 | task_count++; 1012 | } 1013 | 1014 | stackPushInt(task_count); 1015 | } 1016 | 1017 | #endif 1018 | -------------------------------------------------------------------------------- /gsc_sqlite.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_SQLITE_HPP_ 2 | #define _GSC_SQLITE_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_sqlite_open(); 8 | void gsc_sqlite_query(); 9 | void gsc_sqlite_close(); 10 | void gsc_sqlite_escape_string(); 11 | void gsc_sqlite_databases_count(); 12 | void gsc_sqlite_tasks_count(); 13 | 14 | void gsc_async_sqlite_initialize(); 15 | void gsc_async_sqlite_create_query(); 16 | void gsc_async_sqlite_create_query_nosave(); 17 | void gsc_async_sqlite_checkdone(); 18 | 19 | void gsc_async_sqlite_create_entity_query(scr_entref_t entid); 20 | void gsc_async_sqlite_create_entity_query_nosave(scr_entref_t entid); 21 | 22 | void free_sqlite_db_stores_and_tasks(); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /gsc_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_utils.hpp" 2 | 3 | #if COMPILE_UTILS == 1 4 | 5 | //thanks to riicchhaarrd/php 6 | void gsc_utils_getarraykeys() 7 | { 8 | unsigned int arrIndex; 9 | 10 | if (!stackGetParamObject(0, &arrIndex)) 11 | { 12 | stackError("gsc_utils_getarraykeys() argument is undefined or has a wrong type"); 13 | stackPushUndefined(); 14 | return; 15 | } 16 | 17 | int arraysize = GetArraySize(arrIndex); 18 | 19 | if (!arraysize) 20 | { 21 | stackError("gsc_utils_getarraykeys() got an empty or invalid array"); 22 | stackPushUndefined(); 23 | return; 24 | } 25 | 26 | unsigned int index = arrIndex; 27 | unsigned int name; 28 | 29 | stackPushArray(); 30 | 31 | for (int i = 0; i < arraysize; i++) 32 | { 33 | index = GetNextVariable(index); 34 | name = GetVariableName(index); 35 | 36 | if (name < 0x10000) 37 | { 38 | stackPushString(SL_ConvertToString(name)); 39 | stackPushArrayLast(); 40 | } 41 | } 42 | } 43 | 44 | /* 45 | ================= 46 | Sys_AnsiColorPrint 47 | Transform Q3 colour codes to ANSI escape sequences 48 | ================= 49 | */ 50 | #define MAXPRINTMSG 1024 51 | #define ColorIndex(c) (((c) - '0') & 0x07) 52 | #define Q_COLOR_ESCAPE '^' 53 | #define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && isdigit(*((p)+1))) // ^[0-9] 54 | void Sys_AnsiColorPrint( const char *msg ) 55 | { 56 | static char buffer[ MAXPRINTMSG ]; 57 | int length = 0; 58 | static int q3ToAnsi[ 8 ] = 59 | { 60 | 30, // COLOR_BLACK 61 | 31, // COLOR_RED 62 | 32, // COLOR_GREEN 63 | 33, // COLOR_YELLOW 64 | 34, // COLOR_BLUE 65 | 36, // COLOR_CYAN 66 | 35, // COLOR_MAGENTA 67 | 0 // COLOR_WHITE 68 | }; 69 | 70 | while( *msg ) 71 | { 72 | if( Q_IsColorString( msg ) || *msg == '\n' ) 73 | { 74 | // First empty the buffer 75 | if( length > 0 ) 76 | { 77 | buffer[ length ] = '\0'; 78 | fputs( buffer, stdout ); 79 | length = 0; 80 | } 81 | 82 | if( *msg == '\n' ) 83 | { 84 | // Issue a reset and then the newline 85 | fputs( "\033[0m\n", stdout ); 86 | msg++; 87 | } 88 | else 89 | { 90 | // Print the color code 91 | snprintf( buffer, sizeof( buffer ), "\033[1;%dm", q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] ); 92 | fputs( buffer, stdout ); 93 | msg += 2; 94 | } 95 | } 96 | else 97 | { 98 | if( length >= MAXPRINTMSG - 1 ) 99 | break; 100 | 101 | buffer[ length ] = *msg; 102 | length++; 103 | msg++; 104 | } 105 | } 106 | 107 | // Empty anything still left in the buffer 108 | if( length > 0 ) 109 | { 110 | buffer[ length ] = '\0'; 111 | fputs( buffer, stdout ); 112 | // Issue a reset at the end 113 | fputs( "\033[0m", stdout ); 114 | } 115 | } 116 | 117 | extern cvar_t *con_coloredPrints; 118 | int stackPrintParam(int param) 119 | { 120 | if (param >= Scr_GetNumParam()) 121 | return 0; 122 | 123 | switch (stackGetParamType(param)) 124 | { 125 | case STACK_STRING: 126 | char *str; 127 | stackGetParamString(param, &str); // no error checking, since we know it's a string 128 | if (con_coloredPrints->boolean && strchr(str, Q_COLOR_ESCAPE) != NULL) 129 | Sys_AnsiColorPrint(str); 130 | else 131 | printf("%s", str); 132 | return 1; 133 | 134 | case STACK_VECTOR: 135 | float vec[3]; 136 | stackGetParamVector(param, vec); 137 | printf("(%.2f, %.2f, %.2f)", vec[0], vec[1], vec[2]); 138 | return 1; 139 | 140 | case STACK_FLOAT: 141 | float tmp_float; 142 | stackGetParamFloat(param, &tmp_float); 143 | printf("%.3f", tmp_float); // need a way to define precision 144 | return 1; 145 | 146 | case STACK_INT: 147 | int tmp_int; 148 | stackGetParamInt(param, &tmp_int); 149 | printf("%d", tmp_int); 150 | return 1; 151 | } 152 | 153 | printf("(%s)", stackGetParamTypeAsString(param)); 154 | return 0; 155 | } 156 | 157 | void gsc_utils_printf() 158 | { 159 | char *str; 160 | 161 | if ( ! stackGetParams("s", &str)) 162 | { 163 | stackError("gsc_utils_printf() argument is undefined or has a wrong type"); 164 | stackPushUndefined(); 165 | return; 166 | } 167 | 168 | int param = 1; // maps to first % 169 | int len = strlen(str); 170 | 171 | for (int i = 0; i < len; i++) 172 | { 173 | if (str[i] == '%') 174 | { 175 | if(str[i + 1] == '%') 176 | { 177 | putchar('%'); 178 | i++; 179 | } 180 | else 181 | stackPrintParam(param++); 182 | } 183 | else 184 | putchar(str[i]); 185 | } 186 | 187 | stackPushBool(qtrue); 188 | } 189 | 190 | void gsc_utils_outofbandprint() 191 | { 192 | char * address; 193 | char * msg; 194 | 195 | if (!stackGetParams("ss", &address, &msg)) 196 | { 197 | stackError("gsc_utils_outofbandprint() one or more arguments is undefined or has a wrong type"); 198 | stackPushUndefined(); 199 | return; 200 | } 201 | 202 | netadr_t from; 203 | NET_StringToAdr(address, &from); 204 | NET_OutOfBandPrint(NS_SERVER, from, msg); 205 | } 206 | 207 | void gsc_utils_sprintf() 208 | { 209 | char result[COD2_MAX_STRINGLENGTH]; 210 | char *str; 211 | 212 | if (!stackGetParams("s", &str)) 213 | { 214 | stackError("gsc_utils_sprintf() argument is undefined or has a wrong type"); 215 | stackPushUndefined(); 216 | return; 217 | } 218 | 219 | int param = 1; // maps to first % 220 | int len = strlen(str); 221 | int num = 0; 222 | 223 | for (int i = 0; i < len; i++) 224 | { 225 | if (str[i] == '%') 226 | { 227 | if (str[i + 1] == '%') 228 | { 229 | result[num++] = '%'; 230 | i++; 231 | } 232 | else 233 | { 234 | if(param >= Scr_GetNumParam()) 235 | continue; 236 | 237 | switch (stackGetParamType(param)) 238 | { 239 | case STACK_STRING: 240 | char *tmp_str; 241 | stackGetParamString(param, &tmp_str); // no error checking, since we know it's a string 242 | num += sprintf(&(result[num]), "%s", tmp_str); 243 | break; 244 | 245 | case STACK_VECTOR: 246 | float vec[3]; 247 | stackGetParamVector(param, vec); 248 | num += sprintf(&(result[num]), "(%.2f, %.2f, %.2f)", vec[0], vec[1], vec[2]); 249 | break; 250 | 251 | case STACK_FLOAT: 252 | 253 | float tmp_float; 254 | stackGetParamFloat(param, &tmp_float); 255 | num += sprintf(&(result[num]), "%.3f", tmp_float); // need a way to define precision 256 | break; 257 | 258 | case STACK_INT: 259 | int tmp_int; 260 | stackGetParamInt(param, &tmp_int); 261 | num += sprintf(&(result[num]), "%d", tmp_int); 262 | break; 263 | } 264 | 265 | param++; 266 | } 267 | } 268 | else 269 | result[num++] = str[i]; 270 | } 271 | 272 | result[num] = '\0'; 273 | stackPushString(result); 274 | } 275 | 276 | void gsc_utils_getAscii() 277 | { 278 | char *str; 279 | 280 | if ( ! stackGetParams("s", &str)) 281 | { 282 | stackError("gsc_utils_getAscii() argument is undefined or has a wrong type"); 283 | stackPushUndefined(); 284 | return; 285 | } 286 | 287 | if (!strlen(str)) 288 | { 289 | stackError("gsc_utils_getAscii() string length is 0"); 290 | stackPushUndefined(); 291 | return; 292 | } 293 | 294 | stackPushInt(str[0]); 295 | } 296 | 297 | void gsc_utils_putchar() 298 | { 299 | int val; 300 | 301 | if ( ! stackGetParams("i", &val)) 302 | { 303 | stackError("gsc_utils_putchar() argument is undefined or has a wrong type"); 304 | stackPushUndefined(); 305 | return; 306 | } 307 | 308 | if (val < -127 || val > 127) 309 | { 310 | stackError("gsc_utils_putchar() character index is out of range"); 311 | stackPushUndefined(); 312 | return; 313 | } 314 | 315 | char s[2]; 316 | 317 | s[0] = val; 318 | s[1] = '\0'; 319 | 320 | stackPushString( s ); 321 | } 322 | 323 | void gsc_utils_toupper() 324 | { 325 | char *str; 326 | 327 | if ( ! stackGetParams("s", &str)) 328 | { 329 | stackError("gsc_utils_toupper() argument is undefined or has a wrong type"); 330 | stackPushUndefined(); 331 | return; 332 | } 333 | 334 | if (!strlen(str)) 335 | { 336 | stackError("gsc_utils_toupper() string length is 0"); 337 | stackPushUndefined(); 338 | return; 339 | } 340 | 341 | stackPushString( I_strupr(str) ); 342 | } 343 | 344 | void gsc_utils_system() 345 | { 346 | char *cmd; 347 | 348 | if ( ! stackGetParams("s", &cmd)) 349 | { 350 | stackError("gsc_utils_system() argument is undefined or has a wrong type"); 351 | stackPushUndefined(); 352 | return; 353 | } 354 | 355 | stackPushInt( system(cmd) ); 356 | } 357 | 358 | static int starttime = time(NULL); 359 | void gsc_utils_getserverstarttime() 360 | { 361 | stackPushInt( starttime ); 362 | } 363 | 364 | void gsc_utils_getsystemtime() 365 | { 366 | time_t timer; 367 | stackPushInt( time(&timer) ); 368 | } 369 | 370 | void gsc_utils_getlocaltime() 371 | { 372 | time_t timer; 373 | struct tm *timeinfo; 374 | 375 | time(&timer); 376 | timeinfo = localtime(&timer); 377 | 378 | const char *timestring = asctime(timeinfo); 379 | char stripped_time[128]; 380 | 381 | strncpy(stripped_time, timestring, sizeof(stripped_time)); 382 | stripped_time[strlen(timestring) - 1] = '\0'; 383 | 384 | stackPushString( stripped_time ); 385 | } 386 | 387 | void gsc_utils_exponent() 388 | { 389 | float basis; 390 | float exponent; 391 | 392 | if ( ! stackGetParams("ff", &basis, &exponent)) 393 | { 394 | stackError("gsc_utils_exponent() one or more arguments is undefined or has a wrong type"); 395 | stackPushUndefined(); 396 | return; 397 | } 398 | 399 | stackPushFloat( pow(basis, exponent) ); 400 | } 401 | 402 | void gsc_utils_round() 403 | { 404 | float val; 405 | 406 | if ( ! stackGetParams("f", &val)) 407 | { 408 | stackError("gsc_utils_round() argument is undefined or has a wrong type"); 409 | stackPushUndefined(); 410 | return; 411 | } 412 | 413 | stackPushFloat( roundf(val * 100) / 100 ); 414 | } 415 | 416 | void gsc_utils_file_link() 417 | { 418 | char *source, *dest; 419 | 420 | if ( ! stackGetParams("ss", &source, &dest)) 421 | { 422 | stackError("gsc_utils_file_link() one or more arguments is undefined or has a wrong type"); 423 | stackPushUndefined(); 424 | return; 425 | } 426 | 427 | int link_success = symlink(source, dest) == 0; 428 | stackPushInt( link_success ); 429 | } 430 | 431 | void gsc_utils_file_unlink() 432 | { 433 | char *file; 434 | 435 | if ( ! stackGetParams("s", &file)) 436 | { 437 | stackError("gsc_utils_file_unlink() argument is undefined or has a wrong type"); 438 | stackPushUndefined(); 439 | return; 440 | } 441 | 442 | int unlink_success = unlink(file) == 0; 443 | stackPushInt( unlink_success ); 444 | } 445 | 446 | void gsc_utils_file_exists() 447 | { 448 | char *filename; 449 | 450 | if ( ! stackGetParams("s", &filename)) 451 | { 452 | stackError("gsc_utils_file_exists() argument is undefined or has a wrong type"); 453 | stackPushUndefined(); 454 | return; 455 | } 456 | 457 | int file_exists = access(filename, F_OK) != -1; 458 | stackPushInt( file_exists ); 459 | } 460 | 461 | void gsc_utils_FS_LoadDir() 462 | { 463 | char *path, *dir; 464 | 465 | if ( ! stackGetParams("ss", &path, &dir)) 466 | { 467 | stackError("gsc_utils_FS_LoadDir() one or more arguments is undefined or has a wrong type"); 468 | stackPushUndefined(); 469 | return; 470 | } 471 | 472 | FS_LoadDir(path, dir); 473 | stackPushBool(qtrue); 474 | } 475 | 476 | void gsc_utils_getType() 477 | { 478 | if (Scr_GetNumParam() == 0) 479 | { 480 | stackError("gsc_utils_getType() argument is undefined or has a wrong type"); 481 | stackPushUndefined(); 482 | return; 483 | } 484 | 485 | stackPushString( stackGetParamTypeAsString(0) ); 486 | } 487 | 488 | void gsc_utils_float() 489 | { 490 | if (Scr_GetNumParam() == 0) 491 | { 492 | stackError("gsc_utils_float() argument is undefined or has a wrong type"); 493 | stackPushUndefined(); 494 | return; 495 | } 496 | 497 | switch (stackGetParamType(0)) 498 | { 499 | case STACK_STRING: 500 | char *asstring; 501 | stackGetParamString(0, &asstring); 502 | stackPushFloat( atof(asstring) ); 503 | return; 504 | 505 | case STACK_FLOAT: 506 | float asfloat; 507 | stackGetParamFloat(0, &asfloat); 508 | stackPushFloat( asfloat ); 509 | return; 510 | 511 | case STACK_INT: 512 | int asinteger; 513 | stackGetParamInt(0, &asinteger); 514 | stackPushFloat( float(asinteger) ); 515 | return; 516 | 517 | default: 518 | stackError("gsc_utils_float() argument is undefined or has a wrong type"); 519 | stackPushUndefined(); 520 | return; 521 | } 522 | } 523 | 524 | void gsc_utils_ExecuteString() 525 | { 526 | char *str; 527 | 528 | if ( ! stackGetParams("s", &str)) 529 | { 530 | stackError("gsc_utils_ExecuteString() argument is undefined or has a wrong type"); 531 | stackPushUndefined(); 532 | return; 533 | } 534 | 535 | Cmd_ExecuteString(str); 536 | stackPushBool(qtrue); 537 | } 538 | 539 | void gsc_utils_sendgameservercommand() 540 | { 541 | int clientNum; 542 | char *message; 543 | 544 | if ( ! stackGetParams("is", &clientNum, &message)) 545 | { 546 | stackError("gsc_utils_sendgameservercommand() one or more arguments is undefined or has a wrong type"); 547 | stackPushUndefined(); 548 | return; 549 | } 550 | 551 | SV_GameSendServerCommand(clientNum, 0, message); 552 | stackPushBool(qtrue); 553 | } 554 | 555 | void gsc_utils_scandir() 556 | { 557 | char *dirname; 558 | 559 | if ( ! stackGetParams("s", &dirname)) 560 | { 561 | stackError("gsc_utils_scandir() argument is undefined or has a wrong type"); 562 | stackPushUndefined(); 563 | return; 564 | } 565 | 566 | DIR *dir; 567 | struct dirent *dir_ent; 568 | 569 | dir = opendir(dirname); 570 | 571 | if ( ! dir) 572 | { 573 | stackPushUndefined(); 574 | return; 575 | } 576 | 577 | stackPushArray(); 578 | 579 | while ( (dir_ent = readdir(dir)) != NULL) 580 | { 581 | stackPushString(dir_ent->d_name); 582 | stackPushArrayLast(); 583 | } 584 | 585 | closedir(dir); 586 | } 587 | 588 | void gsc_utils_fopen() 589 | { 590 | FILE *file; 591 | char *filename, *mode; 592 | 593 | if ( ! stackGetParams("ss", &filename, &mode)) 594 | { 595 | stackError("gsc_utils_fopen() one or more arguments is undefined or has a wrong type"); 596 | stackPushUndefined(); 597 | return; 598 | } 599 | 600 | file = fopen(filename, mode); 601 | 602 | if (!file) 603 | { 604 | stackError("gsc_utils_fopen() returned a error"); 605 | stackPushUndefined(); 606 | return; 607 | } 608 | 609 | stackPushInt((int)file); 610 | } 611 | 612 | void gsc_utils_fread() 613 | { 614 | FILE *file; 615 | 616 | if ( ! stackGetParams("i", &file)) 617 | { 618 | stackError("gsc_utils_fread() argument is undefined or has a wrong type"); 619 | stackPushUndefined(); 620 | return; 621 | } 622 | 623 | if (!file) 624 | { 625 | stackError("gsc_utils_fread() returned a error"); 626 | stackPushUndefined(); 627 | return; 628 | } 629 | 630 | char buffer[256]; 631 | int ret = fread(buffer, 1, 255, file); 632 | 633 | if ( ! ret) 634 | { 635 | stackPushUndefined(); 636 | return; 637 | } 638 | 639 | buffer[ret] = '\0'; 640 | stackPushString(buffer); 641 | } 642 | 643 | void gsc_utils_fwrite() 644 | { 645 | FILE *file; 646 | char *buffer; 647 | 648 | if ( ! stackGetParams("is", &file, &buffer)) 649 | { 650 | stackError("gsc_utils_fwrite() one or more arguments is undefined or has a wrong type"); 651 | stackPushUndefined(); 652 | return; 653 | } 654 | 655 | if (!file) 656 | { 657 | stackError("gsc_utils_fwrite() returned a error"); 658 | stackPushUndefined(); 659 | return; 660 | } 661 | 662 | stackPushInt(fwrite(buffer, 1, strlen(buffer), file)); 663 | } 664 | 665 | void gsc_utils_fclose() 666 | { 667 | FILE *file; 668 | 669 | if ( ! stackGetParams("i", &file)) 670 | { 671 | stackError("gsc_utils_fclose() argument is undefined or has a wrong type"); 672 | stackPushUndefined(); 673 | return; 674 | } 675 | 676 | if (!file) 677 | { 678 | stackError("gsc_utils_fclose() returned a error"); 679 | stackPushUndefined(); 680 | return; 681 | } 682 | 683 | stackPushInt( fclose(file) ); 684 | } 685 | 686 | void gsc_utils_fsize() 687 | { 688 | FILE *file; 689 | 690 | if ( ! stackGetParams("i", &file)) 691 | { 692 | stackError("gsc_utils_fsize() argument is undefined or has a wrong type"); 693 | stackPushUndefined(); 694 | return; 695 | } 696 | 697 | if (!file) 698 | { 699 | stackError("gsc_utils_fsize() returned a error"); 700 | stackPushUndefined(); 701 | return; 702 | } 703 | 704 | struct stat buf; 705 | fstat(fileno(file), &buf); 706 | 707 | stackPushInt( buf.st_size ); 708 | } 709 | 710 | void gsc_utils_ftime() 711 | { 712 | FILE *file; 713 | 714 | if ( ! stackGetParams("i", &file)) 715 | { 716 | stackError("gsc_utils_ftime() argument is undefined or has a wrong type"); 717 | stackPushUndefined(); 718 | return; 719 | } 720 | 721 | if (!file) 722 | { 723 | stackError("gsc_utils_ftime() returned a error"); 724 | stackPushUndefined(); 725 | return; 726 | } 727 | 728 | struct stat buf; 729 | fstat(fileno(file), &buf); 730 | 731 | const char *timestring = ctime(&buf.st_mtime); 732 | char stripped_time[128]; 733 | 734 | strncpy(stripped_time, timestring, sizeof(stripped_time)); 735 | stripped_time[strlen(timestring) - 1] = '\0'; 736 | 737 | stackPushString( stripped_time ); 738 | } 739 | 740 | // http://code.metager.de/source/xref/RavenSoftware/jediacademy/code/game/g_utils.cpp#36 741 | void gsc_G_FindConfigstringIndexOriginal() 742 | { 743 | char *name; 744 | int min, max, create; 745 | 746 | if ( ! stackGetParams("siii", &name, &min, &max, &create)) 747 | { 748 | stackError("gsc_G_FindConfigstringIndexOriginal() one or more arguments is undefined or has a wrong type"); 749 | stackPushUndefined(); 750 | return; 751 | } 752 | 753 | if (min < 0 || max >= MAX_CONFIGSTRINGS) 754 | { 755 | stackError("gsc_G_FindConfigstringIndexOriginal() configstring index is out of range"); 756 | stackPushUndefined(); 757 | return; 758 | } 759 | 760 | stackPushInt( G_FindConfigstringIndex(name, min, max, create, "G_FindConfigstringIndex() from GSC") ); 761 | } 762 | 763 | // simple version, without crash 764 | void gsc_G_FindConfigstringIndex() 765 | { 766 | char *name; 767 | int min, max; 768 | 769 | if ( ! stackGetParams("sii", &name, &min, &max)) 770 | { 771 | stackError("gsc_G_FindConfigstringIndex() one or more arguments is undefined or has a wrong type"); 772 | return; 773 | } 774 | 775 | if (min < 0 || max >= MAX_CONFIGSTRINGS) 776 | { 777 | stackError("gsc_G_FindConfigstringIndex() configstring index is out of range"); 778 | stackPushUndefined(); 779 | return; 780 | } 781 | 782 | for (int i = 1; i < max; i++) 783 | { 784 | const char *curitem = SV_GetConfigstringConst(min + i); 785 | 786 | if ( ! *curitem) 787 | break; 788 | 789 | if ( ! strcasecmp(name, curitem)) 790 | { 791 | stackPushInt(i + min); 792 | return; 793 | } 794 | } 795 | 796 | stackPushBool(qtrue); 797 | } 798 | 799 | void gsc_get_configstring() 800 | { 801 | int index; 802 | 803 | if ( ! stackGetParams("i", &index)) 804 | { 805 | stackError("gsc_get_configstring() argument is undefined or has a wrong type"); 806 | stackPushUndefined(); 807 | return; 808 | } 809 | 810 | if (index < 0 || index >= MAX_CONFIGSTRINGS) 811 | { 812 | stackError("gsc_get_configstring() configstring index is out of range"); 813 | stackPushUndefined(); 814 | return; 815 | } 816 | 817 | const char *string = SV_GetConfigstringConst(index); 818 | 819 | if ( ! *string ) 820 | stackPushUndefined(); 821 | else 822 | stackPushString(string); 823 | } 824 | 825 | void gsc_set_configstring() 826 | { 827 | int index; 828 | char *string; 829 | 830 | if ( ! stackGetParams("is", &index, &string)) 831 | { 832 | stackError("gsc_set_configstring() one or more arguments is undefined or has a wrong type"); 833 | stackPushUndefined(); 834 | return; 835 | } 836 | 837 | if (index < 0 || index >= MAX_CONFIGSTRINGS) 838 | { 839 | stackError("gsc_set_configstring() configstring index is out of range"); 840 | stackPushUndefined(); 841 | return; 842 | } 843 | 844 | SV_SetConfigstring(index, string); 845 | stackPushBool(qtrue); 846 | } 847 | 848 | void gsc_utils_sqrt() 849 | { 850 | float x; 851 | 852 | if ( ! stackGetParams("f", &x)) 853 | { 854 | stackError("gsc_utils_sqrt() argument is undefined or has a wrong type"); 855 | stackPushUndefined(); 856 | return; 857 | } 858 | 859 | stackPushFloat(sqrt(x)); 860 | } 861 | 862 | void gsc_utils_sqrtInv() 863 | { 864 | float x; 865 | 866 | if ( ! stackGetParams("f", &x)) 867 | { 868 | stackError("gsc_utils_sqrtInv() argument is undefined or has a wrong type"); 869 | stackPushUndefined(); 870 | return; 871 | } 872 | 873 | // http://www.beyond3d.com/content/articles/8/ 874 | float xhalf = 0.5f*x; 875 | int i = *(int*)&x; 876 | i = 0x5f3759df - (i>>1); 877 | x = *(float*)&i; 878 | x = x*(1.5f - xhalf*x*x); 879 | 880 | stackPushFloat(x); 881 | } 882 | 883 | void gsc_make_localized_string() 884 | { 885 | char *str; 886 | 887 | if ( ! stackGetParams("s", &str)) 888 | { 889 | stackError("gsc_make_localized_string() argument is undefined or has a wrong type"); 890 | stackPushUndefined(); 891 | return; 892 | } 893 | 894 | stackPushString(str); 895 | 896 | VariableValue *var; 897 | int param = 0; 898 | 899 | var = &scrVmPub.top[-param]; 900 | var->type = STACK_LOCALIZED_STRING; 901 | } 902 | 903 | void gsc_utils_getlasttestclientnumber() 904 | { 905 | #if COD_VERSION == COD2_1_0 906 | int offset = 0x083DF9EC; 907 | #elif COD_VERSION == COD2_1_2 908 | int offset = 0x083E1E8C; 909 | #elif COD_VERSION == COD2_1_3 910 | int offset = 0x083E2F0C; 911 | #endif 912 | 913 | stackPushInt(*(int *)offset); 914 | } 915 | 916 | void gsc_utils_bullethiteffect() 917 | { 918 | vec3_t origin; 919 | vec3_t normal; 920 | 921 | if ( ! stackGetParams("vv", &origin, &normal)) 922 | { 923 | stackError("gsc_utils_bullethiteffect() one or more arguments is undefined or has a wrong type"); 924 | stackPushUndefined(); 925 | return; 926 | } 927 | 928 | gentity_t *entity = G_TempEntity(origin, EV_SHOTGUN_HIT); 929 | entity->s.eventParm = DirToByte(normal); 930 | 931 | trace_t trace; 932 | 933 | vec3_t end_origin = { origin[0] - (normal[0] * 10), origin[1] - (normal[1] * 10), origin[2] - (normal[2] * 10) }; 934 | G_LocationalTrace(&trace, origin, end_origin, 1023, 1); 935 | 936 | entity->s.surfaceFlags = (trace.surfaceFlags >> 20) & 0x1F; 937 | 938 | stackPushBool(qtrue); 939 | } 940 | 941 | void gsc_utils_vectorscale() 942 | { 943 | vec3_t vector; 944 | float scale; 945 | 946 | if ( ! stackGetParams("vf", &vector, &scale)) 947 | { 948 | stackError("gsc_utils_vectorscale() one or more arguments is undefined or has a wrong type"); 949 | stackPushUndefined(); 950 | return; 951 | } 952 | 953 | vec3_t out; 954 | 955 | VectorScale(vector, scale, out); 956 | stackPushVector(out); 957 | } 958 | 959 | void gsc_utils_remove_file() 960 | { 961 | char *filename; 962 | 963 | if (!stackGetParams("s", &filename)) 964 | { 965 | stackError("gsc_utils_remove_file() argument is undefined or has a wrong type"); 966 | stackPushUndefined(); 967 | return; 968 | } 969 | 970 | stackPushInt(remove( filename )); 971 | } 972 | 973 | void gsc_utils_remotecommand() 974 | { 975 | char * sFrom; 976 | int pointerMsg; 977 | 978 | if (!stackGetParams("si", &sFrom, &pointerMsg)) 979 | { 980 | stackError("gsc_utils_remotecommand() one or more arguments is undefined or has a wrong type"); 981 | return; 982 | } 983 | 984 | netadr_t from; 985 | 986 | msg_t * msg = (msg_t *)pointerMsg; 987 | NET_StringToAdr(sFrom, &from); 988 | 989 | #if COD_VERSION == COD2_1_0 990 | int lasttime_offset = 0x0848B674; 991 | #elif COD_VERSION == COD2_1_2 992 | int lasttime_offset = 0x0849EB74; 993 | #elif COD_VERSION == COD2_1_3 994 | int lasttime_offset = 0x0849FBF4; 995 | #endif 996 | 997 | *(int *)lasttime_offset = 0; 998 | 999 | SVC_RemoteCommand(from, msg); 1000 | } 1001 | 1002 | #endif 1003 | -------------------------------------------------------------------------------- /gsc_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_UTILS_HPP_ 2 | #define _GSC_UTILS_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_utils_printf(); 8 | void gsc_utils_outofbandprint(); 9 | void gsc_utils_getarraykeys(); 10 | void gsc_utils_getAscii(); 11 | void gsc_utils_toupper(); 12 | void gsc_utils_system(); 13 | void gsc_utils_exponent(); 14 | void gsc_utils_round(); 15 | void gsc_utils_file_link(); 16 | void gsc_utils_file_unlink(); 17 | void gsc_utils_file_exists(); 18 | void gsc_utils_FS_LoadDir(); 19 | void gsc_utils_getType(); 20 | void gsc_utils_float(); 21 | void gsc_utils_ExecuteString(); 22 | void gsc_utils_sendgameservercommand(); 23 | void gsc_utils_scandir(); 24 | void gsc_G_FindConfigstringIndex(); 25 | void gsc_G_FindConfigstringIndexOriginal(); 26 | void gsc_get_configstring(); 27 | void gsc_set_configstring(); 28 | void gsc_make_localized_string(); 29 | void gsc_utils_getlasttestclientnumber(); 30 | void gsc_utils_bullethiteffect(); 31 | void gsc_utils_fopen(); 32 | void gsc_utils_fread(); 33 | void gsc_utils_fwrite(); 34 | void gsc_utils_fclose(); 35 | void gsc_utils_fsize(); 36 | void gsc_utils_ftime(); 37 | void gsc_utils_sprintf(); 38 | void gsc_utils_getsystemtime(); 39 | void gsc_utils_getserverstarttime(); 40 | void gsc_utils_getlocaltime(); 41 | void gsc_utils_sqrt(); 42 | void gsc_utils_sqrtInv(); 43 | void gsc_utils_vectorscale(); 44 | void gsc_utils_remove_file(); 45 | void gsc_utils_putchar(); 46 | void gsc_utils_remotecommand(); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /gsc_weapons.cpp: -------------------------------------------------------------------------------- 1 | #include "gsc_weapons.hpp" 2 | 3 | #if COMPILE_WEAPONS == 1 4 | 5 | qboolean isValidWeaponId(int id) 6 | { 7 | int weps = BG_GetNumWeapons(); 8 | 9 | if (id >= weps || id < 0 || weps == 0) 10 | return qfalse; 11 | 12 | return qtrue; 13 | } 14 | 15 | void gsc_weapons_getweaponmaxammo() 16 | { 17 | int id; 18 | char *name; 19 | 20 | if (stackGetParams("s", &name)) 21 | { 22 | id = BG_FindWeaponIndexForName(name); 23 | } 24 | else if ( ! stackGetParams("i", &id)) 25 | { 26 | stackError("gsc_weapons_getweaponmaxammo() argument is undefined or has a wrong type"); 27 | stackPushUndefined(); 28 | return; 29 | } 30 | 31 | if (!isValidWeaponId(id)) 32 | { 33 | stackError("gsc_weapons_getweaponmaxammo() weapon index is out of bounds"); 34 | stackPushUndefined(); 35 | return; 36 | } 37 | 38 | WeaponDef_t *weapon = BG_WeaponDefs(id); 39 | stackPushInt(weapon->iMaxAmmo); 40 | } 41 | 42 | void gsc_weapons_getweaponclipsize() 43 | { 44 | int id; 45 | char *name; 46 | 47 | if (stackGetParams("s", &name)) 48 | { 49 | id = BG_FindWeaponIndexForName(name); 50 | } 51 | else if ( ! stackGetParams("i", &id)) 52 | { 53 | stackError("gsc_weapons_getweaponclipsize() argument is undefined or has a wrong type"); 54 | stackPushUndefined(); 55 | return; 56 | } 57 | 58 | if (!isValidWeaponId(id)) 59 | { 60 | stackError("gsc_weapons_getweaponclipsize() weapon index is out of bounds"); 61 | stackPushUndefined(); 62 | return; 63 | } 64 | 65 | WeaponDef_t *weapon = BG_WeaponDefs(id); 66 | stackPushInt(weapon->iClipSize); 67 | } 68 | 69 | void gsc_weapons_getweapondamage() 70 | { 71 | int id; 72 | char *name; 73 | 74 | if (stackGetParams("s", &name)) 75 | { 76 | id = BG_FindWeaponIndexForName(name); 77 | } 78 | else if ( ! stackGetParams("i", &id)) 79 | { 80 | stackError("gsc_weapons_getweapondamage() argument is undefined or has a wrong type"); 81 | stackPushUndefined(); 82 | return; 83 | } 84 | 85 | if (!isValidWeaponId(id)) 86 | { 87 | stackError("gsc_weapons_getweapondamage() weapon index is out of bounds"); 88 | stackPushUndefined(); 89 | return; 90 | } 91 | 92 | WeaponDef_t *weapon = BG_WeaponDefs(id); 93 | stackPushInt(weapon->damage); 94 | } 95 | 96 | void gsc_weapons_getweaponmeleedamage() 97 | { 98 | int id; 99 | char *name; 100 | 101 | if (stackGetParams("s", &name)) 102 | { 103 | id = BG_FindWeaponIndexForName(name); 104 | } 105 | else if ( ! stackGetParams("i", &id)) 106 | { 107 | stackError("gsc_weapons_getweaponmeleedamage() argument is undefined or has a wrong type"); 108 | stackPushUndefined(); 109 | return; 110 | } 111 | 112 | if (!isValidWeaponId(id)) 113 | { 114 | stackError("gsc_weapons_getweaponmeleedamage() weapon index is out of bounds"); 115 | stackPushUndefined(); 116 | return; 117 | } 118 | 119 | WeaponDef_t *weapon = BG_WeaponDefs(id); 120 | stackPushInt(weapon->iMeleeDamage); 121 | } 122 | 123 | void gsc_weapons_getweaponfiretime() 124 | { 125 | int id; 126 | char *name; 127 | 128 | if (stackGetParams("s", &name)) 129 | { 130 | id = BG_FindWeaponIndexForName(name); 131 | } 132 | else if ( ! stackGetParams("i", &id)) 133 | { 134 | stackError("gsc_weapons_getweaponfiretime() argument is undefined or has a wrong type"); 135 | stackPushUndefined(); 136 | return; 137 | } 138 | 139 | if (!isValidWeaponId(id)) 140 | { 141 | stackError("gsc_weapons_getweaponfiretime() weapon index is out of bounds"); 142 | stackPushUndefined(); 143 | return; 144 | } 145 | 146 | WeaponDef_t *weapon = BG_WeaponDefs(id); 147 | stackPushInt(weapon->iFireTime); 148 | } 149 | 150 | void gsc_weapons_getweaponmeleetime() 151 | { 152 | int id; 153 | char *name; 154 | 155 | if (stackGetParams("s", &name)) 156 | { 157 | id = BG_FindWeaponIndexForName(name); 158 | } 159 | else if ( ! stackGetParams("i", &id)) 160 | { 161 | stackError("gsc_weapons_getweaponmeleetime() argument is undefined or has a wrong type"); 162 | stackPushUndefined(); 163 | return; 164 | } 165 | 166 | if (!isValidWeaponId(id)) 167 | { 168 | stackError("gsc_weapons_getweaponmeleetime() weapon index is out of bounds"); 169 | stackPushUndefined(); 170 | return; 171 | } 172 | 173 | WeaponDef_t *weapon = BG_WeaponDefs(id); 174 | stackPushInt(weapon->iMeleeTime); 175 | } 176 | 177 | void gsc_weapons_getweaponreloadtime() 178 | { 179 | int id; 180 | char *name; 181 | 182 | if (stackGetParams("s", &name)) 183 | { 184 | id = BG_FindWeaponIndexForName(name); 185 | } 186 | else if ( ! stackGetParams("i", &id)) 187 | { 188 | stackError("gsc_weapons_getweaponreloadtime() argument is undefined or has a wrong type"); 189 | stackPushUndefined(); 190 | return; 191 | } 192 | 193 | if (!isValidWeaponId(id)) 194 | { 195 | stackError("gsc_weapons_getweaponreloadtime() weapon index is out of bounds"); 196 | stackPushUndefined(); 197 | return; 198 | } 199 | 200 | WeaponDef_t *weapon = BG_WeaponDefs(id); 201 | stackPushInt(weapon->iReloadTime); 202 | } 203 | 204 | void gsc_weapons_getweaponreloademptytime() 205 | { 206 | int id; 207 | char *name; 208 | 209 | if (stackGetParams("s", &name)) 210 | { 211 | id = BG_FindWeaponIndexForName(name); 212 | } 213 | else if ( ! stackGetParams("i", &id)) 214 | { 215 | stackError("gsc_weapons_getweaponreloademptytime() argument is undefined or has a wrong type"); 216 | stackPushUndefined(); 217 | return; 218 | } 219 | 220 | if (!isValidWeaponId(id)) 221 | { 222 | stackError("gsc_weapons_getweaponreloademptytime() weapon index is out of bounds"); 223 | stackPushUndefined(); 224 | return; 225 | } 226 | 227 | WeaponDef_t *weapon = BG_WeaponDefs(id); 228 | stackPushInt(weapon->iReloadEmptyTime); 229 | } 230 | 231 | void gsc_weapons_getweaponcookable() 232 | { 233 | int id; 234 | char *name; 235 | 236 | if (stackGetParams("s", &name)) 237 | { 238 | id = BG_FindWeaponIndexForName(name); 239 | } 240 | else if ( ! stackGetParams("i", &id)) 241 | { 242 | stackError("gsc_weapons_getweaponcookable() argument is undefined or has a wrong type"); 243 | stackPushUndefined(); 244 | return; 245 | } 246 | 247 | if (!isValidWeaponId(id)) 248 | { 249 | stackError("gsc_weapons_getweaponcookable() weapon index is out of bounds"); 250 | stackPushUndefined(); 251 | return; 252 | } 253 | 254 | WeaponDef_t *weapon = BG_WeaponDefs(id); 255 | stackPushInt(weapon->bCookOffHold); 256 | } 257 | 258 | void gsc_weapons_setweapondamage() 259 | { 260 | int id; 261 | char *name; 262 | int damage; 263 | 264 | if (stackGetParams("si", &name, &damage)) 265 | { 266 | id = BG_FindWeaponIndexForName(name); 267 | } 268 | else if ( ! stackGetParams("ii", &id, &damage)) 269 | { 270 | stackError("gsc_weapons_setweapondamage() one or more arguments is undefined or has a wrong type"); 271 | stackPushUndefined(); 272 | return; 273 | } 274 | 275 | if (!isValidWeaponId(id)) 276 | { 277 | stackError("gsc_weapons_setweapondamage() weapon index is out of bounds"); 278 | stackPushUndefined(); 279 | return; 280 | } 281 | 282 | WeaponDef_t *weapon = BG_WeaponDefs(id); 283 | weapon->damage = damage; 284 | 285 | stackPushBool(qtrue); 286 | } 287 | 288 | void gsc_weapons_setweaponmaxammo() 289 | { 290 | int id; 291 | char *name; 292 | int ammo; 293 | 294 | if (stackGetParams("si", &name, &ammo)) 295 | { 296 | id = BG_FindWeaponIndexForName(name); 297 | } 298 | else if ( ! stackGetParams("ii", &id, &ammo)) 299 | { 300 | stackError("gsc_weapons_setweaponmaxammo() one or more arguments is undefined or has a wrong type"); 301 | stackPushUndefined(); 302 | return; 303 | } 304 | 305 | if (!isValidWeaponId(id)) 306 | { 307 | stackError("gsc_weapons_setweaponmaxammo() weapon index is out of bounds"); 308 | stackPushUndefined(); 309 | return; 310 | } 311 | 312 | WeaponDef_t *weapon = BG_WeaponDefs(id); 313 | weapon->iMaxAmmo = ammo; 314 | 315 | stackPushBool(qtrue); 316 | } 317 | 318 | void gsc_weapons_setweaponclipsize() 319 | { 320 | int id; 321 | char *name; 322 | int clipSize; 323 | 324 | if (stackGetParams("si", &name, &clipSize)) 325 | { 326 | id = BG_FindWeaponIndexForName(name); 327 | } 328 | else if ( ! stackGetParams("ii", &id, &clipSize)) 329 | { 330 | stackError("gsc_weapons_setweaponclipsize() one or more arguments is undefined or has a wrong type"); 331 | stackPushUndefined(); 332 | return; 333 | } 334 | 335 | if (!isValidWeaponId(id)) 336 | { 337 | stackError("gsc_weapons_setweaponclipsize() weapon index is out of bounds"); 338 | stackPushUndefined(); 339 | return; 340 | } 341 | 342 | WeaponDef_t *weapon = BG_WeaponDefs(id); 343 | weapon->iClipSize = clipSize; 344 | 345 | stackPushBool(qtrue); 346 | } 347 | 348 | void gsc_weapons_setweaponmeleedamage() 349 | { 350 | int id; 351 | char *name; 352 | int damage; 353 | 354 | if (stackGetParams("si", &name, &damage)) 355 | { 356 | id = BG_FindWeaponIndexForName(name); 357 | } 358 | else if ( ! stackGetParams("ii", &id, &damage)) 359 | { 360 | stackError("gsc_weapons_setweaponmeleedamage() one or more arguments is undefined or has a wrong type"); 361 | stackPushUndefined(); 362 | return; 363 | } 364 | 365 | if (!isValidWeaponId(id)) 366 | { 367 | stackError("gsc_weapons_setweaponmeleedamage() weapon index is out of bounds"); 368 | stackPushUndefined(); 369 | return; 370 | } 371 | 372 | WeaponDef_t *weapon = BG_WeaponDefs(id); 373 | weapon->iMeleeDamage = damage; 374 | 375 | stackPushBool(qtrue); 376 | } 377 | 378 | void gsc_weapons_setweaponfiretime() 379 | { 380 | int id; 381 | char *name; 382 | int time; 383 | 384 | if (stackGetParams("si", &name, &time)) 385 | { 386 | id = BG_FindWeaponIndexForName(name); 387 | } 388 | else if ( ! stackGetParams("ii", &id, &time)) 389 | { 390 | stackError("gsc_weapons_setweaponfiretime() one or more arguments is undefined or has a wrong type"); 391 | stackPushUndefined(); 392 | return; 393 | } 394 | 395 | if (!isValidWeaponId(id)) 396 | { 397 | stackError("gsc_weapons_setweaponfiretime() weapon index is out of bounds"); 398 | stackPushUndefined(); 399 | return; 400 | } 401 | 402 | WeaponDef_t *weapon = BG_WeaponDefs(id); 403 | weapon->iFireTime = time; 404 | 405 | stackPushBool(qtrue); 406 | } 407 | 408 | void gsc_weapons_setweaponmeleetime() 409 | { 410 | int id; 411 | char *name; 412 | int time; 413 | 414 | if (stackGetParams("si", &name, &time)) 415 | { 416 | id = BG_FindWeaponIndexForName(name); 417 | } 418 | else if ( ! stackGetParams("ii", &id, &time)) 419 | { 420 | stackError("gsc_weapons_setweaponmeleetime() one or more arguments is undefined or has a wrong type"); 421 | stackPushUndefined(); 422 | return; 423 | } 424 | 425 | if (!isValidWeaponId(id)) 426 | { 427 | stackError("gsc_weapons_setweaponmeleetime() weapon index is out of bounds"); 428 | stackPushUndefined(); 429 | return; 430 | } 431 | 432 | WeaponDef_t *weapon = BG_WeaponDefs(id); 433 | weapon->iMeleeTime = time; 434 | 435 | stackPushBool(qtrue); 436 | } 437 | 438 | void gsc_weapons_setweaponreloadtime() 439 | { 440 | int id; 441 | char *name; 442 | int time; 443 | 444 | if (stackGetParams("si", &name, &time)) 445 | { 446 | id = BG_FindWeaponIndexForName(name); 447 | } 448 | else if ( ! stackGetParams("ii", &id, &time)) 449 | { 450 | stackError("gsc_weapons_setweaponreloadtime() one or more arguments is undefined or has a wrong type"); 451 | stackPushUndefined(); 452 | return; 453 | } 454 | 455 | if (!isValidWeaponId(id)) 456 | { 457 | stackError("gsc_weapons_setweaponreloadtime() weapon index is out of bounds"); 458 | stackPushUndefined(); 459 | return; 460 | } 461 | 462 | WeaponDef_t *weapon = BG_WeaponDefs(id); 463 | weapon->iReloadTime = time; 464 | 465 | stackPushBool(qtrue); 466 | } 467 | 468 | void gsc_weapons_setweaponreloademptytime() 469 | { 470 | int id; 471 | char *name; 472 | int time; 473 | 474 | if (stackGetParams("si", &name, &time)) 475 | { 476 | id = BG_FindWeaponIndexForName(name); 477 | } 478 | else if ( ! stackGetParams("ii", &id, &time)) 479 | { 480 | stackError("gsc_weapons_setweaponreloademptytime() one or more arguments is undefined or has a wrong type"); 481 | stackPushUndefined(); 482 | return; 483 | } 484 | 485 | if (!isValidWeaponId(id)) 486 | { 487 | stackError("gsc_weapons_setweaponreloademptytime() weapon index is out of bounds"); 488 | stackPushUndefined(); 489 | return; 490 | } 491 | 492 | WeaponDef_t *weapon = BG_WeaponDefs(id); 493 | weapon->iReloadEmptyTime = time; 494 | 495 | stackPushBool(qtrue); 496 | } 497 | 498 | void gsc_weapons_setweaponcookable() 499 | { 500 | int id; 501 | char *name; 502 | int cookable; 503 | 504 | if (stackGetParams("si", &name, &time)) 505 | { 506 | id = BG_FindWeaponIndexForName(name); 507 | } 508 | else if ( ! stackGetParams("ii", &id, &cookable)) 509 | { 510 | stackError("gsc_weapons_setweaponcookable() one or more arguments is undefined or has a wrong type"); 511 | stackPushUndefined(); 512 | return; 513 | } 514 | 515 | if (!isValidWeaponId(id)) 516 | { 517 | stackError("gsc_weapons_setweaponcookable() weapon index is out of bounds"); 518 | stackPushUndefined(); 519 | return; 520 | } 521 | 522 | WeaponDef_t *weapon = BG_WeaponDefs(id); 523 | weapon->bCookOffHold = cookable; 524 | 525 | stackPushBool(qtrue); 526 | } 527 | 528 | const char *hitlocs[] = { "none", "helmet", "head", "neck", "torso_upper", "torso_lower", "right_arm_upper", "right_arm_lower", "right_hand", "left_arm_upper", "left_arm_lower", "left_hand", "right_leg_upper", "right_leg_lower", "right_foot", "left_leg_upper", "left_leg_lower", "left_foot", "gun" }; 529 | int getHitLocOffset(const char *hitloc) 530 | { 531 | int offset = 0; 532 | 533 | for (int i = 0; i < int( sizeof(hitlocs) / sizeof(hitlocs[0]) ); i++) 534 | { 535 | if (strcmp(hitlocs[i], hitloc) == 0) 536 | { 537 | offset = i; 538 | break; 539 | } 540 | } 541 | 542 | return offset; 543 | } 544 | 545 | void gsc_weapons_getweaponhitlocmultiplier() 546 | { 547 | int id; 548 | char *name; 549 | char *hitloc; 550 | 551 | if (stackGetParams("ss", &name, &hitloc)) 552 | { 553 | id = BG_FindWeaponIndexForName(name); 554 | } 555 | else if ( ! stackGetParams("is", &id, &hitloc)) 556 | { 557 | stackError("gsc_weapons_getweaponhitlocmultiplier() one or more arguments is undefined or has a wrong type"); 558 | stackPushUndefined(); 559 | return; 560 | } 561 | 562 | if (!isValidWeaponId(id)) 563 | { 564 | stackError("gsc_weapons_getweaponhitlocmultiplier() weapon index is out of bounds"); 565 | stackPushUndefined(); 566 | return; 567 | } 568 | 569 | WeaponDef_t *weapon = BG_WeaponDefs(id); 570 | int offset = getHitLocOffset(hitloc); 571 | 572 | stackPushFloat(weapon->locationDamageMultipliers[offset]); 573 | } 574 | 575 | void gsc_weapons_setweaponhitlocmultiplier() 576 | { 577 | int id; 578 | char *name; 579 | float multiplier; 580 | char* hitloc; 581 | 582 | if (stackGetParams("ssf", &name, &hitloc, &multiplier)) 583 | { 584 | id = BG_FindWeaponIndexForName(name); 585 | } 586 | else if ( ! stackGetParams("isf", &id, &hitloc, &multiplier)) 587 | { 588 | stackError("gsc_weapons_setweaponhitlocmultiplier() one or more arguments is undefined or has a wrong type"); 589 | stackPushUndefined(); 590 | return; 591 | } 592 | 593 | if (!isValidWeaponId(id)) 594 | { 595 | stackError("gsc_weapons_setweaponhitlocmultiplier() weapon index is out of bounds"); 596 | stackPushUndefined(); 597 | return; 598 | } 599 | 600 | WeaponDef_t *weapon = BG_WeaponDefs(id); 601 | int offset = getHitLocOffset(hitloc); 602 | 603 | weapon->locationDamageMultipliers[offset] = multiplier; 604 | stackPushBool(qtrue); 605 | } 606 | 607 | void gsc_weapons_getloadedweapons() 608 | { 609 | int numweapons = BG_GetNumWeapons(); 610 | 611 | stackPushArray(); 612 | 613 | for (int i = 0; i < numweapons; i++) 614 | { 615 | WeaponDef_t *weapon = BG_WeaponDefs(i); 616 | stackPushString(weapon->szInternalName); 617 | stackPushArrayLast(); 618 | } 619 | } 620 | 621 | #endif 622 | -------------------------------------------------------------------------------- /gsc_weapons.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_WEAPONS_HPP_ 2 | #define _GSC_WEAPONS_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void gsc_weapons_getweaponmaxammo(); 8 | void gsc_weapons_setweaponmaxammo(); 9 | void gsc_weapons_getweaponclipsize(); 10 | void gsc_weapons_setweaponclipsize(); 11 | void gsc_weapons_getweapondamage(); 12 | void gsc_weapons_setweapondamage(); 13 | void gsc_weapons_getweaponmeleedamage(); 14 | void gsc_weapons_setweaponmeleedamage(); 15 | void gsc_weapons_getweaponfiretime(); 16 | void gsc_weapons_setweaponfiretime(); 17 | void gsc_weapons_getweaponmeleetime(); 18 | void gsc_weapons_setweaponmeleetime(); 19 | void gsc_weapons_getweaponreloadtime(); 20 | void gsc_weapons_setweaponreloadtime(); 21 | void gsc_weapons_getweaponreloademptytime(); 22 | void gsc_weapons_setweaponreloademptytime(); 23 | void gsc_weapons_getweaponcookable(); 24 | void gsc_weapons_setweaponcookable(); 25 | void gsc_weapons_getweaponhitlocmultiplier(); 26 | void gsc_weapons_setweaponhitlocmultiplier(); 27 | void gsc_weapons_getloadedweapons(); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /jump.cpp: -------------------------------------------------------------------------------- 1 | #include "jump.hpp" 2 | 3 | #if COMPILE_JUMP == 1 4 | 5 | cvar_t *jump_height; 6 | cvar_t *jump_stepSize; 7 | cvar_t *jump_slowdownEnable; 8 | cvar_t *jump_ladderPushVel; 9 | cvar_t *jump_spreadAdd; 10 | 11 | #define JUMP_LAND_SLOWDOWN_TIME 1800 12 | 13 | bool player_jump_height_enabled[MAX_CLIENTS] = {0}; 14 | float player_jump_height[MAX_CLIENTS] = {0}; 15 | bool player_jump_slowdownenable_enabled[MAX_CLIENTS] = {0}; 16 | bool player_jump_slowdownenable[MAX_CLIENTS] = {0}; 17 | 18 | int playerstateToClientNum(playerState_t* ps) 19 | { 20 | return (int)(((byte *)ps - (byte *)sv.gameClients) / sv.gameClientSize); 21 | } 22 | 23 | float getJumpHeight(playerState_t* ps) 24 | { 25 | int clientid = playerstateToClientNum(ps); 26 | if(player_jump_height_enabled[clientid]) 27 | return player_jump_height[clientid]; 28 | return jump_height->floatval; 29 | } 30 | 31 | bool getJumpSlowdownEnable(playerState_t* ps) 32 | { 33 | int clientid = playerstateToClientNum(ps); 34 | if(player_jump_slowdownenable_enabled[clientid]) 35 | return player_jump_slowdownenable[clientid]; 36 | return jump_slowdownEnable->floatval; 37 | } 38 | 39 | float Jump_CalcHeight(playerState_t* ps ) 40 | { 41 | float val; 42 | float newdiv; 43 | float jumpHeight = getJumpHeight(ps);//jump_height->floatval; 44 | 45 | val = jumpHeight; 46 | val = (val + val) * ps->gravity; 47 | 48 | if(ps->pm_flags & PMF_JUMPING && ps->pm_time <= JUMP_LAND_SLOWDOWN_TIME ) 49 | { 50 | if(getJumpSlowdownEnable(ps))//jump_slowdownEnable->boolean) 51 | { 52 | 53 | if(ps->pm_time > 1699) 54 | { 55 | 56 | newdiv = 2.5; 57 | 58 | } 59 | else 60 | { 61 | newdiv = ps->pm_time * (float)1.5 * (float)0.00058823527 + (float)1.0; 62 | } 63 | 64 | } 65 | else 66 | { 67 | newdiv = 1.0; 68 | } 69 | val = val / newdiv; 70 | } 71 | 72 | return val; 73 | } 74 | 75 | double Jump_GetLandFactor(playerState_s *ps) 76 | { 77 | if ( !getJumpSlowdownEnable(ps))//jump_slowdownEnable->boolean ) 78 | { 79 | return 1.0; 80 | } 81 | if ( ps->pm_time < 1700 ) 82 | { 83 | return (double)ps->pm_time * 1.5 * 0.00058823527 + 1.0; 84 | } 85 | return 2.5; 86 | } 87 | 88 | void Jump_AddSurfaceEvent(playerState_s *ps, pml_t *pml) 89 | { 90 | int surfType; 91 | 92 | if ( ps->pm_flags & PMF_LADDER ) 93 | { 94 | BG_AddPredictableEventToPlayerstate(76, 0x15u, ps); 95 | } 96 | else 97 | { 98 | surfType = PM_GroundSurfaceType(pml); 99 | if ( surfType ) 100 | { 101 | BG_AddPredictableEventToPlayerstate(76, surfType, ps); 102 | } 103 | } 104 | } 105 | 106 | void Jump_PushOffLadder(playerState_s *ps, pml_t *pml) 107 | { 108 | vec3_t flatForward; 109 | vec3_t pushOffDir; 110 | float dot; 111 | 112 | ps->velocity[2] = ps->velocity[2] * 0.75; 113 | flatForward[0] = pml->forward[0]; 114 | flatForward[1] = pml->forward[1]; 115 | flatForward[2] = 0.0; 116 | Vec3Normalize(flatForward); 117 | dot = DotProduct(ps->vLadderVec, pml->forward); 118 | if ( dot >= 0.0 ) 119 | { 120 | VectorCopy(flatForward, pushOffDir); 121 | } 122 | else 123 | { 124 | dot = DotProduct(ps->vLadderVec, flatForward); 125 | VectorMA(flatForward, -2.0 * dot, ps->vLadderVec, pushOffDir); 126 | Vec3Normalize(pushOffDir); 127 | } 128 | ps->velocity[0] = jump_ladderPushVel->floatval * pushOffDir[0]; 129 | ps->velocity[1] = jump_ladderPushVel->floatval * pushOffDir[1]; 130 | ps->pm_flags &= 0xFFFFFFDF; 131 | } 132 | 133 | void Jump_Start(pmove_t *pm, pml_t *pml, float height) 134 | { 135 | float factor; 136 | float velocitySqrd; 137 | playerState_s *ps; 138 | 139 | ps = pm->ps; 140 | 141 | 142 | velocitySqrd = (float)(height * 2.0) * (float)ps->gravity; 143 | if ( ps->pm_flags & PMF_JUMPING ) 144 | { 145 | if ( ps->pm_time <= JUMP_LAND_SLOWDOWN_TIME ) 146 | { 147 | factor = Jump_GetLandFactor(ps); 148 | velocitySqrd = velocitySqrd / factor; 149 | } 150 | } 151 | pml->groundPlane = 0; 152 | pml->almostGroundPlane = 0; 153 | pml->walking = 0; 154 | ps->groundEntityNum = 1023; 155 | ps->jumpTime = pm->cmd.serverTime; 156 | ps->jumpOriginZ = ps->origin[2]; 157 | ps->velocity[2] = sqrtf(velocitySqrd); 158 | ps->pm_flags &= 0xFFFFFE7F; 159 | ps->pm_flags |= PMF_JUMPING; 160 | ps->pm_time = 0; 161 | ps->aimSpreadScale = ps->aimSpreadScale + jump_spreadAdd->floatval; 162 | if ( ps->aimSpreadScale > 255.0 ) 163 | { 164 | ps->aimSpreadScale = 255.0; 165 | } 166 | } 167 | 168 | void Jump_ClearState(playerState_s *ps) 169 | { 170 | ps->pm_flags &= ~PMF_JUMPING; 171 | ps->jumpOriginZ = 0.0; 172 | } 173 | 174 | double Jump_ReduceFriction(playerState_s *ps) 175 | { 176 | float control; 177 | 178 | if ( ps->pm_time > JUMP_LAND_SLOWDOWN_TIME ) 179 | { 180 | Jump_ClearState(ps); 181 | control = 1.0; 182 | } 183 | else 184 | { 185 | control = Jump_GetLandFactor(ps); 186 | } 187 | return control; 188 | } 189 | 190 | void Jump_ClampVelocity(playerState_t* ps, vec3_t vec) 191 | { 192 | float comp; 193 | float newZVelocity; 194 | 195 | if(ps->origin[2] - vec[2] > 0) 196 | { 197 | 198 | float jumpHeight = getJumpHeight(ps);//jump_height->floatval; 199 | 200 | comp = ps->jumpOriginZ + jumpHeight - ps->origin[2]; 201 | 202 | if(comp >= (float)0.1) 203 | { 204 | 205 | newZVelocity = sqrtf( (comp + comp) * (float)ps->gravity); 206 | 207 | if(ps->velocity[2] > newZVelocity ) 208 | { 209 | ps->velocity[2] = newZVelocity; 210 | } 211 | 212 | } 213 | else 214 | { 215 | ps->velocity[2] = 0; 216 | return; 217 | } 218 | 219 | } 220 | } 221 | 222 | qboolean Jump_IsPlayerAboveMax(playerState_t* ps) 223 | { 224 | float jumpHeight = getJumpHeight(ps);//jump_height->floatval; 225 | 226 | if(ps->origin[2] >= ps->jumpOriginZ + jumpHeight ) 227 | return qtrue; 228 | else 229 | return qfalse; 230 | 231 | } 232 | 233 | qboolean Jump_GetStepHeight(playerState_t* ps, const vec3_t vec1, float* val2) 234 | { 235 | float jumpHeight = getJumpHeight(ps);//jump_height->floatval; 236 | 237 | if(vec1[2] > ps->jumpOriginZ + jumpHeight) 238 | return qfalse; 239 | 240 | *val2 = jump_stepSize->floatval; 241 | 242 | if(vec1[2] + jump_stepSize->floatval > ps->jumpOriginZ + jumpHeight) 243 | *val2 = ps->jumpOriginZ + jumpHeight - vec1[2]; 244 | 245 | return qtrue; 246 | 247 | } 248 | 249 | qboolean Jump_Check(pmove_t *pm, pml_t *pml) 250 | { 251 | playerState_s *ps; 252 | 253 | ps = pm->ps; 254 | 255 | if ( ps->pm_flags & 0x1000 ) 256 | { 257 | return qfalse; 258 | } 259 | if ( pm->cmd.serverTime - ps->jumpTime < 500 ) 260 | { 261 | return qfalse; 262 | } 263 | if ( ps->pm_flags & 0x400 ) 264 | { 265 | return qfalse; 266 | } 267 | if ( ps->pm_flags & 4 ) 268 | { 269 | return qfalse; 270 | } 271 | if ( ps->pm_type > 5 ) 272 | { 273 | return qfalse; 274 | } 275 | if ( PM_GetEffectiveStance(ps) && ps->groundEntityNum != 1023 ) 276 | { 277 | return qfalse; 278 | } 279 | if ( !(pm->cmd.buttons & 0x400) ) 280 | { 281 | return qfalse; 282 | } 283 | if ( pm->oldcmd.buttons & 0x400 ) 284 | { 285 | pm->cmd.buttons &= 0xFFFFFBFF; 286 | return qfalse; 287 | } 288 | Jump_Start(pm, pml, getJumpHeight(ps));//jump_height->floatval); 289 | Jump_AddSurfaceEvent(ps, pml); 290 | if ( ps->pm_flags & PMF_LADDER ) 291 | { 292 | Jump_PushOffLadder(ps, pml); 293 | } 294 | if ( pm->cmd.forwardmove < 0 ) 295 | { 296 | BG_AnimScriptEvent(ps, ANIM_ET_JUMPBK, 0, 1); 297 | } 298 | else 299 | { 300 | BG_AnimScriptEvent(ps, ANIM_ET_JUMP, 0, 1); 301 | } 302 | return qtrue; 303 | } 304 | 305 | void Jump_ApplySlowdown(playerState_s *ps) 306 | { 307 | float scale; 308 | 309 | scale = 1.0; 310 | if ( ps->pm_time <= JUMP_LAND_SLOWDOWN_TIME ) 311 | { 312 | if ( !ps->pm_time ) 313 | { 314 | if ( (float)(ps->jumpOriginZ + 18.0) <= ps->origin[2] ) 315 | { 316 | ps->pm_time = 1200; 317 | scale = 0.5; 318 | } 319 | else 320 | { 321 | ps->pm_time = JUMP_LAND_SLOWDOWN_TIME; 322 | scale = 0.64999998; 323 | } 324 | } 325 | } 326 | else 327 | { 328 | Jump_ClearState(ps); 329 | scale = 0.64999998; 330 | } 331 | if ( getJumpSlowdownEnable(ps))//jump_slowdownEnable->boolean ) 332 | { 333 | VectorScale(ps->velocity, scale, ps->velocity); 334 | } 335 | } 336 | 337 | void Jump_ActivateSlowdown(playerState_s *ps) 338 | { 339 | if ( !ps->pm_time ) 340 | { 341 | ps->pm_flags |= PMF_JUMPING; 342 | ps->pm_time = JUMP_LAND_SLOWDOWN_TIME; 343 | } 344 | } 345 | 346 | void Jump_RegisterDvars() 347 | { 348 | jump_height = Cvar_RegisterFloat("jump_height", 39.0, 0.0, 128.0, CVAR_CHEAT | CVAR_SYSTEMINFO); 349 | jump_stepSize = Cvar_RegisterFloat("jump_stepSize", 18.0, 0.0, 64.0, CVAR_CHEAT | CVAR_SYSTEMINFO); 350 | jump_slowdownEnable = Cvar_RegisterBool("jump_slowdownEnable", qtrue, CVAR_CHEAT | CVAR_SYSTEMINFO); 351 | jump_ladderPushVel = Cvar_RegisterFloat("jump_ladderPushVel", 128.0, 0.0, 1024.0, CVAR_CHEAT | CVAR_SYSTEMINFO); 352 | jump_spreadAdd = Cvar_RegisterFloat("jump_spreadAdd", 64.0, 0.0, 512.0, CVAR_CHEAT | CVAR_SYSTEMINFO); 353 | } 354 | 355 | #endif 356 | -------------------------------------------------------------------------------- /jump.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _GSC_JUMP_HPP_ 2 | #define _GSC_JUMP_HPP_ 3 | 4 | /* gsc functions */ 5 | #include "gsc.hpp" 6 | 7 | void Jump_ClearState(playerState_s *ps); 8 | double Jump_ReduceFriction(playerState_s *ps); 9 | void Jump_ClampVelocity(playerState_t* ps, vec3_t vec); 10 | qboolean Jump_IsPlayerAboveMax(playerState_t* ps); 11 | qboolean Jump_GetStepHeight(playerState_t* ps, const vec3_t vec1, float* val2); 12 | qboolean Jump_Check(pmove_t *pm, pml_t *pml); 13 | void Jump_ApplySlowdown(playerState_s *ps); 14 | void Jump_ActivateSlowdown(playerState_s *ps); 15 | void Jump_RegisterDvars(); 16 | 17 | #endif 18 | --------------------------------------------------------------------------------