mirror of
https://github.com/JezuzLizard/T4SP-Server-Plugin.git
synced 2025-07-03 09:41:49 +00:00
Compare commits
41 Commits
v1.0.0
...
a3a7b8847c
Author | SHA1 | Date | |
---|---|---|---|
a3a7b8847c | |||
7fccea636f | |||
38a860e4ce | |||
3995bed200 | |||
3502a70933 | |||
1a33de617d | |||
59e57d05f7 | |||
23f5c28c29 | |||
0e29d35407 | |||
a756ab6cc0 | |||
c15f3c21d5 | |||
5a944f8711 | |||
e0728eb375 | |||
bafc637be8 | |||
7da012fdf3 | |||
d9c3b7cab5 | |||
8a36e02fdd | |||
944bab5e5c | |||
8ca8002067 | |||
afc01a05e3 | |||
8cb282da97 | |||
0327434187 | |||
b3b693a56e | |||
347033f424 | |||
4c78d6fe41 | |||
33b6006a34 | |||
98b2c3f4d6 | |||
beb90edc3d | |||
df9ef00a64 | |||
1f0717edef | |||
7a82be782d | |||
f0c95340bf | |||
4843c61e2e | |||
b79b776f63 | |||
d1a0277861 | |||
4963a9180a | |||
3bff917ce3 | |||
d6a6a096fd | |||
c147f3fbe2 | |||
7da463ccd3 | |||
7503e8988b |
18
README.md
18
README.md
@ -58,8 +58,8 @@ All files will be closed upon GSC restart (map_restart or fast_restart or missio
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* `<string> FS_ReadLine(<filehandle int>)` Reads a line from the file pointed by the filehandle, removes the newline char. Returns `undefined` when nothing is left to read. Will not read more than 8192 characters at once. Filehandle must be opened for reading.
|
* `<string> FS_ReadLine(<filehandle int>)` Reads a line from the file pointed by the filehandle, removes the newline char. Returns `undefined` when nothing is left to read. Will not read more than 65536 characters at once. Filehandle must be opened for reading.
|
||||||
* `<string> FS_Read(<filehandle int>, <bytes int>(optional))` Reads number of bytes from the file. If bytes is `undefined`, reads the entire file. No more than 8192 characters will be read at once. Returns `undefined` if there are nothing left to read.
|
* `<string> FS_Read(<filehandle int>, <bytes int>(optional))` Reads number of bytes from the file. If bytes is `undefined`, reads the entire file. No more than 65536 characters will be read at once. Returns `undefined` if there are nothing left to read.
|
||||||
```gsc
|
```gsc
|
||||||
// open the file for reading
|
// open the file for reading
|
||||||
|
|
||||||
@ -89,6 +89,20 @@ All files will be closed upon GSC restart (map_restart or fast_restart or missio
|
|||||||
// close the file
|
// close the file
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* `<array of strings> FS_ListFiles(<folder string>)` Returns a list of files inside of the folder given.
|
||||||
|
```gsc
|
||||||
|
folder = "testfolder/";
|
||||||
|
files = FS_ListFiles(folder);
|
||||||
|
|
||||||
|
for (i = 0; i < files.size; i++)
|
||||||
|
{
|
||||||
|
filename = files[i];
|
||||||
|
|
||||||
|
// do something with the filename
|
||||||
|
filepath = folder + filename;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
Move the `t4sp-server-plugin.dll` to `%LOCALAPPDATA%\Plutonium\storage\t4\plugins\`, the plugin will be loaded when you start up a dedicated server for Plutonium T4SP.
|
Move the `t4sp-server-plugin.dll` to `%LOCALAPPDATA%\Plutonium\storage\t4\plugins\`, the plugin will be loaded when you start up a dedicated server for Plutonium T4SP.
|
||||||
|
|
||||||
|
2
deps/GSL
vendored
2
deps/GSL
vendored
Submodule deps/GSL updated: 43d60c5e38...e64c97fc2c
2
deps/asmjit
vendored
2
deps/asmjit
vendored
Submodule deps/asmjit updated: f1ea8a46c3...416f735696
2
deps/curl
vendored
2
deps/curl
vendored
Submodule deps/curl updated: 4528690cd5...78a1814b33
2
deps/json
vendored
2
deps/json
vendored
Submodule deps/json updated: 546370c9e7...a259ecc51e
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
Submodule deps/libtomcrypt updated: b96e96cf8b...7e863d2142
2
deps/libtommath
vendored
2
deps/libtommath
vendored
Submodule deps/libtommath updated: 7f96509df1...8314bde5e5
2
deps/minhook
vendored
2
deps/minhook
vendored
Submodule deps/minhook updated: 49d03ad118...f5485b8454
2
deps/zlib
vendored
2
deps/zlib
vendored
Submodule deps/zlib updated: 04f42ceca4...643e17b749
@ -67,11 +67,18 @@ namespace codsrc
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
for ( len = refString->u.s.byteLen - 1;
|
if (!refString->u.s.byteLen)
|
||||||
refString->str[len];
|
|
||||||
len += 256 )
|
|
||||||
{
|
{
|
||||||
;
|
len = 256 - 1; //Bugfix for 256 % 256 = 0 or 512 % 256 = 0 or... Just promote it to 256
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = refString->u.s.byteLen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (refString->str[len])
|
||||||
|
{
|
||||||
|
len += 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
@ -10,6 +10,7 @@ namespace fileio
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static constexpr size_t max_fhs = 10;
|
static constexpr size_t max_fhs = 10;
|
||||||
|
static constexpr size_t max_gsc_string = 0x10000 - 1;
|
||||||
|
|
||||||
enum class scr_fh_type_e
|
enum class scr_fh_type_e
|
||||||
{
|
{
|
||||||
@ -33,15 +34,16 @@ namespace fileio
|
|||||||
|
|
||||||
bool validate_scr_path(const std::string& fpath)
|
bool validate_scr_path(const std::string& fpath)
|
||||||
{
|
{
|
||||||
if (fpath.empty())
|
auto toks = utils::string::split(fpath, '/');
|
||||||
|
|
||||||
|
for (const auto& tok : toks)
|
||||||
|
{
|
||||||
|
if (tok == "." || tok == "..")
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static std::array bad_strings { R"(..)", R"(../)", R"(..\)" };
|
if (tok.find(":") != std::string::npos)
|
||||||
for (auto i = 0u; i < bad_strings.size(); i++)
|
|
||||||
{
|
|
||||||
if (fpath.find(bad_strings[i]) != std::string::npos)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -50,13 +52,17 @@ namespace fileio
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string build_base_path(const std::string& path)
|
std::string build_base_path(const std::string& path_)
|
||||||
{
|
{
|
||||||
|
auto path = path_;
|
||||||
|
std::replace(path.begin(), path.end(), '\\', '/');
|
||||||
|
|
||||||
if (!validate_scr_path(path))
|
if (!validate_scr_path(path))
|
||||||
{
|
{
|
||||||
game::Scr_Error(utils::string::va("Invalid path: %s", path.c_str()), game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, utils::string::va("Invalid path: %s", path_.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// its sandboxed, but what about symlinks?
|
||||||
return path.starts_with("scriptdata/") ? path : "scriptdata/" + path;
|
return path.starts_with("scriptdata/") ? path : "scriptdata/" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,18 +107,25 @@ namespace fileio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fwrite_to_file(bool append_newline)
|
int scr_get_fh()
|
||||||
{
|
{
|
||||||
auto fh = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0) - 1;
|
auto fh = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0) - 1;
|
||||||
|
|
||||||
if (fh < 0 || fh >= max_fhs)
|
if (fh < 0 || fh >= max_fhs)
|
||||||
{
|
{
|
||||||
game::Scr_Error("fs_fwrite: invalid filehandle", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "fs_fwrite: invalid filehandle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwrite_to_file(bool append_newline)
|
||||||
|
{
|
||||||
|
auto fh = scr_get_fh();
|
||||||
|
|
||||||
if (scr_fhs[fh].type != scr_fh_type_e::WRITE && scr_fhs[fh].type != scr_fh_type_e::APPEND)
|
if (scr_fhs[fh].type != scr_fh_type_e::WRITE && scr_fhs[fh].type != scr_fh_type_e::APPEND)
|
||||||
{
|
{
|
||||||
game::Scr_Error("File not opened for writing", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "File not opened for writing");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_write = game::Scr_GetString(1, game::SCRIPTINSTANCE_SERVER);
|
std::string to_write = game::Scr_GetString(1, game::SCRIPTINSTANCE_SERVER);
|
||||||
@ -169,7 +182,7 @@ namespace fileio
|
|||||||
{
|
{
|
||||||
if (scr_fd.type != scr_fh_type_e::UNUSED && scr_fd.base_path == fpath)
|
if (scr_fd.type != scr_fh_type_e::UNUSED && scr_fd.base_path == fpath)
|
||||||
{
|
{
|
||||||
game::Scr_Error("File already opened", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "File already opened");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +198,7 @@ namespace fileio
|
|||||||
|
|
||||||
if (i >= max_fhs)
|
if (i >= max_fhs)
|
||||||
{
|
{
|
||||||
game::Scr_Error("Too many files opened", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "Too many files opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check mode
|
// check mode
|
||||||
@ -239,7 +252,7 @@ namespace fileio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
game::Scr_Error(utils::string::va("Invalid mode: %s", mode), game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(1, game::SCRIPTINSTANCE_SERVER, utils::string::va("Invalid mode: %s", mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -260,16 +273,11 @@ namespace fileio
|
|||||||
|
|
||||||
gsc::function::add("fs_readline", []()
|
gsc::function::add("fs_readline", []()
|
||||||
{
|
{
|
||||||
auto fh = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0) - 1;
|
auto fh = scr_get_fh();
|
||||||
|
|
||||||
if (fh < 0 || fh >= max_fhs)
|
|
||||||
{
|
|
||||||
game::Scr_Error("Invalid filehandle", game::SCRIPTINSTANCE_SERVER, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scr_fhs[fh].type != scr_fh_type_e::READ)
|
if (scr_fhs[fh].type != scr_fh_type_e::READ)
|
||||||
{
|
{
|
||||||
game::Scr_Error("File not opened for reading", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "File not opened for reading");
|
||||||
}
|
}
|
||||||
|
|
||||||
// file is completed being read
|
// file is completed being read
|
||||||
@ -293,10 +301,10 @@ namespace fileio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_to_read > 8191)
|
if (bytes_to_read > max_gsc_string)
|
||||||
{
|
{
|
||||||
found_nl = false;
|
found_nl = false;
|
||||||
bytes_to_read = 8191;
|
bytes_to_read = max_gsc_string;
|
||||||
|
|
||||||
game::Com_PrintWarning(game::CON_CHANNEL_SCRIPT, "Line was too long in file %s, truncating\n", scr_fhs[fh].base_path.c_str());
|
game::Com_PrintWarning(game::CON_CHANNEL_SCRIPT, "Line was too long in file %s, truncating\n", scr_fhs[fh].base_path.c_str());
|
||||||
}
|
}
|
||||||
@ -318,16 +326,11 @@ namespace fileio
|
|||||||
|
|
||||||
gsc::function::add("fs_read", []()
|
gsc::function::add("fs_read", []()
|
||||||
{
|
{
|
||||||
auto fh = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0) - 1;
|
auto fh = scr_get_fh();
|
||||||
|
|
||||||
if (fh < 0 || fh >= max_fhs)
|
|
||||||
{
|
|
||||||
game::Scr_Error("Invalid filehandle", game::SCRIPTINSTANCE_SERVER, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scr_fhs[fh].type != scr_fh_type_e::READ)
|
if (scr_fhs[fh].type != scr_fh_type_e::READ)
|
||||||
{
|
{
|
||||||
game::Scr_Error("File not opened for reading", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "File not opened for reading");
|
||||||
}
|
}
|
||||||
|
|
||||||
// file is completed being read
|
// file is completed being read
|
||||||
@ -344,13 +347,13 @@ namespace fileio
|
|||||||
|
|
||||||
if (bytes_to_read <= 0)
|
if (bytes_to_read <= 0)
|
||||||
{
|
{
|
||||||
game::Scr_Error("Trying to read <1 bytes", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(1, game::SCRIPTINSTANCE_SERVER, "Trying to read <1 bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_to_read > 8191)
|
if (bytes_to_read > max_gsc_string)
|
||||||
{
|
{
|
||||||
bytes_to_read = 8191;
|
bytes_to_read = max_gsc_string;
|
||||||
|
|
||||||
game::Com_PrintWarning(game::CON_CHANNEL_SCRIPT, "Line was too long in file %s, truncating\n", scr_fhs[fh].base_path.c_str());
|
game::Com_PrintWarning(game::CON_CHANNEL_SCRIPT, "Line was too long in file %s, truncating\n", scr_fhs[fh].base_path.c_str());
|
||||||
}
|
}
|
||||||
@ -369,16 +372,11 @@ namespace fileio
|
|||||||
|
|
||||||
gsc::function::add("fs_fclose", []()
|
gsc::function::add("fs_fclose", []()
|
||||||
{
|
{
|
||||||
auto fh = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0) - 1;
|
auto fh = scr_get_fh();
|
||||||
|
|
||||||
if (fh < 0 || fh >= max_fhs)
|
|
||||||
{
|
|
||||||
game::Scr_Error("Invalid filehandle", game::SCRIPTINSTANCE_SERVER, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scr_fhs[fh].type == scr_fh_type_e::UNUSED)
|
if (scr_fhs[fh].type == scr_fh_type_e::UNUSED)
|
||||||
{
|
{
|
||||||
game::Scr_Error("File not opened", game::SCRIPTINSTANCE_SERVER, false);
|
game::Scr_ParamError(0, game::SCRIPTINSTANCE_SERVER, "File not opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
free_scr_fh(scr_fhs[fh]);
|
free_scr_fh(scr_fhs[fh]);
|
||||||
@ -400,6 +398,23 @@ namespace fileio
|
|||||||
|
|
||||||
game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 1);
|
game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gsc::function::add("fs_listfiles", []()
|
||||||
|
{
|
||||||
|
auto fpath = build_base_path(game::Scr_GetString(0, game::SCRIPTINSTANCE_SERVER));
|
||||||
|
|
||||||
|
int numfiles;
|
||||||
|
auto* files = game::FS_ListFiles(fpath.c_str(), "", game::FS_LIST_ALL, &numfiles);
|
||||||
|
|
||||||
|
game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER);
|
||||||
|
for (int i = 0; i < numfiles; i++)
|
||||||
|
{
|
||||||
|
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, files[i]);
|
||||||
|
game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::FS_FreeFileList(files);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +231,21 @@ namespace game
|
|||||||
*cmd_functions = newCmd;
|
*cmd_functions = newCmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restored
|
||||||
|
const char** FS_ListFiles(const char* path, const char* extension, FsListBehavior_e behavior, int* numfiles)
|
||||||
|
{
|
||||||
|
return FS_ListFilteredFiles(*fs_searchpaths, path, extension, nullptr, behavior, numfiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restored
|
||||||
|
void FS_FreeFileList(const char** list)
|
||||||
|
{
|
||||||
|
if ( list )
|
||||||
|
{
|
||||||
|
Hunk_UserDestroy((HunkUser*)*(list - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// restored
|
// restored
|
||||||
void Sys_EnterCriticalSection(CriticalSection critSect)
|
void Sys_EnterCriticalSection(CriticalSection critSect)
|
||||||
{
|
{
|
||||||
|
@ -78,6 +78,9 @@ namespace game
|
|||||||
void Sys_EnterCriticalSection(CriticalSection critSect);
|
void Sys_EnterCriticalSection(CriticalSection critSect);
|
||||||
void Sys_LeaveCriticalSection(CriticalSection critSect);
|
void Sys_LeaveCriticalSection(CriticalSection critSect);
|
||||||
|
|
||||||
|
const char** FS_ListFiles(const char* path, const char* extension, FsListBehavior_e behavior, int* numfiles);
|
||||||
|
void FS_FreeFileList(const char** list);
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
WEAK symbol<CRITICAL_SECTION> s_criticalSection{ 0x0, 0x2298D08 };
|
WEAK symbol<CRITICAL_SECTION> s_criticalSection{ 0x0, 0x2298D08 };
|
||||||
WEAK symbol<HunkUser*> g_DebugHunkUser{ 0x0, 0x212B2EC };
|
WEAK symbol<HunkUser*> g_DebugHunkUser{ 0x0, 0x212B2EC };
|
||||||
|
Reference in New Issue
Block a user