mirror of
				https://github.com/JezuzLizard/T4SP-Server-Plugin.git
				synced 2025-10-31 09:46:58 +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, '/'); | ||||||
| 			{ |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			constexpr static std::array bad_strings { R"(..)", R"(../)", R"(..\)" }; | 			for (const auto& tok : toks) | ||||||
| 			for (auto i = 0u; i < bad_strings.size(); i++) |  | ||||||
| 			{ | 			{ | ||||||
| 				if (fpath.find(bad_strings[i]) != std::string::npos) | 				if (tok == "." || tok == "..") | ||||||
|  | 				{ | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (tok.find(":") != 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