Merge pull request #263 from JariKCoding/main
Added compiled GSC loading by overriding existing scripts & implemented fix for change team not being available
This commit is contained in:
commit
ab40dd5ec3
BIN
data/scripts/mp/gametypes/_clientids.gsc
Normal file
BIN
data/scripts/mp/gametypes/_clientids.gsc
Normal file
Binary file not shown.
33
data/scripts/mp/gametypes/_clientids.gsc_raw
Normal file
33
data/scripts/mp/gametypes/_clientids.gsc_raw
Normal file
@ -0,0 +1,33 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
|
||||
#insert scripts\shared\shared.gsh;
|
||||
|
||||
#namespace clientids;
|
||||
|
||||
REGISTER_SYSTEM( "clientids", &__init__, undefined )
|
||||
|
||||
function __init__()
|
||||
{
|
||||
callback::on_start_gametype( &init );
|
||||
callback::on_connect( &on_player_connect );
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
level.clientid = 0;
|
||||
wait 0.5;
|
||||
level.allow_teamchange = "1";
|
||||
}
|
||||
|
||||
function on_player_connect()
|
||||
{
|
||||
self.clientid = matchRecordNewPlayer( self );
|
||||
if ( !isdefined( self.clientid ) || self.clientid == -1 )
|
||||
{
|
||||
self.clientid = level.clientid;
|
||||
level.clientid++;
|
||||
}
|
||||
}
|
@ -7,3 +7,78 @@ CoD.IsTeamChangeAllowed = function()
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
DataSources.StartMenuGameOptions = ListHelper_SetupDataSource("StartMenuGameOptions", function (controller)
|
||||
local options = {}
|
||||
if Engine.IsDemoPlaying() then
|
||||
if not IsDemoRestrictedBasicMode() then
|
||||
table.insert(options, {models = {displayText = Engine.ToUpper(Engine.Localize("MENU_UPLOAD_CLIP", Engine.GetDemoSegmentCount())), action = StartMenuUploadClip, disabledFunction = IsUploadClipButtonDisabled}, properties = {hideHelpItemLabel = true}})
|
||||
end
|
||||
if Engine.IsDemoHighlightReelMode() then
|
||||
table.insert(options, {models = {displayText = Engine.ToUpper(Engine.Localize("MENU_DEMO_CUSTOMIZE_HIGHLIGHT_REEL")), action = StartMenuOpenCustomizeHighlightReel, disabledFunction = IsCustomizeHighlightReelButtonDisabled}})
|
||||
end
|
||||
table.insert(options, {models = {displayText = Engine.ToUpper(Engine.ToUpper(Engine.Localize("MENU_JUMP_TO_START"))), action = StartMenuJumpToStart, disabledFunction = IsJumpToStartButtonDisabled}, properties = {hideHelpItemLabel = true}})
|
||||
local endDemoButtonText = nil
|
||||
if Engine.IsDemoClipPlaying() then
|
||||
endDemoButtonText = Engine.ToUpper(Engine.Localize("MENU_END_CLIP"))
|
||||
else
|
||||
endDemoButtonText = Engine.ToUpper(Engine.Localize("MENU_END_FILM"))
|
||||
end
|
||||
table.insert(options, {models = {displayText = Engine.ToUpper(endDemoButtonText), action = StartMenuEndDemo}})
|
||||
elseif CoD.isCampaign then
|
||||
table.insert(options, {models = {displayText = "MENU_RESUMEGAME_CAPS", action = StartMenuGoBack_ListElement}})
|
||||
local inTrainingSim = CoD.SafeGetModelValue(Engine.GetModelForController(controller), "safehouse.inTrainingSim")
|
||||
if not inTrainingSim then
|
||||
inTrainingSim = 0
|
||||
end
|
||||
if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) then
|
||||
if not CoD.isSafehouse and controller == Engine.GetPrimaryController() then
|
||||
table.insert(options, {models = {displayText = "MENU_RESTART_MISSION_CAPS", action = RestartMission}})
|
||||
if LUI.DEV ~= nil then
|
||||
table.insert(options, {models = {displayText = "MENU_RESTART_CHECKPOINT_CAPS", action = RestartFromCheckpoint}})
|
||||
end
|
||||
end
|
||||
if controller == Engine.GetPrimaryController() then
|
||||
table.insert(options, {models = {displayText = "MENU_CHANGE_DIFFICULTY_CAPS", action = OpenDifficultySelect}})
|
||||
end
|
||||
if CoD.isSafehouse and inTrainingSim == 1 then
|
||||
table.insert(options, {models = {displayText = "MENU_END_TRAINING_SIM", action = EndTrainingSim}})
|
||||
elseif controller == Engine.GetPrimaryController() then
|
||||
if Engine.DvarBool(0, "ui_blocksaves") then
|
||||
table.insert(options, {models = {displayText = "MENU_EXIT_CAPS", action = SaveAndQuitGame}})
|
||||
else
|
||||
table.insert(options, {models = {displayText = "MENU_SAVE_AND_QUIT_CAPS", action = SaveAndQuitGame}})
|
||||
end
|
||||
end
|
||||
elseif CoD.isSafehouse and inTrainingSim == 1 then
|
||||
table.insert(options, {models = {displayText = "MENU_END_TRAINING_SIM", action = EndTrainingSim}})
|
||||
else
|
||||
table.insert(options, {models = {displayText = "MENU_LEAVE_PARTY_AND_EXIT_CAPS", action = QuitGame}})
|
||||
end
|
||||
elseif CoD.isMultiplayer then
|
||||
if Engine.Team(controller, "name") ~= "TEAM_SPECTATOR" and Engine.GetGametypeSetting("disableClassSelection") ~= 1 then
|
||||
table.insert(options, {models = {displayText = "MPUI_CHOOSE_CLASS_BUTTON_CAPS", action = ChooseClass}})
|
||||
end
|
||||
if not Engine.IsVisibilityBitSet(controller, Enum.UIVisibilityBit.BIT_ROUND_END_KILLCAM) and not Engine.IsVisibilityBitSet(controller, Enum.UIVisibilityBit.BIT_FINAL_KILLCAM) and CoD.IsTeamChangeAllowed() then
|
||||
table.insert(options, {models = {displayText = "MPUI_CHANGE_TEAM_BUTTON_CAPS", action = ChooseTeam}})
|
||||
end
|
||||
if controller == 0 then
|
||||
local endGameText = "MENU_QUIT_GAME_CAPS"
|
||||
if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and not CoD.isOnlineGame() then
|
||||
endGameText = "MENU_END_GAME_CAPS"
|
||||
end
|
||||
table.insert(options, {models = {displayText = endGameText, action = QuitGame_MP}})
|
||||
end
|
||||
elseif CoD.isZombie then
|
||||
table.insert(options, {models = {displayText = "MENU_RESUMEGAME_CAPS", action = StartMenuGoBack_ListElement}})
|
||||
if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and (not not (Engine.SessionModeIsMode(CoD.SESSIONMODE_SYSTEMLINK) == true) or Engine.SessionModeIsMode(CoD.SESSIONMODE_OFFLINE) == true) then
|
||||
table.insert(options, {models = {displayText = "MENU_RESTART_LEVEL_CAPS", action = RestartGame}})
|
||||
end
|
||||
if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) == true then
|
||||
table.insert(options, {models = {displayText = "MENU_END_GAME_CAPS", action = QuitGame_MP}})
|
||||
else
|
||||
table.insert(options, {models = {displayText = "MENU_QUIT_GAME_CAPS", action = QuitGame_MP}})
|
||||
end
|
||||
end
|
||||
return options
|
||||
end, true)
|
132
src/client/component/script.cpp
Normal file
132
src/client/component/script.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace script
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour db_findxassetheader_hook;
|
||||
|
||||
struct globals_t
|
||||
{
|
||||
std::unordered_map<std::string, game::RawFile*> loaded_scripts;
|
||||
};
|
||||
|
||||
globals_t globals;
|
||||
|
||||
game::RawFile* get_loaded_script(const std::string& name)
|
||||
{
|
||||
const auto itr = globals.loaded_scripts.find(name);
|
||||
return (itr == globals.loaded_scripts.end()) ? NULL : itr->second;
|
||||
}
|
||||
|
||||
void print_loading_script(const std::string& name)
|
||||
{
|
||||
printf("Loading GSC script '%s'\n", name.data());
|
||||
}
|
||||
|
||||
void load_script(std::string& name, const std::string& data)
|
||||
{
|
||||
auto& allocator = *utils::memory::get_allocator();
|
||||
auto file_string = static_cast<char*>(allocator.allocate(data.length()));
|
||||
std::memcpy(file_string, data.data(), data.length());
|
||||
|
||||
const utils::nt::library host{};
|
||||
auto appdata_path = (game::get_appdata_path() / "data/").generic_string();
|
||||
auto host_path = (host.get_folder() / "boiii/").generic_string();
|
||||
std::string::size_type i = name.find(appdata_path);
|
||||
if (i != std::string::npos)
|
||||
name.erase(i, appdata_path.length());
|
||||
i = name.find(host_path);
|
||||
if (i != std::string::npos)
|
||||
name.erase(i, host_path.length());
|
||||
|
||||
auto rawfile = static_cast<game::RawFile*>(allocator.allocate(24));
|
||||
rawfile->name = name.c_str();
|
||||
rawfile->buffer = file_string;
|
||||
rawfile->len = static_cast<int>(data.length());
|
||||
|
||||
globals.loaded_scripts[name] = rawfile;
|
||||
}
|
||||
|
||||
void load_scripts_folder(const std::string& script_dir)
|
||||
{
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto scripts = utils::io::list_files(script_dir);
|
||||
|
||||
for (const auto& script : scripts)
|
||||
{
|
||||
std::string data;
|
||||
auto script_file = script.generic_string();
|
||||
if (!std::filesystem::is_directory(script) && utils::io::read_file(script_file, &data))
|
||||
{
|
||||
print_loading_script(script_file);
|
||||
load_script(script_file, data);
|
||||
}
|
||||
else if (std::filesystem::is_directory(script))
|
||||
{
|
||||
load_scripts_folder(script_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_scripts()
|
||||
{
|
||||
globals = {};
|
||||
const utils::nt::library host{};
|
||||
load_scripts_folder((game::get_appdata_path() / "data/scripts").string());
|
||||
load_scripts_folder((host.get_folder() / "boiii/scripts").string());
|
||||
}
|
||||
|
||||
game::RawFile* db_findxassetheader_stub(game::XAssetType type, const char* name, bool errorIfMissing, int waitTime)
|
||||
{
|
||||
if (type != game::ASSET_TYPE_SCRIPTPARSETREE)
|
||||
{
|
||||
return db_findxassetheader_hook.invoke<game::RawFile*>(type, name, errorIfMissing, waitTime);
|
||||
}
|
||||
|
||||
auto asset_header = db_findxassetheader_hook.invoke<game::RawFile*>(type, name, errorIfMissing, waitTime);
|
||||
if (globals.loaded_scripts.contains(name))
|
||||
{
|
||||
auto script = get_loaded_script(name);
|
||||
|
||||
utils::hook::copy((void*)(script->buffer + 0x8), asset_header->buffer + 0x8, 4); // Copy over the checksum of the original script
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
return asset_header;
|
||||
}
|
||||
}
|
||||
|
||||
struct component final : generic_component
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
if (game::is_server())
|
||||
{
|
||||
load_scripts();
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduler::once(load_scripts, scheduler::pipeline::renderer);
|
||||
}
|
||||
|
||||
db_findxassetheader_hook.create(game::select(0x141420ED0, 0x1401D5FB0), db_findxassetheader_stub);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT(script::component)
|
@ -313,7 +313,7 @@ namespace ui_scripting
|
||||
globals.raw_script_name = target_script;
|
||||
|
||||
return game::XAssetHeader{
|
||||
.luaFile = reinterpret_cast<game::LuaFile*>(1) //
|
||||
.luaFile = reinterpret_cast<game::RawFile*>(1) //
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -556,7 +556,7 @@ namespace game
|
||||
ASSET_TYPE_FULL_COUNT = 0x6C,
|
||||
};
|
||||
|
||||
struct LuaFile
|
||||
struct RawFile
|
||||
{
|
||||
const char* name;
|
||||
int len;
|
||||
@ -1684,7 +1684,7 @@ namespace game
|
||||
BeamDef* beamDef;
|
||||
StreamerHint* streamerHint;*/
|
||||
void* data;
|
||||
LuaFile* luaFile;
|
||||
RawFile* luaFile;
|
||||
};
|
||||
|
||||
struct XAsset
|
||||
|
Loading…
Reference in New Issue
Block a user