LuaJIT for Dedicated Server 
17 comments SUPPORTED CS2D VERSION: 1.0.1.3

Notice
This does NOT support closed-beta dedicated server as in
CS2D Dedicated Server Closed Beta. In Linux, LuaJIT is used in that closed-beta dedicated server anyway.
Description
This patches the dedicated server to use LuaJIT instead of Lua 5.1. This also allows Lua C (external) modules to be loaded without memory errors. This works for Windows and Linux (patches for macOS are welcome).
So what's better with LuaJIT? This execute your scripts faster, I mean, faster. You can also use one of the best feature in LuaJIT which is FFI. This means you can use
[LuaJIT/LuaFFI] Fix for os.clock (6) and
[LuaJIT/LuaFFI] Socket Support (4) again.
CentOS 7 Users 
Unfortunately CentOS 7 stuck with very old glibc. CentOS 7 users must compile from source and not download the prebuilt binaries from this site!
Motivation 
You may hear LuaJIT before and yes, LuaJIT was used in
CS2D Beta 0.1.2.6 but removed in
CS2D Beta 0.1.2.7 due to stability issues. I believe the instability was caused by ancient BlitzMax (or whatever CS2D uses) so this method only patches the Lua API inside the dedicated server to use LuaJIT and nothing else.
From UnrealSoftware Discord:
MikuAuahDark has written:
DC has written:
MikuAuahDark has written:
DC has written:
So, CS2DJIT is born. It provides users an option to use LuaJIT for their server.
Installation 
Windows: Extract
Linux: Extract
If your Linux VPS supports Docker, you can use
EngiN33R's Docker image which additionally support LuaRocks so you can install Lua C modules with ease.
Running 
Windows: Run
Linux: Run
Source Code
In case you think this steals stuff, it's not. You can compile it yourself if you really paranoid. Here's the source code: https://github.com/MikuAuahDark/cs2djit
Permission 
This program is licensed under MIT license. In short:
You can use this.
Modify.
Redistribute modified version under same or different license.
Hold liable. This program is provided "as-is".
Notes
This guaranteed 100% to break when new CS2D is released. Please check this file archive for up-to-date version! GitHub releases are used for archival-purpose only.
Executables only tested in Debian 10 and Windows 10.
In Windows, the LuaJIT lua51.dll is bundled along with the downloads. If you have your own compiled lua51.dll which uses same compiler as your other Lua modules, prefer that. You have to be consistent in using compilers there as mixing DLLs between different (MSVC) compilers can cause problems.
Windows Defender may flag
If you have any issues which directly related to this, please tell me.
If your script breaks after using this, please tell me in UnrealSoftware Discord server, #cs2d-scripting channel.
This only benefits server scripters. This is not a form of cheat/hack that can give players unintended/unfair advantage!
If you got LD_PRELOAD error, please see below.
Fix LD_PRELOAD Error
This is caused if your script uses
attempt to index global 'arg' (a nil value)
If you have code something like this:
Then it won't work. LuaJIT doesn't support this. Please define
Version History 
20211127
CS2D 1.0.1.3 support.
20210523
CS2D 1.0.1.2 support.
20200130
Error when starting cs2djit.sh somewhere else other than current server folder
Windows now has LuaJIT-2.1.0-beta3 DLL bundled. This DLL is compiled under MinGW. Please see above for implications!
cs2djit.sh and cs2djitwrapper.exe now pass all arguments to cs2d_dedicated/.exe.
libcs2djit.so is now compiled under Ubuntu 16.04 to improve compatibility with older distros.
20200111
Initial release.


This does NOT support closed-beta dedicated server as in




This patches the dedicated server to use LuaJIT instead of Lua 5.1. This also allows Lua C (external) modules to be loaded without memory errors. This works for Windows and Linux (patches for macOS are welcome).
So what's better with LuaJIT? This execute your scripts faster, I mean, faster. You can also use one of the best feature in LuaJIT which is FFI. This means you can use






Unfortunately CentOS 7 stuck with very old glibc. CentOS 7 users must compile from source and not download the prebuilt binaries from this site!


You may hear LuaJIT before and yes, LuaJIT was used in




From UnrealSoftware Discord:

Is it possible to have custom build of CS2D dedicated server with LuaJIT instead of Lua 5.1 as an option?

@
MikuAuahDark Last time we tried that everything exploded. Won't go through the pain of trying it again. Not worth it.


Even by adding notice that "it's unstable"?

I can't add it as an option. either broken shit or working shit. The decision has already been made.
So, CS2DJIT is born. It provides users an option to use LuaJIT for their server.


Windows: Extract
cs2djit.dll
, cs2djitwrapper.exe
, and optionally lua51.dll
(notice below!) into your CS2D server root directory, beside cs2d_dedicated.exe
Linux: Extract
cs2djit.sh
and libcs2djit.so
into your CS2D server root directory, beside cs2d_dedicated
executable. Make sure you have 32-bit LuaJIT library installed ( libluajit-5.1:i386
for Debian and its derivatives)If your Linux VPS supports Docker, you can use



Windows: Run
cs2djitwrapper.exe
in your server directory.Linux: Run
cs2djit.sh
in your CS2D server directory, example: bash cs2djit.sh


In case you think this steals stuff, it's not. You can compile it yourself if you really paranoid. Here's the source code: https://github.com/MikuAuahDark/cs2djit


This program is licensed under MIT license. In short:










cs2djitwrapper.exe
as virus or unwanted software. This maybe caused by antivirus doesn't quite like MinGW-compiled binaries. Rest assured that binaries are compiled by GitHub Actions from Debian or if you really paranoid you can compile this program yourself from source above.





This is caused if your script uses
os.execute
or io.popen
. Save this script as sys/lua/autorun/ld_preload_unset.lua
Code:
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
if not jit then return end
local ffi = require("ffi")
ffi.cdef[[
int unsetenv(const char *name);
]]
if os.getenv("LD_PRELOAD") then
ffi.C.unsetenv("LD_PRELOAD")
end
local ffi = require("ffi")
ffi.cdef[[
int unsetenv(const char *name);
]]
if os.getenv("LD_PRELOAD") then
ffi.C.unsetenv("LD_PRELOAD")
end


If you have code something like this:
Code:
1
2
3
2
3
function foo(...)
print(arg[1], arg[2], arg[3])
end
print(arg[1], arg[2], arg[3])
end
Then it won't work. LuaJIT doesn't support this. Please define
arg
yourself:Code:
1
2
3
4
2
3
4
function foo(...)
local arg = {...} -- this
print(arg[1], arg[2], arg[3])
end
local arg = {...} -- this
print(arg[1], arg[2], arg[3])
end













edited 24×, last 26.07.23 04:18:03 am

Comments
17 comments



Log in!
You need to log in to be able to write comments!Log in
@
GeoB99: Alright let me answer it one by one.
GeoB99 has written:
32768 is not arbitrary. It's highest length size for paths for unicode version of WinAPI. The reason I allocate it with
Other than that, the reason why I allocate such big amount is there's no way to get the required size of GetModuleFileNameA/W(), thus the enormous 32768 buffer size.
GeoB99 has written:
If you think about it, it actually sort of makes sense. The only part I use unicode variant is when it involves the module path & name (and CreateProcessW). Other than that I use ANSI variant.
GeoB99 has written:
Interesting. I may consider using it if it doesn't too complicated.
If you still have discussion, please open new GitHub issue instead, to not clutter our discussion in the File Archive comments.


Why do you allocate memory for the module variable? For what? You could simply declare your variable as an array with a fixed size to hold enough number of elements. E.g.:
32768 is not arbitrary. It's highest length size for paths for unicode version of WinAPI. The reason I allocate it with
malloc
so I won't blow up the stack with 64KB memory. Windows is known to have nasty limit of stack like, around 1MB. I understand that 64KB is nothing but IMO 64KB is small enough that malloc won't return NULL, and even if it does, it's handled.Other than that, the reason why I allocate such big amount is there's no way to get the required size of GetModuleFileNameA/W(), thus the enormous 32768 buffer size.

I see in your
function you use a mix of Unicode (W) and an ANSI routines. This is bad.
main()
function you use a mix of Unicode (W) and an ANSI routines. This is bad.
main()
is the only standard entry point, change my mind. Others are compiler-specific/OS-specific non-standard (WinMain counts) and are not supported in (older) MinGW. Not sure how supported tchar.h
is in MinGW, so I'd rather not take the risk.If you think about it, it actually sort of makes sense. The only part I use unicode variant is when it involves the module path & name (and CreateProcessW). Other than that I use ANSI variant.

Furthermore, for functions like swprintf() I'd rather recommend that you use the String Safe API, specifically the StringCchPrintfW() function to print out to the output. This is for the sake to avoid any potential buffer overrun.
Interesting. I may consider using it if it doesn't too complicated.
If you still have discussion, please open new GitHub issue instead, to not clutter our discussion in the File Archive comments.
Some parts of the Windows LuaJIT port code could be simplified. Chunks like this for example.
Why do you allocate memory for the module variable? For what? You could simply declare your variable as an array with a fixed size to hold enough number of elements. E.g.:
I see in your
Where
Furthermore, for functions like swprintf() I'd rather recommend that you use the String Safe API, specifically the StringCchPrintfW() function to print out to the output (BEAR IN MIND this takes the buffer size in character counts!). This is for the sake to avoid any potential buffer overrun. Check the documentation for further information.
Code:
1
2
3
4
2
3
4
/* Windows API quirks -_- */
moduleName = malloc(sizeof(wchar_t) * 32768);
if (moduleName == NULL)
return 0;
moduleName = malloc(sizeof(wchar_t) * 32768);
if (moduleName == NULL)
return 0;
Why do you allocate memory for the module variable? For what? You could simply declare your variable as an array with a fixed size to hold enough number of elements. E.g.:
Code:
1
2
3
2
3
WCHAR szModuleName[256]; // Or a macro define with a fixed size
GetModuleFileNameW(NULL, szModuleName, _countof(szModuleName));
GetModuleFileNameW(NULL, szModuleName, _countof(szModuleName));
_countof()
calculates the exact amount of elements the array can hold. Please avoid filling fixed size numbers to size parameters.I see in your
main()
function you use a mix of Unicode (W) and an ANSI routines. This is bad. You either choose to use Unicode entirely, or ANSI, or just be agnostic of what encoding you use. In the latter case, the correct way to define your function is:Code:
int _tmain(int argc, const TCHAR *argv[])
Where
TCHAR
is converted to a WCHAR if Unicode is defined, CHAR otherwise. Furthermore, for functions like swprintf() I'd rather recommend that you use the String Safe API, specifically the StringCchPrintfW() function to print out to the output (BEAR IN MIND this takes the buffer size in character counts!). This is for the sake to avoid any potential buffer overrun. Check the documentation for further information.
@
Starkkz: Exactly why I wasn't shipping lua51.dll in previous releases. Windows binaries I provide are compiled with i686-w64-mingw64 toolchain under Linux. I've updated the changelog to clear this up.


On Windows it's best to use the binaries provided at luapower.com (which is compiled with MinGW just like CS2D), other binaries could've have been compiled with Microsoft Visual C++, which might cause runtime errors.

This is awesome, actually. Lua JIT also supports goto which is amazing as well. Good job.



