Added compiled GSC loading by overriding existing scripts & implemented fix for change team not being available

This commit is contained in:
Jari van der Kaap 2023-02-28 23:58:07 +01:00
parent 8d249c9bdd
commit 6baee87d6e
6 changed files with 244 additions and 4 deletions

Binary file not shown.

View 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++;
}
}

View File

@ -6,4 +6,79 @@ CoD.IsTeamChangeAllowed = function()
else
return false
end
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)

View 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 = 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)

View File

@ -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) //
};
}

View File

@ -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