forked from alterware/s1-mod
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			custom-fas
			...
			disc-read-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 25cd907a32 | |||
| 8acf4fcf8b | |||
| c99fb7c6a0 | |||
| d6c93e6966 | |||
| 84d7702ba2 | |||
| b25aeb38a5 | 
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -29,9 +29,6 @@ | |||||||
| [submodule "deps/udis86"] | [submodule "deps/udis86"] | ||||||
| 	path = deps/udis86 | 	path = deps/udis86 | ||||||
| 	url = https://github.com/vmt/udis86.git | 	url = https://github.com/vmt/udis86.git | ||||||
| [submodule "deps/WinToast"] |  | ||||||
| 	path = deps/WinToast |  | ||||||
| 	url = https://github.com/mohabouje/WinToast.git |  | ||||||
| [submodule "deps/zlib"] | [submodule "deps/zlib"] | ||||||
| 	path = deps/zlib | 	path = deps/zlib | ||||||
| 	url = https://github.com/madler/zlib.git | 	url = https://github.com/madler/zlib.git | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								deps/GSL
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/GSL
									
									
									
									
										vendored
									
									
								
							 Submodule deps/GSL updated: 3325bbd33d...466e4ebaa5
									
								
							
							
								
								
									
										1
									
								
								deps/WinToast
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								deps/WinToast
									
									
									
									
										vendored
									
									
								
							 Submodule deps/WinToast deleted from a78ce469b4
									
								
							
							
								
								
									
										2
									
								
								deps/asmjit
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/asmjit
									
									
									
									
										vendored
									
									
								
							 Submodule deps/asmjit updated: e8c8e2e48a...cecc73f297
									
								
							
							
								
								
									
										2
									
								
								deps/gsc-tool
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/gsc-tool
									
									
									
									
										vendored
									
									
								
							 Submodule deps/gsc-tool updated: 2d9781ce0c...c508e5b10f
									
								
							
							
								
								
									
										2
									
								
								deps/libtomcrypt
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/libtomcrypt
									
									
									
									
										vendored
									
									
								
							 Submodule deps/libtomcrypt updated: a6b9aff7aa...d448df1938
									
								
							
							
								
								
									
										2
									
								
								deps/minhook
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/minhook
									
									
									
									
										vendored
									
									
								
							 Submodule deps/minhook updated: c3fcafdc10...565968b285
									
								
							
							
								
								
									
										32
									
								
								deps/premake/wintoast.lua
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								deps/premake/wintoast.lua
									
									
									
									
										vendored
									
									
								
							| @@ -1,32 +0,0 @@ | |||||||
| wintoast = { |  | ||||||
| 	source = path.join(dependencies.basePath, "WinToast"), |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function wintoast.import() |  | ||||||
| 	links { "WinToast" } |  | ||||||
| 	wintoast.includes() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function wintoast.includes() |  | ||||||
| 	includedirs { |  | ||||||
| 		path.join(wintoast.source, "include"), |  | ||||||
| 	} |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function wintoast.project() |  | ||||||
| 	project "WinToast" |  | ||||||
| 		language "C++" |  | ||||||
|  |  | ||||||
| 		wintoast.includes() |  | ||||||
| 		rapidjson.import(); |  | ||||||
|  |  | ||||||
| 		files { |  | ||||||
| 			path.join(wintoast.source, "include/wintoastlib.h"), |  | ||||||
| 			path.join(wintoast.source, "src/wintoastlib.cpp"), |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		warnings "Off" |  | ||||||
| 		kind "StaticLib" |  | ||||||
| end |  | ||||||
|  |  | ||||||
| table.insert(dependencies, wintoast) |  | ||||||
							
								
								
									
										61
									
								
								src/client/component/assets/weapons.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/client/component/assets/weapons.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | #include <std_include.hpp> | ||||||
|  | #include "loader/component_loader.hpp" | ||||||
|  | #include "game/game.hpp" | ||||||
|  |  | ||||||
|  | #include "component/console.hpp" | ||||||
|  |  | ||||||
|  | #include <utils/hook.hpp> | ||||||
|  |  | ||||||
|  | namespace weapons | ||||||
|  | { | ||||||
|  | 	namespace | ||||||
|  | 	{ | ||||||
|  | 		void g_setup_level_weapon_def_stub() | ||||||
|  | 		{ | ||||||
|  | 			game::G_SetupLevelWeaponDef(); | ||||||
|  |  | ||||||
|  | 			// The count on this game seems pretty high | ||||||
|  | 			std::array<game::WeaponCompleteDef*, 2048> weapons{}; | ||||||
|  | 			const auto count = game::DB_GetAllXAssetOfType_FastFile(game::ASSET_TYPE_WEAPON, (void**)weapons.data(), static_cast<int>(weapons.max_size())); | ||||||
|  |  | ||||||
|  | 			std::sort(weapons.begin(), weapons.begin() + count, [](game::WeaponCompleteDef* weapon1, game::WeaponCompleteDef* weapon2) | ||||||
|  | 			{ | ||||||
|  | 				assert(weapon1->szInternalName); | ||||||
|  | 				assert(weapon2->szInternalName); | ||||||
|  |  | ||||||
|  | 				return std::strcmp(weapon1->szInternalName, weapon2->szInternalName) < 0; | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | #ifdef _DEBUG | ||||||
|  | 			console::info("Found %i weapons to precache\n", count); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 			for (auto i = 0; i < count; ++i) | ||||||
|  | 			{ | ||||||
|  | #ifdef _DEBUG | ||||||
|  | 				console::info("Precaching weapon \"%s\"\n", weapons[i]->szInternalName); | ||||||
|  | #endif | ||||||
|  | 				(void)game::G_GetWeaponForName(weapons[i]->szInternalName); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	class component final : public component_interface | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		void post_unpack() override | ||||||
|  | 		{ | ||||||
|  | 			if (game::environment::is_sp()) return; | ||||||
|  |  | ||||||
|  | 			// Kill Scr_PrecacheItem (We are going to do this from code) | ||||||
|  | 			utils::hook::nop(0x1403101D0, 4); | ||||||
|  | 			utils::hook::set<std::uint8_t>(0x1403101D0, 0xC3); | ||||||
|  |  | ||||||
|  | 			// Load weapons from the DB | ||||||
|  | 			utils::hook::call(0x1402F6EF4, g_setup_level_weapon_def_stub); | ||||||
|  | 			utils::hook::call(0x140307401, g_setup_level_weapon_def_stub); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | REGISTER_COMPONENT(weapons::component) | ||||||
| @@ -13,6 +13,8 @@ | |||||||
| #include <utils/hook.hpp> | #include <utils/hook.hpp> | ||||||
| #include <utils/string.hpp> | #include <utils/string.hpp> | ||||||
|  |  | ||||||
|  | #define ALLOW_CUSTOM_BOT_NAMES | ||||||
|  |  | ||||||
| namespace bots | namespace bots | ||||||
| { | { | ||||||
| 	namespace | 	namespace | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ | |||||||
|  |  | ||||||
| namespace dvar_cheats | namespace dvar_cheats | ||||||
| { | { | ||||||
| 	void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::dvar_value* value) | 	void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::DvarValue* value) | ||||||
| 	{ | 	{ | ||||||
| 		if (dvar && dvar->name == "sv_cheats"s) | 		if (dvar && dvar->name == "sv_cheats"s) | ||||||
| 		{ | 		{ | ||||||
|   | |||||||
| @@ -18,6 +18,14 @@ namespace fastfiles | |||||||
| 	{ | 	{ | ||||||
| 		utils::hook::detour db_try_load_x_file_internal_hook; | 		utils::hook::detour db_try_load_x_file_internal_hook; | ||||||
| 		utils::hook::detour db_find_x_asset_header_hook; | 		utils::hook::detour db_find_x_asset_header_hook; | ||||||
|  | 		utils::hook::detour db_read_stream_file_hook; | ||||||
|  |  | ||||||
|  | 		int db_read_stream_file_stub(int allow_abort, int finish) | ||||||
|  | 		{ | ||||||
|  | 			// always use lz4 compressor type when reading stream files | ||||||
|  | 			*game::g_compressor = game::DB_COMPRESSOR_LZX; | ||||||
|  | 			return db_read_stream_file_hook.invoke<int>(allow_abort, finish); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		void db_try_load_x_file_internal(const char* zone_name, const int flags) | 		void db_try_load_x_file_internal(const char* zone_name, const int flags) | ||||||
| 		{ | 		{ | ||||||
| @@ -137,21 +145,6 @@ namespace fastfiles | |||||||
| 			db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); | 			db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); | ||||||
| 			dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE); | 			dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE); | ||||||
|  |  | ||||||
| 			command::add("loadzone", [](const command::params& params) |  | ||||||
| 			{ |  | ||||||
| 				if (params.size() < 2) |  | ||||||
| 				{ |  | ||||||
| 					console::info("usage: loadzone <zone>\n"); |  | ||||||
| 					return; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				game::XZoneInfo info{}; |  | ||||||
| 				info.name = params.get(1); |  | ||||||
| 				info.allocFlags = 1; |  | ||||||
| 				info.freeFlags = 0; |  | ||||||
| 				game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_SYNC); |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			command::add("g_poolSizes", []() | 			command::add("g_poolSizes", []() | ||||||
| 			{ | 			{ | ||||||
| 				for (auto i = 0; i < game::ASSET_TYPE_COUNT; i++) | 				for (auto i = 0; i < game::ASSET_TYPE_COUNT; i++) | ||||||
| @@ -160,6 +153,9 @@ namespace fastfiles | |||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
|  | 			// Allow loading of mixed compressor types | ||||||
|  | 			utils::hook::nop(SELECT_VALUE(0x1401536D7, 0x140242DF7), 2); | ||||||
|  |  | ||||||
| 			reallocate_asset_pool<game::ASSET_TYPE_FONT, 48>(); | 			reallocate_asset_pool<game::ASSET_TYPE_FONT, 48>(); | ||||||
|  |  | ||||||
| 			if (!game::environment::is_sp()) | 			if (!game::environment::is_sp()) | ||||||
| @@ -170,6 +166,9 @@ namespace fastfiles | |||||||
| 				utils::hook::inject(0x14026FFAC, xmodel_pool + 8); | 				utils::hook::inject(0x14026FFAC, xmodel_pool + 8); | ||||||
| 				utils::hook::inject(0x14027463C, xmodel_pool + 8); | 				utils::hook::inject(0x14027463C, xmodel_pool + 8); | ||||||
| 				utils::hook::inject(0x140274689, xmodel_pool + 8); | 				utils::hook::inject(0x140274689, xmodel_pool + 8); | ||||||
|  |  | ||||||
|  | 				// Fix compressor type on streamed file load | ||||||
|  | 				db_read_stream_file_hook.create(0x14027AA70, db_read_stream_file_stub); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|   | |||||||
| @@ -357,12 +357,12 @@ namespace gsc | |||||||
| 				build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_maps)); | 				build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_maps)); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (dvars::com_developer_script && dvars::com_developer_script->current.enabled) | 			if (dvars::com_developer_script && dvars::com_developer_script->current.integer > 0) | ||||||
| 			{ | 			{ | ||||||
| 				build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_blocks)); | 				build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_blocks)); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			gsc_ctx->init(build, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>> | 			gsc_ctx->init(build, []([[maybe_unused]] const auto* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>> | ||||||
| 			{ | 			{ | ||||||
| 				const auto script_name = std::filesystem::path(included_path).replace_extension().string(); | 				const auto script_name = std::filesystem::path(included_path).replace_extension().string(); | ||||||
|  |  | ||||||
| @@ -434,8 +434,11 @@ namespace gsc | |||||||
| 			utils::hook::call(SELECT_VALUE(0x14031AB47, 0x1403F7317), find_script); | 			utils::hook::call(SELECT_VALUE(0x14031AB47, 0x1403F7317), find_script); | ||||||
| 			utils::hook::call(SELECT_VALUE(0x14031AB57, 0x1403F7327), db_is_x_asset_default); | 			utils::hook::call(SELECT_VALUE(0x14031AB57, 0x1403F7327), db_is_x_asset_default); | ||||||
|  |  | ||||||
|  | 			// Enable development options | ||||||
| 			dvars::com_developer = game::Dvar_RegisterInt("developer", 0, 0, 2, game::DVAR_FLAG_NONE); | 			dvars::com_developer = game::Dvar_RegisterInt("developer", 0, 0, 2, game::DVAR_FLAG_NONE); | ||||||
| 			dvars::com_developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE); | 			// Enable developer script comments: 0 disabled, 1 full developer script, 2 only dev scripts required by art/lighting tweaks. | ||||||
|  | 			// gsc-tool will only have one mode which supports both 1 and 2 dev blocks in the code simultaneously. | ||||||
|  | 			dvars::com_developer_script = game::Dvar_RegisterInt("developer_script", 0, 0, 2, game::DVAR_FLAG_NONE); | ||||||
|  |  | ||||||
| 			if (game::environment::is_sp()) | 			if (game::environment::is_sp()) | ||||||
| 			{ | 			{ | ||||||
|   | |||||||
							
								
								
									
										236
									
								
								src/client/component/mods.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								src/client/component/mods.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,236 @@ | |||||||
|  | #include <std_include.hpp> | ||||||
|  | #include "loader/component_loader.hpp" | ||||||
|  | #include "game/game.hpp" | ||||||
|  | #include "game/dvars.hpp" | ||||||
|  |  | ||||||
|  | #include "command.hpp" | ||||||
|  | #include "console.hpp" | ||||||
|  | #include "mods.hpp" | ||||||
|  |  | ||||||
|  | #include <utils/hook.hpp> | ||||||
|  | #include <utils/string.hpp> | ||||||
|  |  | ||||||
|  | namespace mods | ||||||
|  | { | ||||||
|  | 	namespace | ||||||
|  | 	{ | ||||||
|  | 		utils::hook::detour sys_create_file_hook; | ||||||
|  |  | ||||||
|  | 		void db_build_os_path_from_source(const char* zone_name, const game::FF_DIR source, const int size, char* filename) | ||||||
|  | 		{ | ||||||
|  | 			char user_map[MAX_PATH]{}; | ||||||
|  |  | ||||||
|  | 			switch (source) | ||||||
|  | 			{ | ||||||
|  | 			case game::FFD_DEFAULT: | ||||||
|  | 				(void)game::Com_sprintf(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name); | ||||||
|  | 				break; | ||||||
|  | 			case game::FFD_MOD_DIR: | ||||||
|  | 				assert(mods::is_using_mods()); | ||||||
|  |  | ||||||
|  | 				(void)game::Com_sprintf(filename, size, "%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), (*dvars::fs_gameDirVar)->current.string, zone_name); | ||||||
|  | 				break; | ||||||
|  | 			case game::FFD_USER_MAP: | ||||||
|  | 				game::I_strncpyz(user_map, zone_name, sizeof(user_map)); | ||||||
|  |  | ||||||
|  | 				(void)game::Com_sprintf(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				assert(false && "inconceivable"); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool fs_game_dir_domain_func(game::dvar_t* dvar, game::DvarValue new_value) | ||||||
|  | 		{ | ||||||
|  | 			if (*new_value.string == '\0') | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (game::I_strnicmp(new_value.string, "mods", 4) != 0) | ||||||
|  | 			{ | ||||||
|  | 				game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0); | ||||||
|  | 				console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (5 < std::strlen(new_value.string) && (new_value.string[4] == '\\' || new_value.string[4] == '/')) | ||||||
|  | 			{ | ||||||
|  | 				const auto* s1 = std::strstr(new_value.string, ".."); | ||||||
|  | 				const auto* s2 = std::strstr(new_value.string, "::"); | ||||||
|  | 				if (s1 == nullptr && s2 == nullptr) | ||||||
|  | 				{ | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0); | ||||||
|  | 				console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Invalid path specified | ||||||
|  | 			game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0); | ||||||
|  | 			console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		const auto skip_extra_zones_stub = utils::hook::assemble([](utils::hook::assembler& a) -> void | ||||||
|  | 		{ | ||||||
|  | 			const auto skip = a.newLabel(); | ||||||
|  | 			const auto original = a.newLabel(); | ||||||
|  |  | ||||||
|  | 			a.pushad64(); | ||||||
|  | 			a.test(esi, game::DB_ZONE_CUSTOM); // allocFlags | ||||||
|  | 			a.jnz(skip); | ||||||
|  |  | ||||||
|  | 			a.bind(original); | ||||||
|  | 			a.popad64(); | ||||||
|  | 			a.mov(rdx, 0x140809D40); | ||||||
|  | 			a.mov(rcx, rbp); | ||||||
|  | 			a.call(0x1406FE120); | ||||||
|  | 			a.jmp(0x140271B63); | ||||||
|  |  | ||||||
|  | 			a.bind(skip); | ||||||
|  | 			a.popad64(); | ||||||
|  | 			a.mov(r13d, game::DB_ZONE_CUSTOM); | ||||||
|  | 			a.not_(r13d); | ||||||
|  | 			a.and_(esi, r13d); | ||||||
|  | 			a.jmp(0x140271D02); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		game::Sys_File sys_create_file_stub(game::Sys_Folder folder, const char* base_filename) | ||||||
|  | 		{ | ||||||
|  | 			auto result = sys_create_file_hook.invoke<game::Sys_File>(folder, base_filename); | ||||||
|  |  | ||||||
|  | 			if (result.handle != INVALID_HANDLE_VALUE) | ||||||
|  | 			{ | ||||||
|  | 				return result; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (!is_using_mods()) | ||||||
|  | 			{ | ||||||
|  | 				return result; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// .ff extension was added previously | ||||||
|  | 			if (!std::strcmp(base_filename, "mod.ff") && mods::db_mod_file_exists()) | ||||||
|  | 			{ | ||||||
|  | 				char file_path[MAX_PATH]{}; | ||||||
|  | 				db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(file_path), file_path); | ||||||
|  | 				result.handle = game::Sys_OpenFileReliable(file_path); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void db_load_x_assets_stub(game::XZoneInfo* zone_info, unsigned int zone_count, game::DBSyncMode sync_mode) | ||||||
|  | 		{ | ||||||
|  | 			std::vector<game::XZoneInfo> zones(zone_info, zone_info + zone_count); | ||||||
|  |  | ||||||
|  | 			if (db_mod_file_exists()) | ||||||
|  | 			{ | ||||||
|  | 				zones.emplace_back("mod", game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM, 0); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			game::DB_LoadXAssets(zones.data(), static_cast<unsigned int>(zones.size()), sync_mode); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool is_using_mods() | ||||||
|  | 	{ | ||||||
|  | 		return (*dvars::fs_gameDirVar) && *(*dvars::fs_gameDirVar)->current.string; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool db_mod_file_exists() | ||||||
|  | 	{ | ||||||
|  | 		if (!*(*dvars::fs_gameDirVar)->current.string) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		char filename[MAX_PATH]{}; | ||||||
|  | 		db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(filename), filename); | ||||||
|  |  | ||||||
|  | 		if (auto zone_file = game::Sys_OpenFileReliable(filename); zone_file != INVALID_HANDLE_VALUE) | ||||||
|  | 		{ | ||||||
|  | 			::CloseHandle(zone_file); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	class component final : public component_interface | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		static_assert(sizeof(game::Sys_File) == 8); | ||||||
|  |  | ||||||
|  | 		void post_unpack() override | ||||||
|  | 		{ | ||||||
|  | 			dvars::fs_gameDirVar = reinterpret_cast<game::dvar_t**>(SELECT_VALUE(0x14A6A7D98, 0x14B20EB48)); | ||||||
|  |  | ||||||
|  | 			// Remove DVAR_INIT from fs_game | ||||||
|  | 			utils::hook::set<std::uint32_t>(SELECT_VALUE(0x14036137F + 2, 0x1404AE4CB + 2), SELECT_VALUE(game::DVAR_FLAG_NONE, game::DVAR_FLAG_SERVERINFO)); | ||||||
|  |  | ||||||
|  | 			utils::hook::inject(SELECT_VALUE(0x140361391 + 3, 0x1404AE4D6 + 3), &fs_game_dir_domain_func); | ||||||
|  |  | ||||||
|  | 			if (game::environment::is_sp()) | ||||||
|  | 			{ | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			utils::hook::nop(0x140271B54, 15); | ||||||
|  | 			utils::hook::jump(0x140271B54, skip_extra_zones_stub, true); | ||||||
|  |  | ||||||
|  | 			// Add custom zone paths | ||||||
|  | 			sys_create_file_hook.create(game::Sys_CreateFile, sys_create_file_stub); | ||||||
|  |  | ||||||
|  | 			// Load mod.ff | ||||||
|  | 			utils::hook::call(0x1405A562A, db_load_x_assets_stub); // R_LoadGraphicsAssets According to myself but I don't remember where I got it from | ||||||
|  |  | ||||||
|  | 			// Allow loading of unsigned fastfiles | ||||||
|  | 			utils::hook::nop(0x1402427A5, 2); // DB_InflateInit | ||||||
|  |  | ||||||
|  | 			command::add("loadmod", [](const command::params& params) -> void | ||||||
|  | 			{ | ||||||
|  | 				if (params.size() != 2) | ||||||
|  | 				{ | ||||||
|  | 					console::info("USAGE: %s \"mods/<mod name>\"", params.get(0)); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				std::string mod_name = utils::string::to_lower(params.get(1)); | ||||||
|  |  | ||||||
|  | 				if (!mod_name.empty() && !mod_name.starts_with("mods/")) | ||||||
|  | 				{ | ||||||
|  | 					mod_name.insert(0, "mods/"); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// change fs_game if needed | ||||||
|  | 				if (mod_name != (*dvars::fs_gameDirVar)->current.string) | ||||||
|  | 				{ | ||||||
|  | 					game::Dvar_SetString((*dvars::fs_gameDirVar), mod_name.c_str()); | ||||||
|  | 					command::execute("vid_restart\n"); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			command::add("unloadmod", []([[maybe_unused]] const command::params& params) -> void | ||||||
|  | 			{ | ||||||
|  | 				if (*dvars::fs_gameDirVar == nullptr || *(*dvars::fs_gameDirVar)->current.string == '\0') | ||||||
|  | 				{ | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				game::Dvar_SetString(*dvars::fs_gameDirVar, ""); | ||||||
|  | 				command::execute("vid_restart\n"); | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			// TODO: without a way to monitor all the ways fs_game can be changed there is no way to detect when we | ||||||
|  | 			// should unregister the path from the internal filesystem we use | ||||||
|  | 			// HINT: It could be done in fs_game_dir_domain_func, but I haven't tested if that's the best place to monitor for changes and register/unregister the mods folder | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | REGISTER_COMPONENT(mods::component) | ||||||
							
								
								
									
										7
									
								
								src/client/component/mods.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/client/component/mods.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace mods | ||||||
|  | { | ||||||
|  | 	bool is_using_mods(); | ||||||
|  | 	bool db_mod_file_exists(); | ||||||
|  | } | ||||||
| @@ -163,17 +163,6 @@ namespace patches | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		void set_client_dvar_from_server_stub(void* a1, void* a2, const char* dvar, const char* value) |  | ||||||
| 		{ |  | ||||||
| 			if (utils::string::to_lower(dvar) == "cg_fov") |  | ||||||
| 			{ |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			// CG_SetClientDvarFromServer |  | ||||||
| 			reinterpret_cast<void(*)(void*, void*, const char*, const char*)>(0x1401BF0A0)(a1, a2, dvar, value); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		utils::hook::detour cmd_lui_notify_server_hook; | 		utils::hook::detour cmd_lui_notify_server_hook; | ||||||
| 		void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) | 		void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) | ||||||
| 		{ | 		{ | ||||||
| @@ -298,9 +287,8 @@ namespace patches | |||||||
| 			utils::hook::inject(0x1404398B2, VERSION); | 			utils::hook::inject(0x1404398B2, VERSION); | ||||||
|  |  | ||||||
| 			// prevent servers overriding our fov | 			// prevent servers overriding our fov | ||||||
| 			utils::hook::call(0x1401BB782, set_client_dvar_from_server_stub); |  | ||||||
| 			utils::hook::nop(0x1403D1195, 5); | 			utils::hook::nop(0x1403D1195, 5); | ||||||
| 			utils::hook::nop(0x1400FAE36, 5); | 			utils::hook::nop(0x1400FAE36, 5); // Dvar_SetFloat inside LUI_CoD_LuaCall_StopFollow (function doesn't exist on dev builds) | ||||||
| 			utils::hook::set<uint8_t>(0x14019B9B9, 0xEB); | 			utils::hook::set<uint8_t>(0x14019B9B9, 0xEB); | ||||||
|  |  | ||||||
| 			// some anti tamper thing that kills performance | 			// some anti tamper thing that kills performance | ||||||
|   | |||||||
| @@ -36,13 +36,13 @@ namespace dvars | |||||||
|  |  | ||||||
| 	game::dvar_t* r_fullbright = nullptr; | 	game::dvar_t* r_fullbright = nullptr; | ||||||
|  |  | ||||||
| 	game::dvar_t* cg_legacyCrashHandling = nullptr; |  | ||||||
|  |  | ||||||
| 	game::dvar_t* sv_cheats = nullptr; | 	game::dvar_t* sv_cheats = nullptr; | ||||||
|  |  | ||||||
| 	game::dvar_t* com_developer = nullptr; | 	game::dvar_t* com_developer = nullptr; | ||||||
| 	game::dvar_t* com_developer_script = nullptr; | 	game::dvar_t* com_developer_script = nullptr; | ||||||
|  |  | ||||||
|  | 	game::dvar_t** fs_gameDirVar = nullptr; | ||||||
|  |  | ||||||
| 	std::string get_dvar_string(const std::string& dvar) | 	std::string get_dvar_string(const std::string& dvar) | ||||||
| 	{ | 	{ | ||||||
| 		const auto* dvar_value = game::Dvar_FindVar(dvar.data()); | 		const auto* dvar_value = game::Dvar_FindVar(dvar.data()); | ||||||
|   | |||||||
| @@ -35,13 +35,13 @@ namespace dvars | |||||||
|  |  | ||||||
| 	extern game::dvar_t* r_fullbright; | 	extern game::dvar_t* r_fullbright; | ||||||
|  |  | ||||||
| 	extern game::dvar_t* cg_legacyCrashHandling; |  | ||||||
|  |  | ||||||
| 	extern game::dvar_t* sv_cheats; | 	extern game::dvar_t* sv_cheats; | ||||||
|  |  | ||||||
| 	extern game::dvar_t* com_developer; | 	extern game::dvar_t* com_developer; | ||||||
| 	extern game::dvar_t* com_developer_script; | 	extern game::dvar_t* com_developer_script; | ||||||
|  |  | ||||||
|  | 	extern game::dvar_t** fs_gameDirVar; | ||||||
|  |  | ||||||
| 	std::string get_dvar_string(const std::string& dvar); | 	std::string get_dvar_string(const std::string& dvar); | ||||||
| 	bool get_dvar_bool(const std::string& dvar); | 	bool get_dvar_bool(const std::string& dvar); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,6 +30,13 @@ namespace game | |||||||
| 		return !game::environment::is_sp() && *mp::virtualLobby_loaded == 1; | 		return !game::environment::is_sp() && *mp::virtualLobby_loaded == 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	HANDLE Sys_OpenFileReliable(const char* filename) | ||||||
|  | 	{ | ||||||
|  | 		return ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, | ||||||
|  | 		                     OPEN_EXISTING, | ||||||
|  | 		                     FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	namespace environment | 	namespace environment | ||||||
| 	{ | 	{ | ||||||
| 		launcher::mode mode = launcher::mode::none; | 		launcher::mode mode = launcher::mode::none; | ||||||
|   | |||||||
| @@ -66,6 +66,8 @@ namespace game | |||||||
|  |  | ||||||
| 	[[nodiscard]] bool VirtualLobby_Loaded(); | 	[[nodiscard]] bool VirtualLobby_Loaded(); | ||||||
|  |  | ||||||
|  | 	[[nodiscard]] HANDLE Sys_OpenFileReliable(const char* filename); | ||||||
|  |  | ||||||
| 	[[nodiscard]] bool is_headless(); | 	[[nodiscard]] bool is_headless(); | ||||||
| 	void show_error(const std::string& text, const std::string& title = "Error"); | 	void show_error(const std::string& text, const std::string& title = "Error"); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,6 +25,14 @@ namespace game | |||||||
| 	typedef void(*BuiltinMethod)(scr_entref_t); | 	typedef void(*BuiltinMethod)(scr_entref_t); | ||||||
| 	typedef void(*BuiltinFunction)(); | 	typedef void(*BuiltinFunction)(); | ||||||
|  |  | ||||||
|  | 	enum ControllerIndex_t | ||||||
|  | 	{ | ||||||
|  | 		INVALID_CONTROLLER_PORT = -1, | ||||||
|  | 		CONTROLLER_INDEX_0 = 0x0, | ||||||
|  | 		CONTROLLER_INDEX_FIRST = 0x0, | ||||||
|  | 		CONTROLLER_INDEX_COUNT = 0x1, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	enum | 	enum | ||||||
| 	{ | 	{ | ||||||
| 		VAR_UNDEFINED = 0x0, | 		VAR_UNDEFINED = 0x0, | ||||||
| @@ -905,6 +913,8 @@ namespace game | |||||||
| 		DVAR_FLAG_LATCHED = 0x2, | 		DVAR_FLAG_LATCHED = 0x2, | ||||||
| 		DVAR_FLAG_CHEAT = 0x4, | 		DVAR_FLAG_CHEAT = 0x4, | ||||||
| 		DVAR_FLAG_REPLICATED = 0x8, | 		DVAR_FLAG_REPLICATED = 0x8, | ||||||
|  | 		DVAR_FLAG_SCRIPTINFO = 0x10, | ||||||
|  | 		DVAR_FLAG_SERVERINFO = 0x400, | ||||||
| 		DVAR_FLAG_WRITE = 0x800, | 		DVAR_FLAG_WRITE = 0x800, | ||||||
| 		DVAR_FLAG_READ = 0x2000, | 		DVAR_FLAG_READ = 0x2000, | ||||||
| 	}; | 	}; | ||||||
| @@ -923,7 +933,7 @@ namespace game | |||||||
| 		rgb = 9 // Color without alpha | 		rgb = 9 // Color without alpha | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	union dvar_value | 	union DvarValue | ||||||
| 	{ | 	{ | ||||||
| 		bool enabled; | 		bool enabled; | ||||||
| 		int integer; | 		int integer; | ||||||
| @@ -966,9 +976,9 @@ namespace game | |||||||
| 		unsigned int flags; | 		unsigned int flags; | ||||||
| 		dvar_type type; | 		dvar_type type; | ||||||
| 		bool modified; | 		bool modified; | ||||||
| 		dvar_value current; | 		DvarValue current; | ||||||
| 		dvar_value latched; | 		DvarValue latched; | ||||||
| 		dvar_value reset; | 		DvarValue reset; | ||||||
| 		dvar_limits domain; | 		dvar_limits domain; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -1319,6 +1329,15 @@ namespace game | |||||||
| 		const char *name; | 		const char *name; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	struct WeaponDef | ||||||
|  | 	{}; | ||||||
|  |  | ||||||
|  | 	struct WeaponCompleteDef | ||||||
|  | 	{ | ||||||
|  | 		const char* szInternalName; | ||||||
|  | 		WeaponDef* weapDef; | ||||||
|  | 	}; // Incomplete | ||||||
|  |  | ||||||
| 	union XAssetHeader | 	union XAssetHeader | ||||||
| 	{ | 	{ | ||||||
| 		void* data; | 		void* data; | ||||||
| @@ -1443,6 +1462,40 @@ namespace game | |||||||
| 		netProfileStream_t recieve; | 		netProfileStream_t recieve; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		DB_ZONE_COMMON = 0x1, | ||||||
|  | 		DB_ZONE_UI = 0x2, | ||||||
|  | 		DB_ZONE_GAME = 0x4, | ||||||
|  | 		DB_ZONE_LOAD = 0x8, | ||||||
|  | 		DB_ZONE_DEV = 0x10, | ||||||
|  | 		DB_ZONE_BASEMAP = 0x20, | ||||||
|  | 		DB_ZONE_TRANSIENT_POOL = 0x40, | ||||||
|  | 		DB_ZONE_TRANSIENT_MASK = 0x40, | ||||||
|  | 		DB_ZONE_CUSTOM = 0x1000, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	enum FF_DIR | ||||||
|  | 	{ | ||||||
|  | 		FFD_DEFAULT = 0x0, | ||||||
|  | 		FFD_MOD_DIR = 0x1, | ||||||
|  | 		FFD_USER_MAP = 0x2, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	struct Sys_File | ||||||
|  | 	{ | ||||||
|  | 		HANDLE handle; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	enum DB_CompressorType | ||||||
|  | 	{ | ||||||
|  | 		DB_COMPRESSOR_INVALID = 0x0, | ||||||
|  | 		DB_COMPRESSOR_ZLIB = 0x1, | ||||||
|  | 		DB_COMPRESSOR_UNK2 = 0x2, | ||||||
|  | 		DB_COMPRESSOR_PASSTHROUGH = 0x3, | ||||||
|  | 		DB_COMPRESSOR_LZX = 0x4, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	namespace mp | 	namespace mp | ||||||
| 	{ | 	{ | ||||||
| 		enum | 		enum | ||||||
|   | |||||||
| @@ -60,6 +60,7 @@ namespace game | |||||||
| 	WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x14017E890, 0x14026FCC0}; | 	WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x14017E890, 0x14026FCC0}; | ||||||
| 	WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x14017E750, 0x14026FB90}; | 	WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x14017E750, 0x14026FB90}; | ||||||
| 	WEAK symbol<char*(const char* filename, char* buf, int size)> DB_ReadRawFile{0x140180E30, 0x140273080}; | 	WEAK symbol<char*(const char* filename, char* buf, int size)> DB_ReadRawFile{0x140180E30, 0x140273080}; | ||||||
|  | 	WEAK symbol<int(XAssetType type, void** assets, int maxCount)> DB_GetAllXAssetOfType_FastFile{0x0, 0x14026F970}; | ||||||
|  |  | ||||||
| 	WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0}; | 	WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0}; | ||||||
| 	WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690}; | 	WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690}; | ||||||
| @@ -70,7 +71,7 @@ namespace game | |||||||
| 	WEAK symbol<void(const dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610}; | 	WEAK symbol<void(const dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610}; | ||||||
| 	WEAK symbol<void(const dvar_t* dvar, bool value)> Dvar_SetBool{0x0, 0x1404C1F30}; | 	WEAK symbol<void(const dvar_t* dvar, bool value)> Dvar_SetBool{0x0, 0x1404C1F30}; | ||||||
| 	WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x1403737D0, 0x1404C2E40}; | 	WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x1403737D0, 0x1404C2E40}; | ||||||
| 	WEAK symbol<const char*(dvar_t* dvar, dvar_value value)> Dvar_ValueToString{0x140374E10, 0x1404C47B0}; | 	WEAK symbol<const char*(dvar_t* dvar, DvarValue value)> Dvar_ValueToString{0x140374E10, 0x1404C47B0}; | ||||||
|  |  | ||||||
| 	WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned int flags)> Dvar_RegisterBool{0x140371850, 0x1404C0BE0}; | 	WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned int flags)> Dvar_RegisterBool{0x140371850, 0x1404C0BE0}; | ||||||
| 	WEAK symbol<dvar_t*(const char* dvarName, const char** valueList, int defaultIndex, unsigned int flags)> Dvar_RegisterEnum{0x140371B30, 0x1404C0EC0}; | 	WEAK symbol<dvar_t*(const char* dvarName, const char** valueList, int defaultIndex, unsigned int flags)> Dvar_RegisterEnum{0x140371B30, 0x1404C0EC0}; | ||||||
| @@ -98,13 +99,13 @@ namespace game | |||||||
| 	WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{0x0, 0x1403F3730}; | 	WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{0x0, 0x1403F3730}; | ||||||
|  |  | ||||||
| 	WEAK symbol<void()> G_Glass_Update{0x14021D540, 0x1402EDEE0}; | 	WEAK symbol<void()> G_Glass_Update{0x14021D540, 0x1402EDEE0}; | ||||||
|  |  | ||||||
| 	WEAK symbol<int(int clientNum)> G_GetClientScore{0, 0x1402F6AB0}; | 	WEAK symbol<int(int clientNum)> G_GetClientScore{0, 0x1402F6AB0}; | ||||||
| 	WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x140274590, 0x14033FF60}; | 	WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x140274590, 0x14033FF60}; | ||||||
| 	WEAK symbol<int(playerState_s* ps, unsigned int weapon, int dualWield, int startInAltMode, int, int, int, char)> G_GivePlayerWeapon{0x1402749B0, 0x140340470}; | 	WEAK symbol<int(playerState_s* ps, unsigned int weapon, int dualWield, int startInAltMode, int, int, int, char)> G_GivePlayerWeapon{0x1402749B0, 0x140340470}; | ||||||
| 	WEAK symbol<void(playerState_s* ps, unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x1402217F0, 0x1402F22B0}; | 	WEAK symbol<void(playerState_s* ps, unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x1402217F0, 0x1402F22B0}; | ||||||
| 	WEAK symbol<void(int clientNum, unsigned int weapon)> G_SelectWeapon{0x140275380, 0x140340D50}; | 	WEAK symbol<void(int clientNum, unsigned int weapon)> G_SelectWeapon{0x140275380, 0x140340D50}; | ||||||
| 	WEAK symbol<int(playerState_s* ps, unsigned int weapon)> G_TakePlayerWeapon{0x1402754E0, 0x1403411D0}; | 	WEAK symbol<int(playerState_s* ps, unsigned int weapon)> G_TakePlayerWeapon{0x1402754E0, 0x1403411D0}; | ||||||
|  | 	WEAK symbol<void()> G_SetupLevelWeaponDef{0x0, 0x140340DE0}; | ||||||
|  |  | ||||||
| 	WEAK symbol<char*(char* string)> I_CleanStr{0x140379010, 0x1404C99A0}; | 	WEAK symbol<char*(char* string)> I_CleanStr{0x140379010, 0x1404C99A0}; | ||||||
|  |  | ||||||
| @@ -113,6 +114,7 @@ namespace game | |||||||
| 	WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14013F380, 0x140207C50}; | 	WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14013F380, 0x140207C50}; | ||||||
|  |  | ||||||
| 	WEAK symbol<unsigned int(int)> Live_SyncOnlineDataFlags{0x1404459A0, 0x140562830}; | 	WEAK symbol<unsigned int(int)> Live_SyncOnlineDataFlags{0x1404459A0, 0x140562830}; | ||||||
|  | 	WEAK symbol<void(int localControllerIndex)> LiveStorage_StatsWriteNotNeeded{0x1402F51F0, 0x1403C3CD0}; | ||||||
|  |  | ||||||
| 	WEAK symbol<void(int localClientNum, const char* menuName, int isPopup, int isModal, unsigned int isExclusive)> LUI_OpenMenu{0, 0x14048E450}; | 	WEAK symbol<void(int localClientNum, const char* menuName, int isPopup, int isModal, unsigned int isExclusive)> LUI_OpenMenu{0, 0x14048E450}; | ||||||
| 	WEAK symbol<void()> LUI_EnterCriticalSection{0, 0x1400D2B10}; | 	WEAK symbol<void()> LUI_EnterCriticalSection{0, 0x1400D2B10}; | ||||||
| @@ -226,6 +228,8 @@ namespace game | |||||||
|  |  | ||||||
| 	WEAK symbol<void(const char* pszCommand, char* pszBuffer, int iBufferSize)> MSG_WriteReliableCommandToBuffer{0x0, 0x1403E1090}; | 	WEAK symbol<void(const char* pszCommand, char* pszBuffer, int iBufferSize)> MSG_WriteReliableCommandToBuffer{0x0, 0x1403E1090}; | ||||||
|  |  | ||||||
|  | 	WEAK symbol<int(const char* s0, const char* s1, int n)> I_strnicmp{0x1403793E0, 0x1404C9E90}; | ||||||
|  |  | ||||||
| 	WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930}; | 	WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930}; | ||||||
| 	WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070}; | 	WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070}; | ||||||
|  |  | ||||||
| @@ -265,6 +269,7 @@ namespace game | |||||||
| 	WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100}; | 	WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100}; | ||||||
| 	WEAK symbol<int> g_poolSize{0x140804140, 0x1409B4B90}; | 	WEAK symbol<int> g_poolSize{0x140804140, 0x1409B4B90}; | ||||||
| 	WEAK symbol<const char*> g_assetNames{0x140803C90, 0x1409B3180}; | 	WEAK symbol<const char*> g_assetNames{0x140803C90, 0x1409B3180}; | ||||||
|  | 	WEAK symbol<int> g_compressor{0x141598580, 0x141E0B080}; | ||||||
|  |  | ||||||
| 	WEAK symbol<DWORD> threadIds{0x149632EC0, 0x147DCEA30}; | 	WEAK symbol<DWORD> threadIds{0x149632EC0, 0x147DCEA30}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,109 +0,0 @@ | |||||||
| #include "toast.hpp" |  | ||||||
| #include "string.hpp" |  | ||||||
|  |  | ||||||
| #pragma warning(push) |  | ||||||
| #pragma warning(disable: 6387) |  | ||||||
| #include <wintoastlib.h> |  | ||||||
| #pragma warning(pop) |  | ||||||
|  |  | ||||||
| namespace utils |  | ||||||
| { |  | ||||||
| 	namespace |  | ||||||
| 	{ |  | ||||||
| 		bool initialize() |  | ||||||
| 		{ |  | ||||||
| 			static bool initialized = false; |  | ||||||
| 			static bool success = false; |  | ||||||
| 			if (initialized) |  | ||||||
| 			{ |  | ||||||
| 				return success; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			initialized = true; |  | ||||||
| 			auto* instance = WinToastLib::WinToast::instance(); |  | ||||||
| 			if (!instance) |  | ||||||
| 			{ |  | ||||||
| 				success = false; |  | ||||||
| 				return success; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			instance->setAppName(L"s1-mod"); |  | ||||||
| 			instance->setAppUserModelId( |  | ||||||
| 				WinToastLib::WinToast::configureAUMI(L"AlterWare", L"s1-mod", L"", L"20201212")); |  | ||||||
|  |  | ||||||
| 			WinToastLib::WinToast::WinToastError error; |  | ||||||
| 			success = instance->initialize(&error); |  | ||||||
|  |  | ||||||
| 			return success; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		class toast_handler : public WinToastLib::IWinToastHandler |  | ||||||
| 		{ |  | ||||||
| 		public: |  | ||||||
| 			void toastActivated() const override |  | ||||||
| 			{ |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			void toastActivated(const int /*actionIndex*/) const override |  | ||||||
| 			{ |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			void toastFailed() const override |  | ||||||
| 			{ |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			void toastDismissed(WinToastDismissalReason /*state*/) const override |  | ||||||
| 			{ |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	toast::toast(const int64_t id) |  | ||||||
| 		: id_(id) |  | ||||||
| 	{ |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	toast::operator bool() const |  | ||||||
| 	{ |  | ||||||
| 		return this->id_ >= 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void toast::hide() const |  | ||||||
| 	{ |  | ||||||
| 		if (this->operator bool()) |  | ||||||
| 		{ |  | ||||||
| 			WinToastLib::WinToast::instance()->hideToast(this->id_); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	toast toast::show(const std::string& title, const std::string& text) |  | ||||||
| 	{ |  | ||||||
| 		if (!initialize()) |  | ||||||
| 		{ |  | ||||||
| 			return toast{-1}; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::Text02); |  | ||||||
| 		toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); |  | ||||||
| 		toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); |  | ||||||
| 		toast_template.setDuration(WinToastLib::WinToastTemplate::Long); |  | ||||||
|  |  | ||||||
| 		return toast{WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	toast toast::show(const std::string& title, const std::string& text, const std::string& image) |  | ||||||
| 	{ |  | ||||||
| 		if (!initialize()) |  | ||||||
| 		{ |  | ||||||
| 			return {-1}; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::ImageAndText02); |  | ||||||
| 		toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); |  | ||||||
| 		toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); |  | ||||||
| 		toast_template.setDuration(WinToastLib::WinToastTemplate::Long); |  | ||||||
| 		toast_template.setImagePath(string::convert(image)); |  | ||||||
|  |  | ||||||
| 		return {WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| namespace utils |  | ||||||
| { |  | ||||||
| 	class toast |  | ||||||
| 	{ |  | ||||||
| 	public: |  | ||||||
| 		static toast show(const std::string& title, const std::string& text); |  | ||||||
| 		static toast show(const std::string& title, const std::string& text, const std::string& image); |  | ||||||
|  |  | ||||||
| 		operator bool() const; |  | ||||||
| 		void hide() const; |  | ||||||
|  |  | ||||||
| 	private: |  | ||||||
| 		toast(int64_t id); |  | ||||||
| 		int64_t id_; |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user