Merge pull request #154 from JariKCoding/main
UI Scripting, dvars cfg file, basic stats menu
This commit is contained in:
commit
c5511a2bae
4
data/ui_scripts/luafixes/__init__.lua
Normal file
4
data/ui_scripts/luafixes/__init__.lua
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
-- Fix LUI_NULL_FUNCTION messages
|
||||||
|
function Engine.PIXBeginEvent() end
|
||||||
|
function Engine.PIXEndEvent() end
|
290
data/ui_scripts/stats/__init__.lua
Normal file
290
data/ui_scripts/stats/__init__.lua
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", function ( controller )
|
||||||
|
local optionsTable = {}
|
||||||
|
|
||||||
|
table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all loot", "Whether loot should be locked based on the player's stats or always unlocked.", "MPStatsSettings_unlock_loot", "cg_unlockall_loot", {
|
||||||
|
{
|
||||||
|
option = "MENU_DISABLED",
|
||||||
|
value = 0,
|
||||||
|
default = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option = "MENU_ENABLED",
|
||||||
|
value = 1
|
||||||
|
},
|
||||||
|
}, nil, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4)
|
||||||
|
local oldValue = Engine.DvarInt( nil, dvarName )
|
||||||
|
local newValue = f1_arg1.value
|
||||||
|
UpdateInfoModels( f1_arg1 )
|
||||||
|
if oldValue == newValue then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
Engine.SetDvar( dvarName, f1_arg1.value )
|
||||||
|
Engine.SetDvar( "ui_enableAllHeroes", f1_arg1.value )
|
||||||
|
end) )
|
||||||
|
|
||||||
|
return optionsTable
|
||||||
|
end)
|
||||||
|
|
||||||
|
if Dvar.cg_unlockall_loot:get() == true then
|
||||||
|
Engine.SetDvar( "ui_enableAllHeroes", 1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
LUI.createMenu.MPStatsMenu = function ( controller )
|
||||||
|
local self = CoD.Menu.NewForUIEditor( "MPStatsMenu" )
|
||||||
|
if PreLoadFunc then
|
||||||
|
PreLoadFunc( self, controller )
|
||||||
|
end
|
||||||
|
self.soundSet = "ChooseDecal"
|
||||||
|
self:setOwner( controller )
|
||||||
|
self:setLeftRight( true, true, 0, 0 )
|
||||||
|
self:setTopBottom( true, true, 0, 0 )
|
||||||
|
self:playSound( "menu_open", controller )
|
||||||
|
self.buttonModel = Engine.CreateModel( Engine.GetModelForController( controller ), "MPStatsMenu.buttonPrompts" )
|
||||||
|
self.anyChildUsesUpdateState = true
|
||||||
|
|
||||||
|
local GameSettingsBackground = CoD.GameSettings_Background.new( self, controller )
|
||||||
|
GameSettingsBackground:setLeftRight( true, true, 0, 0 )
|
||||||
|
GameSettingsBackground:setTopBottom( true, true, 0, 0 )
|
||||||
|
GameSettingsBackground.MenuFrame.titleLabel:setText( Engine.Localize( "STATS SETTINGS" ) )
|
||||||
|
GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText( Engine.Localize( "STATS SETTINGS" ) )
|
||||||
|
GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha( 0 )
|
||||||
|
GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha( 0 )
|
||||||
|
self:addElement( GameSettingsBackground )
|
||||||
|
self.GameSettingsBackground = GameSettingsBackground
|
||||||
|
|
||||||
|
local Options = CoD.Competitive_SettingsList.new( self, controller )
|
||||||
|
Options:setLeftRight( true, false, 26, 741 )
|
||||||
|
Options:setTopBottom( true, false, 135, 720 )
|
||||||
|
Options.Title.DescTitle:setText( Engine.Localize( "Stats" ) )
|
||||||
|
Options.ButtonList:setVerticalCount( 15 )
|
||||||
|
Options.ButtonList:setDataSource( "MPStatsSettings" )
|
||||||
|
self:addElement( Options )
|
||||||
|
self.Options = Options
|
||||||
|
|
||||||
|
self:AddButtonCallbackFunction( self, controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, nil, function ( element, menu, controller, model )
|
||||||
|
GoBack( self, controller )
|
||||||
|
SetPerControllerTableProperty( controller, "disableGameSettingsOptions", nil )
|
||||||
|
return true
|
||||||
|
end, function ( element, menu, controller )
|
||||||
|
CoD.Menu.SetButtonLabel( menu, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, "MENU_BACK" )
|
||||||
|
return true
|
||||||
|
end, false )
|
||||||
|
|
||||||
|
GameSettingsBackground.MenuFrame:setModel( self.buttonModel, controller )
|
||||||
|
Options.id = "Options"
|
||||||
|
|
||||||
|
self:processEvent( {
|
||||||
|
name = "menu_loaded",
|
||||||
|
controller = controller
|
||||||
|
} )
|
||||||
|
self:processEvent( {
|
||||||
|
name = "update_state",
|
||||||
|
menu = self
|
||||||
|
} )
|
||||||
|
if not self:restoreState() then
|
||||||
|
self.Options:processEvent( {
|
||||||
|
name = "gain_focus",
|
||||||
|
controller = controller
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element )
|
||||||
|
element.GameSettingsBackground:close()
|
||||||
|
element.Options:close()
|
||||||
|
Engine.UnsubscribeAndFreeModel( Engine.GetModel( Engine.GetModelForController( controller ), "MPStatsMenu.buttonPrompts" ) )
|
||||||
|
end )
|
||||||
|
|
||||||
|
if PostLoadFunc then
|
||||||
|
PostLoadFunc( self, controller )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
CoD.LobbyButtons.MP_STATS = {
|
||||||
|
stringRef = "STATS",
|
||||||
|
action = function ( self, element, controller, param, menu )
|
||||||
|
SetPerControllerTableProperty( controller, "disableGameSettingsOptions", true )
|
||||||
|
OpenPopup( menu, "MPStatsMenu", controller )
|
||||||
|
end,
|
||||||
|
customId = "btnMPStats"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local IsGamescomDemo = function ()
|
||||||
|
return Dvar.ui_execdemo_gamescom:get()
|
||||||
|
end
|
||||||
|
|
||||||
|
local IsBetaDemo = function ()
|
||||||
|
return Dvar.ui_execdemo_beta:get()
|
||||||
|
end
|
||||||
|
|
||||||
|
local SetButtonState = function ( button, state )
|
||||||
|
if state == nil then
|
||||||
|
return
|
||||||
|
elseif state == CoD.LobbyButtons.DISABLED then
|
||||||
|
button.disabled = true
|
||||||
|
elseif state == CoD.LobbyButtons.HIDDEN then
|
||||||
|
button.hidden = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local AddButton = function ( controller, options, button, isLargeButton )
|
||||||
|
button.disabled = false
|
||||||
|
button.hidden = false
|
||||||
|
button.selected = false
|
||||||
|
button.warning = false
|
||||||
|
if button.defaultState ~= nil then
|
||||||
|
if button.defaultState == CoD.LobbyButtons.DISABLED then
|
||||||
|
button.disabled = true
|
||||||
|
elseif button.defaultState == CoD.LobbyButtons.HIDDEN then
|
||||||
|
button.hidden = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if button.disabledFunc ~= nil then
|
||||||
|
button.disabled = button.disabledFunc( controller )
|
||||||
|
end
|
||||||
|
if button.visibleFunc ~= nil then
|
||||||
|
button.hidden = not button.visibleFunc( controller )
|
||||||
|
end
|
||||||
|
if IsBetaDemo() then
|
||||||
|
SetButtonState( button, button.demo_beta )
|
||||||
|
elseif IsGamescomDemo() then
|
||||||
|
SetButtonState( button, button.demo_gamescom )
|
||||||
|
end
|
||||||
|
if button.hidden then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local lobbyNav = LobbyData.GetLobbyNav()
|
||||||
|
if button.selectedFunc ~= nil then
|
||||||
|
button.selected = button.selectedFunc( button.selectedParam )
|
||||||
|
elseif CoD.LobbyMenus.History[lobbyNav] ~= nil then
|
||||||
|
button.selected = CoD.LobbyMenus.History[lobbyNav] == button.customId
|
||||||
|
end
|
||||||
|
if button.newBreadcrumbFunc then
|
||||||
|
local f8_local1 = button.newBreadcrumbFunc
|
||||||
|
if type( f8_local1 ) == "string" then
|
||||||
|
f8_local1 = LUI.getTableFromPath( f8_local1 )
|
||||||
|
end
|
||||||
|
if f8_local1 then
|
||||||
|
button.isBreadcrumbNew = f8_local1( controller )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if button.warningFunc ~= nil then
|
||||||
|
button.warning = button.warningFunc( controller )
|
||||||
|
end
|
||||||
|
if button.starterPack == CoD.LobbyButtons.STARTERPACK_UPGRADE then
|
||||||
|
button.starterPackUpgrade = true
|
||||||
|
if IsStarterPack() then
|
||||||
|
button.disabled = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert( options, {
|
||||||
|
optionDisplay = button.stringRef,
|
||||||
|
action = button.action,
|
||||||
|
param = button.param,
|
||||||
|
customId = button.customId,
|
||||||
|
isLargeButton = isLargeButton,
|
||||||
|
isLastButtonInGroup = false,
|
||||||
|
disabled = button.disabled,
|
||||||
|
selected = button.selected,
|
||||||
|
isBreadcrumbNew = button.isBreadcrumbNew,
|
||||||
|
warning = button.warning,
|
||||||
|
requiredChunk = button.selectedParam,
|
||||||
|
starterPackUpgrade = button.starterPackUpgrade,
|
||||||
|
unloadMod = button.unloadMod
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
local AddLargeButton = function ( controller, options, button )
|
||||||
|
AddButton( controller, options, button, true )
|
||||||
|
end
|
||||||
|
|
||||||
|
local AddSmallButton = function ( controller, options, button )
|
||||||
|
AddButton( controller, options, button, false )
|
||||||
|
end
|
||||||
|
|
||||||
|
local AddSpacer = function ( options )
|
||||||
|
if 0 < #options then
|
||||||
|
options[#options].isLastButtonInGroup = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CoD.LobbyMenus.MPButtonsOnline = function ( f26_arg0, f26_arg1, f26_arg2 )
|
||||||
|
if f26_arg2 == 1 then
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_FIND_MATCH )
|
||||||
|
AddSpacer( f26_arg1 )
|
||||||
|
end
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_CAC_NO_WARNING )
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_SPECIALISTS_NO_WARNING )
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_SCORESTREAKS )
|
||||||
|
if (Dvar.ui_execdemo_beta:get() or IsStarterPack()) and IsStoreAvailable() then
|
||||||
|
if CoD.isPC then
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.STEAM_STORE )
|
||||||
|
else
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.STORE )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Engine.DvarBool( nil, "inventory_test_button_visible" ) then
|
||||||
|
AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_INVENTORY_TEST )
|
||||||
|
end
|
||||||
|
AddSpacer( f26_arg1 )
|
||||||
|
if not DisableBlackMarket() then
|
||||||
|
AddSmallButton( f26_arg0, f26_arg1, CoD.LobbyButtons.BLACK_MARKET )
|
||||||
|
end
|
||||||
|
AddSpacer( f26_arg1 )
|
||||||
|
AddSmallButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_STATS )
|
||||||
|
end
|
||||||
|
|
||||||
|
local targetButtons = {
|
||||||
|
[LobbyData.UITargets.UI_MAIN.id] = CoD.LobbyMenus.ModeSelect,
|
||||||
|
[LobbyData.UITargets.UI_MODESELECT.id] = CoD.LobbyMenus.ModeSelect,
|
||||||
|
[LobbyData.UITargets.UI_CPLOBBYLANGAME.id] = CoD.LobbyMenus.CPButtonsLAN,
|
||||||
|
[LobbyData.UITargets.UI_CPLOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM,
|
||||||
|
[LobbyData.UITargets.UI_CPLOBBYONLINE.id] = CoD.LobbyMenus.CPButtonsOnline,
|
||||||
|
[LobbyData.UITargets.UI_CPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPButtonsPublicGame,
|
||||||
|
[LobbyData.UITargets.UI_CPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame,
|
||||||
|
[LobbyData.UITargets.UI_CP2LOBBYLANGAME.id] = CoD.LobbyMenus.CPZMButtonsLAN,
|
||||||
|
[LobbyData.UITargets.UI_CP2LOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM,
|
||||||
|
[LobbyData.UITargets.UI_CP2LOBBYONLINE.id] = CoD.LobbyMenus.CPZMButtonsOnline,
|
||||||
|
[LobbyData.UITargets.UI_CP2LOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPZMButtonsPublicGame,
|
||||||
|
[LobbyData.UITargets.UI_CP2LOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame,
|
||||||
|
[LobbyData.UITargets.UI_DOALOBBYLANGAME.id] = CoD.LobbyMenus.DOAButtonsLAN,
|
||||||
|
[LobbyData.UITargets.UI_DOALOBBYONLINE.id] = CoD.LobbyMenus.DOAButtonsOnline,
|
||||||
|
[LobbyData.UITargets.UI_DOALOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.DOAButtonsPublicGame,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYLANGAME.id] = CoD.LobbyMenus.MPButtonsLAN,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYMAIN.id] = CoD.LobbyMenus.MPButtonsMain,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINE.id] = CoD.LobbyMenus.MPButtonsOnline,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.MPButtonsOnlinePublic,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINEMODGAME.id] = CoD.LobbyMenus.MPButtonsModGame,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.MPButtonsCustomGame,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINEARENA.id] = CoD.LobbyMenus.MPButtonsArena,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id] = CoD.LobbyMenus.MPButtonsArenaGame,
|
||||||
|
[LobbyData.UITargets.UI_FRLOBBYONLINEGAME.id] = CoD.LobbyMenus.FRButtonsOnlineGame,
|
||||||
|
[LobbyData.UITargets.UI_FRLOBBYLANGAME.id] = CoD.LobbyMenus.FRButtonsLANGame,
|
||||||
|
[LobbyData.UITargets.UI_ZMLOBBYLANGAME.id] = CoD.LobbyMenus.ZMButtonsLAN,
|
||||||
|
[LobbyData.UITargets.UI_ZMLOBBYONLINE.id] = CoD.LobbyMenus.ZMButtonsOnline,
|
||||||
|
[LobbyData.UITargets.UI_ZMLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.ZMButtonsPublicGame,
|
||||||
|
[LobbyData.UITargets.UI_ZMLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.ZMButtonsCustomGame,
|
||||||
|
[LobbyData.UITargets.UI_MPLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame,
|
||||||
|
[LobbyData.UITargets.UI_ZMLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame
|
||||||
|
}
|
||||||
|
CoD.LobbyMenus.AddButtonsForTarget = function ( controller, id )
|
||||||
|
local buttonFunc = targetButtons[id]
|
||||||
|
local model = nil
|
||||||
|
if Engine.IsLobbyActive( Enum.LobbyType.LOBBY_TYPE_GAME ) then
|
||||||
|
model = Engine.GetModel( DataSources.LobbyRoot.getModel( controller ), "gameClient.isHost" )
|
||||||
|
else
|
||||||
|
model = Engine.GetModel( DataSources.LobbyRoot.getModel( controller ), "privateClient.isHost" )
|
||||||
|
end
|
||||||
|
local isLeader = nil
|
||||||
|
if model ~= nil then
|
||||||
|
isLeader = Engine.GetModelValue( model )
|
||||||
|
else
|
||||||
|
isLeader = 1
|
||||||
|
end
|
||||||
|
local result = {}
|
||||||
|
buttonFunc( controller, result, isLeader )
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
91
src/client/component/dvars.cpp
Normal file
91
src/client/component/dvars.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
namespace dvars
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool initial_config_read = false;
|
||||||
|
utils::hook::detour dvar_register_new_hook;
|
||||||
|
utils::hook::detour dvar_set_variant_hook;
|
||||||
|
|
||||||
|
utils::hook::detour set_config_dvar_hook;
|
||||||
|
utils::hook::detour for_each_name_match_hook;
|
||||||
|
utils::hook::detour get_debug_name_hook;
|
||||||
|
|
||||||
|
|
||||||
|
const std::string get_config_file_path()
|
||||||
|
{
|
||||||
|
return "players/user/config.cfg";
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_archive_dvars()
|
||||||
|
{
|
||||||
|
std::string config_buffer;
|
||||||
|
|
||||||
|
for (int i = 0; i < *game::g_dvarCount; ++i)
|
||||||
|
{
|
||||||
|
const auto* dvar = reinterpret_cast<const game::dvar_t*>(&game::s_dvarPool[160 * i]);
|
||||||
|
|
||||||
|
if (!dvar->debugName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto name = dvar->debugName;
|
||||||
|
auto value = game::Dvar_DisplayableValue(dvar);
|
||||||
|
|
||||||
|
config_buffer.append(utils::string::va("set %s %s\n", name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_buffer.length() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
utils::io::write_file(get_config_file_path(), config_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dvar_set_variant_stub(game::dvar_t* dvar, game::DvarValue* value, unsigned int source)
|
||||||
|
{
|
||||||
|
dvar_set_variant_hook.invoke(dvar, value, source);
|
||||||
|
|
||||||
|
if (initial_config_read && dvar->debugName)
|
||||||
|
{
|
||||||
|
write_archive_dvars();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_archive_dvars()
|
||||||
|
{
|
||||||
|
const std::string path = get_config_file_path();
|
||||||
|
|
||||||
|
if (!utils::io::file_exists(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string filedata;
|
||||||
|
utils::io::read_file(path, &filedata);
|
||||||
|
|
||||||
|
game::Cbuf_ExecuteBuffer(0, game::ControllerIndex_t::CONTROLLER_INDEX_0, filedata.c_str());
|
||||||
|
initial_config_read = true;
|
||||||
|
scheduler::execute(scheduler::pipeline::dvars_loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public client_component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
scheduler::once(read_archive_dvars, scheduler::pipeline::main);
|
||||||
|
|
||||||
|
dvar_set_variant_hook.create(0x1422C9A90_g, dvar_set_variant_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(dvars::component)
|
@ -10,13 +10,20 @@ namespace loot
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
game::dvar_t* dvar_cg_unlockall_loot;
|
||||||
|
|
||||||
utils::hook::detour loot_getitemquantity_hook;
|
utils::hook::detour loot_getitemquantity_hook;
|
||||||
utils::hook::detour liveinventory_getitemquantity_hook;
|
utils::hook::detour liveinventory_getitemquantity_hook;
|
||||||
utils::hook::detour liveinventory_areextraslotspurchased_hook;
|
utils::hook::detour liveinventory_areextraslotspurchased_hook;
|
||||||
|
|
||||||
int loot_getitemquantity_stub(const game::ControllerIndex_t /*controller_index*/, const game::eModes mode,
|
int loot_getitemquantity_stub(const game::ControllerIndex_t controller_index, const game::eModes mode,
|
||||||
const int /*item_id*/)
|
const int item_id)
|
||||||
{
|
{
|
||||||
|
if (!dvar_cg_unlockall_loot->current.enabled)
|
||||||
|
{
|
||||||
|
return loot_getitemquantity_hook.invoke<int>(controller_index, mode, item_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == game::eModes::MODE_ZOMBIES)
|
if (mode == game::eModes::MODE_ZOMBIES)
|
||||||
{
|
{
|
||||||
return 999;
|
return 999;
|
||||||
@ -28,8 +35,8 @@ namespace loot
|
|||||||
int liveinventory_getitemquantity_stub(const game::ControllerIndex_t controller_index, const int item_id)
|
int liveinventory_getitemquantity_stub(const game::ControllerIndex_t controller_index, const int item_id)
|
||||||
{
|
{
|
||||||
// Item id's for extra CaC slots, CWL camo's and paid specialist outfits
|
// Item id's for extra CaC slots, CWL camo's and paid specialist outfits
|
||||||
if (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025 || item_id >= 90047 &&
|
if (dvar_cg_unlockall_loot->current.enabled && (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025||
|
||||||
item_id <= 90064)
|
item_id >= 90047 && item_id <= 90064))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -37,15 +44,14 @@ namespace loot
|
|||||||
return liveinventory_getitemquantity_hook.invoke<int>(controller_index, item_id);
|
return liveinventory_getitemquantity_hook.invoke<int>(controller_index, item_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool liveinventory_areextraslotspurchased_stub(const game::ControllerIndex_t /*controller_index*/)
|
bool liveinventory_areextraslotspurchased_stub(const game::ControllerIndex_t controller_index)
|
||||||
|
{
|
||||||
|
if (dvar_cg_unlockall_loot->current.enabled)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_dvars_on_startup()
|
return liveinventory_areextraslotspurchased_hook.invoke<bool>(controller_index);
|
||||||
{
|
|
||||||
game::Dvar_SetFromStringByName("ui_enableAllHeroes", "1", true);
|
|
||||||
game::Dvar_SetFromStringByName("ui_allLootUnlocked", "1", true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,10 +59,19 @@ namespace loot
|
|||||||
{
|
{
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
scheduler::once(set_dvars_on_startup, scheduler::pipeline::main);
|
dvar_cg_unlockall_loot = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_unlockall_loot"), "cg_unlockall_loot", false, (game::dvarFlags_e)0x0, "Unlocks blackmarket loot");
|
||||||
|
dvar_cg_unlockall_loot->debugName = "cg_unlockall_loot";
|
||||||
|
|
||||||
loot_getitemquantity_hook.create(0x141E82C90_g, loot_getitemquantity_stub);
|
loot_getitemquantity_hook.create(0x141E82C90_g, loot_getitemquantity_stub);
|
||||||
liveinventory_getitemquantity_hook.create(0x141E090C0_g, liveinventory_getitemquantity_stub);
|
liveinventory_getitemquantity_hook.create(0x141E090C0_g, liveinventory_getitemquantity_stub);
|
||||||
liveinventory_areextraslotspurchased_hook.create(0x141E089E0_g, liveinventory_areextraslotspurchased_stub);
|
liveinventory_areextraslotspurchased_hook.create(0x141E089E0_g, liveinventory_areextraslotspurchased_stub);
|
||||||
|
|
||||||
|
scheduler::once([]() {
|
||||||
|
if (dvar_cg_unlockall_loot->current.enabled)
|
||||||
|
{
|
||||||
|
game::Dvar_SetFromStringByName("ui_enableAllHeroes", "1", true);
|
||||||
|
}
|
||||||
|
}, scheduler::pipeline::dvars_loaded);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -91,11 +91,6 @@ namespace scheduler
|
|||||||
utils::hook::detour g_run_frame_hook;
|
utils::hook::detour g_run_frame_hook;
|
||||||
utils::hook::detour main_frame_hook;
|
utils::hook::detour main_frame_hook;
|
||||||
|
|
||||||
void execute(const pipeline type)
|
|
||||||
{
|
|
||||||
assert(type >= 0 && type < pipeline::count);
|
|
||||||
pipelines[type].execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void r_end_frame_stub()
|
void r_end_frame_stub()
|
||||||
{
|
{
|
||||||
@ -116,6 +111,12 @@ namespace scheduler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void execute(const pipeline type)
|
||||||
|
{
|
||||||
|
assert(type >= 0 && type < pipeline::count);
|
||||||
|
pipelines[type].execute();
|
||||||
|
}
|
||||||
|
|
||||||
void schedule(const std::function<bool()>& callback, const pipeline type,
|
void schedule(const std::function<bool()>& callback, const pipeline type,
|
||||||
const std::chrono::milliseconds delay)
|
const std::chrono::milliseconds delay)
|
||||||
{
|
{
|
||||||
|
@ -16,12 +16,17 @@ namespace scheduler
|
|||||||
// The game's main thread
|
// The game's main thread
|
||||||
main,
|
main,
|
||||||
|
|
||||||
|
// Dvars are done loading from the config file
|
||||||
|
dvars_loaded,
|
||||||
|
|
||||||
count,
|
count,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const bool cond_continue = false;
|
static const bool cond_continue = false;
|
||||||
static const bool cond_end = true;
|
static const bool cond_end = true;
|
||||||
|
|
||||||
|
void execute(const pipeline type);
|
||||||
|
|
||||||
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::async,
|
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::async,
|
||||||
std::chrono::milliseconds delay = 0ms);
|
std::chrono::milliseconds delay = 0ms);
|
||||||
void loop(const std::function<void()>& callback, pipeline type = pipeline::async,
|
void loop(const std::function<void()>& callback, pipeline type = pipeline::async,
|
||||||
|
483
src/client/component/ui_scripting.cpp
Normal file
483
src/client/component/ui_scripting.cpp
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include "game/ui_scripting/execution.hpp"
|
||||||
|
|
||||||
|
#include "command.hpp"
|
||||||
|
#include "ui_scripting.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/finally.hpp>
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::unordered_map<game::hks::cclosure*, std::function<arguments(const function_arguments& args)>> converted_functions;
|
||||||
|
|
||||||
|
utils::hook::detour ui_cod_init_hook;
|
||||||
|
utils::hook::detour ui_cod_lobbyui_init_hook;
|
||||||
|
utils::hook::detour ui_shutdown_hook;
|
||||||
|
utils::hook::detour hks_package_require_hook;
|
||||||
|
utils::hook::detour lua_cod_getrawfile_hook;
|
||||||
|
|
||||||
|
game::dvar_t* dvar_cg_enable_unsafe_lua_functions;
|
||||||
|
static bool unsafe_function_called_message_shown = false;
|
||||||
|
|
||||||
|
struct globals_t
|
||||||
|
{
|
||||||
|
std::string in_require_script;
|
||||||
|
std::unordered_map<std::string, std::string> loaded_scripts;
|
||||||
|
std::unordered_map<std::string, std::string> local_scripts;
|
||||||
|
bool load_raw_script{};
|
||||||
|
std::string raw_script_name{};
|
||||||
|
};
|
||||||
|
|
||||||
|
globals_t globals;
|
||||||
|
|
||||||
|
bool is_loaded_script(const std::string& name)
|
||||||
|
{
|
||||||
|
return globals.loaded_scripts.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_local_script(const std::string& name)
|
||||||
|
{
|
||||||
|
return globals.local_scripts.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_root_script(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto itr = globals.loaded_scripts.find(name);
|
||||||
|
return (itr == globals.loaded_scripts.end()) ? std::string() : itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
table get_globals()
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
return state->globals.v.table;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_error(const std::string& error)
|
||||||
|
{
|
||||||
|
printf("************** LUI script execution error **************\n");
|
||||||
|
printf("%s\n", error.data());
|
||||||
|
printf("********************************************************\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_loading_script(const std::string& name)
|
||||||
|
{
|
||||||
|
printf("Loading LUI script '%s'\n", name.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_current_script(game::hks::lua_State* state)
|
||||||
|
{
|
||||||
|
game::hks::lua_Debug info{};
|
||||||
|
game::hks::hksi_lua_getstack(state, 1, &info);
|
||||||
|
game::hks::hksi_lua_getinfo(state, "nSl", &info);
|
||||||
|
return info.short_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_buffer(const std::string& name, const std::string& data)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto sharing_mode = state->m_global->m_bytecodeSharingMode;
|
||||||
|
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||||
|
|
||||||
|
const auto _0 = utils::finally([&]
|
||||||
|
{
|
||||||
|
state->m_global->m_bytecodeSharingMode = sharing_mode;
|
||||||
|
});
|
||||||
|
|
||||||
|
game::hks::HksCompilerSettings compiler_settings{};
|
||||||
|
return game::hks::hksi_hksL_loadbuffer(state, &compiler_settings, data.data(), data.size(), name.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_script(const std::string& name, const std::string& data)
|
||||||
|
{
|
||||||
|
globals.loaded_scripts[name] = name;
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto lua = get_globals();
|
||||||
|
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||||
|
const auto load_results = lua["loadstring"](data, name);
|
||||||
|
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_SECURE;
|
||||||
|
|
||||||
|
if (load_results[0].is<function>())
|
||||||
|
{
|
||||||
|
const auto results = lua["pcall"](load_results);
|
||||||
|
if (!results[0].as<bool>())
|
||||||
|
{
|
||||||
|
print_error(results[1].as<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (load_results[1].is<std::string>())
|
||||||
|
{
|
||||||
|
print_error(load_results[1].as<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_local_script_files(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)
|
||||||
|
{
|
||||||
|
if (std::filesystem::is_regular_file(script))
|
||||||
|
{
|
||||||
|
const std::string file_path = script.substr(script.find("ui_scripts") + 11);
|
||||||
|
globals.local_scripts[file_path.c_str()] = script;
|
||||||
|
}
|
||||||
|
else if (std::filesystem::is_directory(script))
|
||||||
|
{
|
||||||
|
load_local_script_files(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_scripts(const std::string& script_dir)
|
||||||
|
{
|
||||||
|
if (!utils::io::directory_exists(script_dir))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_local_script_files(script_dir);
|
||||||
|
|
||||||
|
const auto scripts = utils::io::list_files(script_dir);
|
||||||
|
|
||||||
|
for (const auto& script : scripts)
|
||||||
|
{
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
if (std::filesystem::is_directory(script) && utils::io::read_file(script + "/__init__.lua", &data))
|
||||||
|
{
|
||||||
|
print_loading_script(script);
|
||||||
|
load_script(script + "/__init__.lua", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_functions()
|
||||||
|
{
|
||||||
|
const auto lua = get_globals();
|
||||||
|
|
||||||
|
using game = table;
|
||||||
|
auto game_type = game();
|
||||||
|
lua["game"] = game_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_globals()
|
||||||
|
{
|
||||||
|
const auto lua = get_globals();
|
||||||
|
const std::string code =
|
||||||
|
"local g = getmetatable(_G)\n"
|
||||||
|
"if not g then\n"
|
||||||
|
"g = {}\n"
|
||||||
|
"setmetatable(_G, g)\n"
|
||||||
|
"end\n"
|
||||||
|
"g.__newindex = nil\n";
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||||
|
lua["loadstring"](code)[0]();
|
||||||
|
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_SECURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
globals = {};
|
||||||
|
|
||||||
|
const auto lua = get_globals();
|
||||||
|
enable_globals();
|
||||||
|
|
||||||
|
setup_functions();
|
||||||
|
|
||||||
|
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x141D30290_g)); // hks::base_print
|
||||||
|
lua["table"]["unpack"] = lua["unpack"];
|
||||||
|
lua["luiglobals"] = lua;
|
||||||
|
|
||||||
|
utils::nt::library host{};
|
||||||
|
load_scripts(host.get_folder().append("/data/ui_scripts/").string());
|
||||||
|
load_scripts("boiii/ui_scripts/");
|
||||||
|
load_scripts("data/ui_scripts/");
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_start()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
printf("Failed to load LUI scripts: %s\n", ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_cod_init_stub(bool frontend)
|
||||||
|
{
|
||||||
|
ui_cod_init_hook.invoke(frontend);
|
||||||
|
|
||||||
|
if (game::Com_IsRunningUILevel())
|
||||||
|
{
|
||||||
|
// Fetch the names of the local files so file overrides are already handled
|
||||||
|
globals = {};
|
||||||
|
utils::nt::library host{};
|
||||||
|
load_local_script_files(host.get_folder().append("/data/ui_scripts/").string());
|
||||||
|
load_local_script_files("boiii/ui_scripts/");
|
||||||
|
load_local_script_files("data/ui_scripts/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto _0 = utils::finally(&try_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_cod_lobbyui_init_stub()
|
||||||
|
{
|
||||||
|
ui_cod_lobbyui_init_hook.invoke();
|
||||||
|
const auto _0 = utils::finally(&try_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_shutdown_stub()
|
||||||
|
{
|
||||||
|
converted_functions.clear();
|
||||||
|
globals = {};
|
||||||
|
return ui_shutdown_hook.invoke<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hks_package_require_stub(game::hks::lua_State* state)
|
||||||
|
{
|
||||||
|
const auto script = get_current_script(state);
|
||||||
|
const auto root = get_root_script(script);
|
||||||
|
globals.in_require_script = root;
|
||||||
|
return hks_package_require_hook.invoke<void*>(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hks_load_stub(game::hks::lua_State* state, void* compiler_options, void* reader, void* reader_data, void* debug_reader, void* debug_reader_data, const char* chunk_name)
|
||||||
|
{
|
||||||
|
if (globals.load_raw_script)
|
||||||
|
{
|
||||||
|
globals.load_raw_script = false;
|
||||||
|
globals.loaded_scripts[globals.raw_script_name] = globals.in_require_script;
|
||||||
|
return load_buffer(globals.raw_script_name, utils::io::read_file(globals.raw_script_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::hook::invoke<int>(0x141D3AFB0_g, state, compiler_options, reader, reader_data, debug_reader, debug_reader_data, chunk_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::XAssetHeader lua_cod_getrawfile_stub(char* filename)
|
||||||
|
{
|
||||||
|
game::XAssetHeader header{ .luaFile = nullptr };
|
||||||
|
|
||||||
|
if (!is_loaded_script(globals.in_require_script) && !is_local_script(filename))
|
||||||
|
{
|
||||||
|
return lua_cod_getrawfile_hook.invoke<game::XAssetHeader>(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string name_ = filename;
|
||||||
|
std::string target_script;
|
||||||
|
if (is_loaded_script(globals.in_require_script))
|
||||||
|
{
|
||||||
|
const auto folder = globals.in_require_script.substr(0, globals.in_require_script.find_last_of("/\\"));
|
||||||
|
target_script = folder + "/" + name_ + ".lua";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target_script = globals.local_scripts[name_];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils::io::file_exists(target_script))
|
||||||
|
{
|
||||||
|
globals.load_raw_script = true;
|
||||||
|
globals.raw_script_name = target_script;
|
||||||
|
header.luaFile = reinterpret_cast<game::LuaFile*>(1);
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lua_cod_getrawfile_hook.invoke<game::XAssetHeader>(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int luaopen_stub([[maybe_unused]] game::hks::lua_State* l)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lua_unsafe_function_stub([[maybe_unused]] game::hks::lua_State* l)
|
||||||
|
{
|
||||||
|
if (!unsafe_function_called_message_shown)
|
||||||
|
{
|
||||||
|
auto state = get_globals();
|
||||||
|
// TODO: Is it possible to do this with a confirm dialog? Doing this in LUI seems unsafe to me because mods will be able to change this aswell
|
||||||
|
state["LuaUtils"]["ShowMessageDialog"](0, 0, "The map/mod you are playing tried to run code that can be unsafe. This can include writing or reading files on your system, accessing environment variables, running system commands or loading a dll. These are usually used for storing data across games, integrating third party software like Discord or fetching data from a server to make the gameplay for dynamic.\nThis can also cause a lot of harm by the wrong people.\n\nIf you trust this map/mod and want to enable these features, open the following file in your Black Ops 3 installation: players/user/config.cfg.\nIn this file change 'set cg_enable_unsafe_lua_functions 0' to 'set cg_enable_unsafe_lua_functions 1' and restart Black Ops 3.", "Unsafe lua function called");
|
||||||
|
unsafe_function_called_message_shown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main_handler(game::hks::lua_State* state)
|
||||||
|
{
|
||||||
|
const auto value = state->m_apistack.base[-1];
|
||||||
|
if (value.t != game::hks::TCFUNCTION)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto closure = value.v.cClosure;
|
||||||
|
if (!converted_functions.contains(closure))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& function = converted_functions[closure];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto args = get_return_values();
|
||||||
|
const auto results = function(args);
|
||||||
|
|
||||||
|
for (const auto& result : results)
|
||||||
|
{
|
||||||
|
push_value(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(results.size());
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
game::hks::hksi_luaL_error(state, ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
game::hks::cclosure* convert_function(F f)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto closure = game::hks::cclosure_Create(state, main_handler, 0, 0, 0);
|
||||||
|
converted_functions[closure] = wrap_function(f);
|
||||||
|
return closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public client_component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
utils::hook::call(0x141D4979A_g, hks_load_stub);
|
||||||
|
|
||||||
|
hks_package_require_hook.create(0x141D28EF0_g, hks_package_require_stub);
|
||||||
|
ui_cod_init_hook.create(0x141F298B0_g, ui_cod_init_stub);
|
||||||
|
ui_cod_lobbyui_init_hook.create(0x141F2C620_g, ui_cod_lobbyui_init_stub);
|
||||||
|
ui_shutdown_hook.create(0x14270E9C0_g, ui_shutdown_stub);
|
||||||
|
lua_cod_getrawfile_hook.create(0x141F0F880_g, lua_cod_getrawfile_stub);
|
||||||
|
|
||||||
|
dvar_cg_enable_unsafe_lua_functions = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_enable_unsafe_lua_functions"), "cg_enable_unsafe_lua_functions", false, (game::dvarFlags_e)0x1000, "Enables the use of unsafe lua functions");
|
||||||
|
dvar_cg_enable_unsafe_lua_functions->debugName = "cg_enable_unsafe_lua_functions";
|
||||||
|
|
||||||
|
scheduler::once([]() {
|
||||||
|
game::dvar_t* dvar_callstack_ship = game::Dvar_FindVar("ui_error_callstack_ship");
|
||||||
|
dvar_callstack_ship->flags = (game::dvarFlags_e)0;
|
||||||
|
game::dvar_t* dvar_report_delay= game::Dvar_FindVar("ui_error_report_delay");
|
||||||
|
dvar_report_delay->flags = (game::dvarFlags_e)0;
|
||||||
|
|
||||||
|
game::Dvar_SetFromStringByName("ui_error_callstack_ship", "1", true);
|
||||||
|
game::Dvar_SetFromStringByName("ui_error_report_delay", "0", true);
|
||||||
|
}, scheduler::pipeline::renderer);
|
||||||
|
|
||||||
|
command::add("luiReload", [](auto& params)
|
||||||
|
{
|
||||||
|
auto frontend = game::Com_IsRunningUILevel();
|
||||||
|
|
||||||
|
if (frontend)
|
||||||
|
{
|
||||||
|
converted_functions.clear();
|
||||||
|
|
||||||
|
globals.loaded_scripts.clear();
|
||||||
|
globals.local_scripts.clear();
|
||||||
|
|
||||||
|
game::UI_CoD_Shutdown();
|
||||||
|
game::UI_CoD_Init(true);
|
||||||
|
|
||||||
|
// Com_LoadFrontEnd stripped
|
||||||
|
game::Lua_CoD_LoadLuaFile(*game::hks::lua_state, "ui_mp.T6.main");
|
||||||
|
game::UI_AddMenu(game::UI_CoD_GetRootNameForController(0), "main", -1, *game::hks::lua_state);
|
||||||
|
|
||||||
|
game::UI_CoD_LobbyUI_Init();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Find a way to do a full shutdown & restart like in frontend, that opens up the loading screen that can't be easily closed
|
||||||
|
game::CG_LUIHUDRestart(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scheduler::once([]() {
|
||||||
|
if (!dvar_cg_enable_unsafe_lua_functions->current.enabled)
|
||||||
|
{
|
||||||
|
// Do not allow the HKS vm to open LUA's libraries
|
||||||
|
// Disable unsafe functions
|
||||||
|
utils::hook::jump(0x141D34190_g, luaopen_stub); // debug
|
||||||
|
|
||||||
|
utils::hook::jump(0x141D300B0_g, lua_unsafe_function_stub); // base_loadfile
|
||||||
|
utils::hook::jump(0x141D31EE0_g, lua_unsafe_function_stub); // base_load
|
||||||
|
utils::hook::jump(0x141D2CF00_g, lua_unsafe_function_stub); // string_dump
|
||||||
|
utils::hook::jump(0x141FD3220_g, lua_unsafe_function_stub); // engine_openurl
|
||||||
|
|
||||||
|
utils::hook::jump(0x141D2AFF0_g, lua_unsafe_function_stub); // os_getenv
|
||||||
|
utils::hook::jump(0x141D2B790_g, lua_unsafe_function_stub); // os_exit
|
||||||
|
utils::hook::jump(0x141D2B7C0_g, lua_unsafe_function_stub); // os_remove
|
||||||
|
utils::hook::jump(0x141D2BB70_g, lua_unsafe_function_stub); // os_rename
|
||||||
|
utils::hook::jump(0x141D2B360_g, lua_unsafe_function_stub); // os_tmpname
|
||||||
|
utils::hook::jump(0x141D2B0F0_g, lua_unsafe_function_stub); // os_sleep
|
||||||
|
utils::hook::jump(0x141D2AF90_g, lua_unsafe_function_stub); // os_execute
|
||||||
|
utils::hook::jump(0x141D2AFF0_g, lua_unsafe_function_stub); // os_getenv
|
||||||
|
|
||||||
|
// io helpers
|
||||||
|
utils::hook::jump(0x141D32390_g, lua_unsafe_function_stub); // io_tostring
|
||||||
|
utils::hook::jump(0x141D2FDC0_g, lua_unsafe_function_stub); // io_close_file
|
||||||
|
utils::hook::jump(0x141D2FD50_g, lua_unsafe_function_stub); // io_flush
|
||||||
|
utils::hook::jump(0x141D31260_g, lua_unsafe_function_stub); // io_lines
|
||||||
|
utils::hook::jump(0x141D305C0_g, lua_unsafe_function_stub); // io_read_file
|
||||||
|
utils::hook::jump(0x141D305C0_g, lua_unsafe_function_stub); // io_read_file
|
||||||
|
utils::hook::jump(0x141D320A0_g, lua_unsafe_function_stub); // io_seek_file
|
||||||
|
utils::hook::jump(0x141D321E0_g, lua_unsafe_function_stub); // io_setvbuf
|
||||||
|
utils::hook::jump(0x141D2FCD0_g, lua_unsafe_function_stub); // io_write
|
||||||
|
// io functions
|
||||||
|
utils::hook::jump(0x141D2FD10_g, lua_unsafe_function_stub); // io_write
|
||||||
|
utils::hook::jump(0x141D30F40_g, lua_unsafe_function_stub); // io_read
|
||||||
|
utils::hook::jump(0x141D2FF00_g, lua_unsafe_function_stub); // io_close
|
||||||
|
utils::hook::jump(0x141D2FD90_g, lua_unsafe_function_stub); // io_flush
|
||||||
|
utils::hook::jump(0x141D313A0_g, lua_unsafe_function_stub); // io_lines
|
||||||
|
utils::hook::jump(0x141D31BA0_g, lua_unsafe_function_stub); // io_input
|
||||||
|
utils::hook::jump(0x141D31BC0_g, lua_unsafe_function_stub); // io_output
|
||||||
|
utils::hook::jump(0x141D31BE0_g, lua_unsafe_function_stub); // io_type
|
||||||
|
utils::hook::jump(0x141D31DD0_g, lua_unsafe_function_stub); // io_open
|
||||||
|
utils::hook::jump(0x141D31D70_g, lua_unsafe_function_stub); // io_tmpfile
|
||||||
|
utils::hook::jump(0x141D33C00_g, lua_unsafe_function_stub); // io_popen
|
||||||
|
|
||||||
|
utils::hook::jump(0x141D2D0C0_g, lua_unsafe_function_stub); // serialize_persist
|
||||||
|
utils::hook::jump(0x141D2D480_g, lua_unsafe_function_stub); // serialize_unpersist
|
||||||
|
|
||||||
|
utils::hook::jump(0x141D2F560_g, lua_unsafe_function_stub); // havokscript_compiler_settings
|
||||||
|
utils::hook::jump(0x141D2F660_g, lua_unsafe_function_stub); // havokscript_setgcweights
|
||||||
|
utils::hook::jump(0x141D2FB10_g, lua_unsafe_function_stub); // havokscript_getgcweights
|
||||||
|
|
||||||
|
utils::hook::jump(0x141D299C0_g, lua_unsafe_function_stub); // package_loadlib
|
||||||
|
}
|
||||||
|
}, scheduler::pipeline::dvars_loaded);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(ui_scripting::component)
|
47
src/client/component/ui_scripting.hpp
Normal file
47
src/client/component/ui_scripting.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
template <class... Args, std::size_t... I>
|
||||||
|
auto wrap_function(const std::function<void(Args...)>& f, std::index_sequence<I...>)
|
||||||
|
{
|
||||||
|
return [f](const function_arguments& args)
|
||||||
|
{
|
||||||
|
f(args[I]...);
|
||||||
|
return arguments{ {} };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args, std::size_t... I>
|
||||||
|
auto wrap_function(const std::function<arguments(Args...)>& f, std::index_sequence<I...>)
|
||||||
|
{
|
||||||
|
return [f](const function_arguments& args)
|
||||||
|
{
|
||||||
|
return f(args[I]...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R, class... Args, std::size_t... I>
|
||||||
|
auto wrap_function(const std::function<R(Args...)>& f, std::index_sequence<I...>)
|
||||||
|
{
|
||||||
|
return [f](const function_arguments& args)
|
||||||
|
{
|
||||||
|
return arguments{ f(args[I]...) };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R, class... Args>
|
||||||
|
auto wrap_function(const std::function<R(Args...)>& f)
|
||||||
|
{
|
||||||
|
return wrap_function(f, std::index_sequence_for<Args...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
auto wrap_function(F f)
|
||||||
|
{
|
||||||
|
return wrap_function(std::function(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
game::hks::cclosure* convert_function(F f);
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
|
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
#include <utils/nt.hpp>
|
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "structs.hpp"
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
size_t get_base();
|
size_t get_base();
|
||||||
|
@ -6,11 +6,6 @@
|
|||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
enum XAssetType
|
|
||||||
{
|
|
||||||
ASSET_TYPE_LEADERBOARD = 0x32,
|
|
||||||
ASSET_TYPE_DDL = 0x33,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ControllerIndex_t
|
enum ControllerIndex_t
|
||||||
{
|
{
|
||||||
@ -421,6 +416,126 @@ namespace game
|
|||||||
ERROR_SOFTRESTART_KEEPDW = 0x800,
|
ERROR_SOFTRESTART_KEEPDW = 0x800,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum XAssetType
|
||||||
|
{
|
||||||
|
ASSET_TYPE_PHYSPRESET = 0x0,
|
||||||
|
ASSET_TYPE_PHYSCONSTRAINTS = 0x1,
|
||||||
|
ASSET_TYPE_DESTRUCTIBLEDEF = 0x2,
|
||||||
|
ASSET_TYPE_XANIMPARTS = 0x3,
|
||||||
|
ASSET_TYPE_XMODEL = 0x4,
|
||||||
|
ASSET_TYPE_XMODELMESH = 0x5,
|
||||||
|
ASSET_TYPE_MATERIAL = 0x6,
|
||||||
|
ASSET_TYPE_COMPUTE_SHADER_SET = 0x7,
|
||||||
|
ASSET_TYPE_TECHNIQUE_SET = 0x8,
|
||||||
|
ASSET_TYPE_IMAGE = 0x9,
|
||||||
|
ASSET_TYPE_SOUND = 0xA,
|
||||||
|
ASSET_TYPE_SOUND_PATCH = 0xB,
|
||||||
|
ASSET_TYPE_CLIPMAP = 0xC,
|
||||||
|
ASSET_TYPE_COMWORLD = 0xD,
|
||||||
|
ASSET_TYPE_GAMEWORLD = 0xE,
|
||||||
|
ASSET_TYPE_MAP_ENTS = 0xF,
|
||||||
|
ASSET_TYPE_GFXWORLD = 0x10,
|
||||||
|
ASSET_TYPE_LIGHT_DEF = 0x11,
|
||||||
|
ASSET_TYPE_LENSFLARE_DEF = 0x12,
|
||||||
|
ASSET_TYPE_UI_MAP = 0x13,
|
||||||
|
ASSET_TYPE_FONT = 0x14,
|
||||||
|
ASSET_TYPE_FONTICON = 0x15,
|
||||||
|
ASSET_TYPE_LOCALIZE_ENTRY = 0x16,
|
||||||
|
ASSET_TYPE_WEAPON = 0x17,
|
||||||
|
ASSET_TYPE_WEAPONDEF = 0x18,
|
||||||
|
ASSET_TYPE_WEAPON_VARIANT = 0x19,
|
||||||
|
ASSET_TYPE_WEAPON_FULL = 0x1A,
|
||||||
|
ASSET_TYPE_CGMEDIA = 0x1B,
|
||||||
|
ASSET_TYPE_PLAYERSOUNDS = 0x1C,
|
||||||
|
ASSET_TYPE_PLAYERFX = 0x1D,
|
||||||
|
ASSET_TYPE_SHAREDWEAPONSOUNDS = 0x1E,
|
||||||
|
ASSET_TYPE_ATTACHMENT = 0x1F,
|
||||||
|
ASSET_TYPE_ATTACHMENT_UNIQUE = 0x20,
|
||||||
|
ASSET_TYPE_WEAPON_CAMO = 0x21,
|
||||||
|
ASSET_TYPE_CUSTOMIZATION_TABLE = 0x22,
|
||||||
|
ASSET_TYPE_CUSTOMIZATION_TABLE_FE_IMAGES = 0x23,
|
||||||
|
ASSET_TYPE_CUSTOMIZATION_TABLE_COLOR = 0x24,
|
||||||
|
ASSET_TYPE_SNDDRIVER_GLOBALS = 0x25,
|
||||||
|
ASSET_TYPE_FX = 0x26,
|
||||||
|
ASSET_TYPE_TAGFX = 0x27,
|
||||||
|
ASSET_TYPE_NEW_LENSFLARE_DEF = 0x28,
|
||||||
|
ASSET_TYPE_IMPACT_FX = 0x29,
|
||||||
|
ASSET_TYPE_IMPACT_SOUND = 0x2A,
|
||||||
|
ASSET_TYPE_PLAYER_CHARACTER = 0x2B,
|
||||||
|
ASSET_TYPE_AITYPE = 0x2C,
|
||||||
|
ASSET_TYPE_CHARACTER = 0x2D,
|
||||||
|
ASSET_TYPE_XMODELALIAS = 0x2E,
|
||||||
|
ASSET_TYPE_RAWFILE = 0x2F,
|
||||||
|
ASSET_TYPE_STRINGTABLE = 0x30,
|
||||||
|
ASSET_TYPE_STRUCTURED_TABLE = 0x31,
|
||||||
|
ASSET_TYPE_LEADERBOARD = 0x32,
|
||||||
|
ASSET_TYPE_DDL = 0x33,
|
||||||
|
ASSET_TYPE_GLASSES = 0x34,
|
||||||
|
ASSET_TYPE_TEXTURELIST = 0x35,
|
||||||
|
ASSET_TYPE_SCRIPTPARSETREE = 0x36,
|
||||||
|
ASSET_TYPE_KEYVALUEPAIRS = 0x37,
|
||||||
|
ASSET_TYPE_VEHICLEDEF = 0x38,
|
||||||
|
ASSET_TYPE_ADDON_MAP_ENTS = 0x39,
|
||||||
|
ASSET_TYPE_TRACER = 0x3A,
|
||||||
|
ASSET_TYPE_SLUG = 0x3B,
|
||||||
|
ASSET_TYPE_SURFACEFX_TABLE = 0x3C,
|
||||||
|
ASSET_TYPE_SURFACESOUNDDEF = 0x3D,
|
||||||
|
ASSET_TYPE_FOOTSTEP_TABLE = 0x3E,
|
||||||
|
ASSET_TYPE_ENTITYFXIMPACTS = 0x3F,
|
||||||
|
ASSET_TYPE_ENTITYSOUNDIMPACTS = 0x40,
|
||||||
|
ASSET_TYPE_ZBARRIER = 0x41,
|
||||||
|
ASSET_TYPE_VEHICLEFXDEF = 0x42,
|
||||||
|
ASSET_TYPE_VEHICLESOUNDDEF = 0x43,
|
||||||
|
ASSET_TYPE_TYPEINFO = 0x44,
|
||||||
|
ASSET_TYPE_SCRIPTBUNDLE = 0x45,
|
||||||
|
ASSET_TYPE_SCRIPTBUNDLELIST = 0x46,
|
||||||
|
ASSET_TYPE_RUMBLE = 0x47,
|
||||||
|
ASSET_TYPE_BULLETPENETRATION = 0x48,
|
||||||
|
ASSET_TYPE_LOCDMGTABLE = 0x49,
|
||||||
|
ASSET_TYPE_AIMTABLE = 0x4A,
|
||||||
|
ASSET_TYPE_ANIMSELECTORTABLESET = 0x4B,
|
||||||
|
ASSET_TYPE_ANIMMAPPINGTABLE = 0x4C,
|
||||||
|
ASSET_TYPE_ANIMSTATEMACHINE = 0x4D,
|
||||||
|
ASSET_TYPE_BEHAVIORTREE = 0x4E,
|
||||||
|
ASSET_TYPE_BEHAVIORSTATEMACHINE = 0x4F,
|
||||||
|
ASSET_TYPE_TTF = 0x50,
|
||||||
|
ASSET_TYPE_SANIM = 0x51,
|
||||||
|
ASSET_TYPE_LIGHT_DESCRIPTION = 0x52,
|
||||||
|
ASSET_TYPE_SHELLSHOCK = 0x53,
|
||||||
|
ASSET_TYPE_XCAM = 0x54,
|
||||||
|
ASSET_TYPE_BG_CACHE = 0x55,
|
||||||
|
ASSET_TYPE_TEXTURE_COMBO = 0x56,
|
||||||
|
ASSET_TYPE_FLAMETABLE = 0x57,
|
||||||
|
ASSET_TYPE_BITFIELD = 0x58,
|
||||||
|
ASSET_TYPE_ATTACHMENT_COSMETIC_VARIANT = 0x59,
|
||||||
|
ASSET_TYPE_MAPTABLE = 0x5A,
|
||||||
|
ASSET_TYPE_MAPTABLE_LOADING_IMAGES = 0x5B,
|
||||||
|
ASSET_TYPE_MEDAL = 0x5C,
|
||||||
|
ASSET_TYPE_MEDALTABLE = 0x5D,
|
||||||
|
ASSET_TYPE_OBJECTIVE = 0x5E,
|
||||||
|
ASSET_TYPE_OBJECTIVE_LIST = 0x5F,
|
||||||
|
ASSET_TYPE_UMBRA_TOME = 0x60,
|
||||||
|
ASSET_TYPE_NAVMESH = 0x61,
|
||||||
|
ASSET_TYPE_NAVVOLUME = 0x62,
|
||||||
|
ASSET_TYPE_BINARYHTML = 0x63,
|
||||||
|
ASSET_TYPE_LASER = 0x64,
|
||||||
|
ASSET_TYPE_BEAM = 0x65,
|
||||||
|
ASSET_TYPE_STREAMER_HINT = 0x66,
|
||||||
|
ASSET_TYPE_COUNT = 0x67,
|
||||||
|
ASSET_TYPE_STRING = 0x68,
|
||||||
|
ASSET_TYPE_ASSETLIST = 0x69,
|
||||||
|
ASSET_TYPE_REPORT = 0x6A,
|
||||||
|
ASSET_TYPE_DEPEND = 0x68,
|
||||||
|
ASSET_TYPE_FULL_COUNT = 0x6C,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LuaFile
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
int len;
|
||||||
|
const char* buffer;
|
||||||
|
};
|
||||||
|
|
||||||
struct XZoneBuffer
|
struct XZoneBuffer
|
||||||
{
|
{
|
||||||
const void* data;
|
const void* data;
|
||||||
@ -502,6 +617,23 @@ namespace game
|
|||||||
DVAR_TYPE_COUNT = 0x10,
|
DVAR_TYPE_COUNT = 0x10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dvarFlags_e
|
||||||
|
{
|
||||||
|
DVAR_ARCHIVE = 1 << 0,
|
||||||
|
DVAR_USERINFO = 1 << 1,
|
||||||
|
DVAR_SYSTEMINFO = 1 << 2,
|
||||||
|
DVAR_CODINFO = 1 << 3,
|
||||||
|
DVAR_LATCH = 1 << 4,
|
||||||
|
DVAR_ROM = 1 << 5,
|
||||||
|
DVAR_SAVED = 1 << 6,
|
||||||
|
DVAR_INIT = 1 << 7,
|
||||||
|
DVAR_CHEAT = 1 << 8,
|
||||||
|
//DVAR_UNKNOWN = 1 << 9,
|
||||||
|
DVAR_EXTERNAL = 1 << 10,
|
||||||
|
//DVAR_UNKNOWN3x = 1 << 11-13,
|
||||||
|
DVAR_SESSIONMODE = 1 << 15
|
||||||
|
};
|
||||||
|
|
||||||
typedef float vec_t;
|
typedef float vec_t;
|
||||||
|
|
||||||
union vec4_t
|
union vec4_t
|
||||||
@ -525,7 +657,6 @@ namespace game
|
|||||||
vec4_t vector;
|
vec4_t vector;
|
||||||
const char* string;
|
const char* string;
|
||||||
byte color[4];
|
byte color[4];
|
||||||
const dvar_t* indirect[3];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct $7034703ED3857507327AE195CCA24A71
|
struct $7034703ED3857507327AE195CCA24A71
|
||||||
@ -877,6 +1008,512 @@ namespace game
|
|||||||
JoinResult joinResult;
|
JoinResult joinResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace hks
|
||||||
|
{
|
||||||
|
struct lua_State;
|
||||||
|
struct HashTable;
|
||||||
|
struct StringTable;
|
||||||
|
struct cclosure;
|
||||||
|
typedef int hksBool;
|
||||||
|
typedef char hksChar;
|
||||||
|
typedef unsigned __int8 hksByte;
|
||||||
|
typedef __int16 hksShort16;
|
||||||
|
typedef unsigned __int16 hksUshort16;
|
||||||
|
typedef float HksNumber;
|
||||||
|
typedef int hksInt32;
|
||||||
|
typedef unsigned int hksUint32;
|
||||||
|
typedef __int64 hksInt64;
|
||||||
|
typedef unsigned __int64 hksUint64;
|
||||||
|
|
||||||
|
typedef int HksGcCost;
|
||||||
|
|
||||||
|
|
||||||
|
typedef size_t hksSize;
|
||||||
|
typedef void* (*lua_Alloc)(void*, void*, size_t, size_t);
|
||||||
|
typedef hksInt32(*lua_CFunction)(lua_State*);
|
||||||
|
|
||||||
|
struct GenericChunkHeader
|
||||||
|
{
|
||||||
|
hksSize m_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChunkHeader : GenericChunkHeader
|
||||||
|
{
|
||||||
|
ChunkHeader* m_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChunkList
|
||||||
|
{
|
||||||
|
ChunkHeader m_head;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserData : ChunkHeader
|
||||||
|
{
|
||||||
|
unsigned __int64 m_envAndSizeOffsetHighBits;
|
||||||
|
unsigned __int64 m_metaAndSizeOffsetLowBits;
|
||||||
|
char m_data[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InternString
|
||||||
|
{
|
||||||
|
unsigned __int64 m_flags;
|
||||||
|
unsigned __int64 m_lengthbits;
|
||||||
|
unsigned int m_hash;
|
||||||
|
char m_data[30];
|
||||||
|
};
|
||||||
|
|
||||||
|
union HksValue
|
||||||
|
{
|
||||||
|
cclosure* cClosure;
|
||||||
|
void* closure;
|
||||||
|
UserData* userData;
|
||||||
|
HashTable* table;
|
||||||
|
void* tstruct;
|
||||||
|
InternString* str;
|
||||||
|
void* thread;
|
||||||
|
void* ptr;
|
||||||
|
float number;
|
||||||
|
unsigned int native;
|
||||||
|
bool boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksObjectType
|
||||||
|
{
|
||||||
|
TANY = 0xFFFFFFFE,
|
||||||
|
TNONE = 0xFFFFFFFF,
|
||||||
|
TNIL = 0x0,
|
||||||
|
TBOOLEAN = 0x1,
|
||||||
|
TLIGHTUSERDATA = 0x2,
|
||||||
|
TNUMBER = 0x3,
|
||||||
|
TSTRING = 0x4,
|
||||||
|
TTABLE = 0x5,
|
||||||
|
TFUNCTION = 0x6, // idk
|
||||||
|
TUSERDATA = 0x7,
|
||||||
|
TTHREAD = 0x8,
|
||||||
|
TIFUNCTION = 0x9, // Lua function
|
||||||
|
TCFUNCTION = 0xA, // C function
|
||||||
|
TUI64 = 0xB,
|
||||||
|
TSTRUCT = 0xC,
|
||||||
|
NUM_TYPE_OBJECTS = 0xE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HksObject
|
||||||
|
{
|
||||||
|
HksObjectType t;
|
||||||
|
HksValue v;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hksInstruction
|
||||||
|
{
|
||||||
|
unsigned int code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActivationRecord
|
||||||
|
{
|
||||||
|
HksObject* m_base;
|
||||||
|
const hksInstruction* m_returnAddress;
|
||||||
|
__int16 m_tailCallDepth;
|
||||||
|
__int16 m_numVarargs;
|
||||||
|
int m_numExpectedReturns;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallStack
|
||||||
|
{
|
||||||
|
ActivationRecord* m_records;
|
||||||
|
ActivationRecord* m_lastrecord;
|
||||||
|
ActivationRecord* m_current;
|
||||||
|
const hksInstruction* m_current_lua_pc;
|
||||||
|
const hksInstruction* m_hook_return_addr;
|
||||||
|
int m_hook_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ApiStack
|
||||||
|
{
|
||||||
|
HksObject* top;
|
||||||
|
HksObject* base;
|
||||||
|
HksObject* alloc_top;
|
||||||
|
HksObject* bottom;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpValue : ChunkHeader
|
||||||
|
{
|
||||||
|
HksObject m_storage;
|
||||||
|
HksObject* loc;
|
||||||
|
UpValue* m_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallSite
|
||||||
|
{
|
||||||
|
_SETJMP_FLOAT128 m_jumpBuffer[16];
|
||||||
|
CallSite* m_prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
NEW = 0x1,
|
||||||
|
RUNNING = 0x2,
|
||||||
|
YIELDED = 0x3,
|
||||||
|
DEAD_ERROR = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksError
|
||||||
|
{
|
||||||
|
HKS_NO_ERROR = 0,
|
||||||
|
HKS_ERRSYNTAX = -4,
|
||||||
|
HKS_ERRFILE = -5,
|
||||||
|
HKS_ERRRUN = -100,
|
||||||
|
HKS_ERRMEM = -200,
|
||||||
|
HKS_ERRERR = -300,
|
||||||
|
HKS_THROWING_ERROR = -500,
|
||||||
|
HKS_GC_YIELD = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lua_Debug
|
||||||
|
{
|
||||||
|
int event;
|
||||||
|
const char* name;
|
||||||
|
const char* namewhat;
|
||||||
|
const char* what;
|
||||||
|
const char* source;
|
||||||
|
int currentline;
|
||||||
|
int nups;
|
||||||
|
int nparams;
|
||||||
|
int ishksfunc;
|
||||||
|
int linedefined;
|
||||||
|
int lastlinedefined;
|
||||||
|
char short_src[512];
|
||||||
|
int callstack_level;
|
||||||
|
int is_tail_call;
|
||||||
|
};
|
||||||
|
|
||||||
|
using lua_function = int(__fastcall*)(lua_State*);
|
||||||
|
|
||||||
|
struct luaL_Reg
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
lua_function function;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
HksObject m_key;
|
||||||
|
HksObject m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringPinner
|
||||||
|
{
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
InternString* m_strings[32];
|
||||||
|
Node* m_prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
lua_State* const m_state;
|
||||||
|
StringPinner* const m_prev;
|
||||||
|
InternString** m_nextStringsPlace;
|
||||||
|
Node m_firstNode;
|
||||||
|
Node* m_currentNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringTable
|
||||||
|
{
|
||||||
|
InternString** m_data;
|
||||||
|
unsigned int m_count;
|
||||||
|
unsigned int m_mask;
|
||||||
|
StringPinner* m_pinnedStrings;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Metatable
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HashTable : ChunkHeader
|
||||||
|
{
|
||||||
|
Metatable* m_meta;
|
||||||
|
unsigned int m_version;
|
||||||
|
unsigned int m_mask;
|
||||||
|
Node* m_hashPart;
|
||||||
|
HksObject* m_arrayPart;
|
||||||
|
unsigned int m_arraySize;
|
||||||
|
Node* m_freeNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cclosure : ChunkHeader
|
||||||
|
{
|
||||||
|
lua_function m_function;
|
||||||
|
HashTable* m_env;
|
||||||
|
__int16 m_numUpvalues;
|
||||||
|
__int16 m_flags;
|
||||||
|
InternString* m_name;
|
||||||
|
HksObject m_upvalues[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksCompilerSettings_BytecodeSharingFormat
|
||||||
|
{
|
||||||
|
BYTECODE_DEFAULT = 0x0,
|
||||||
|
BYTECODE_INPLACE = 0x1,
|
||||||
|
BYTECODE_REFERENCED = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksCompilerSettings_IntLiteralOptions
|
||||||
|
{
|
||||||
|
INT_LITERALS_NONE = 0x0,
|
||||||
|
INT_LITERALS_LUD = 0x1,
|
||||||
|
INT_LITERALS_32BIT = 0x1,
|
||||||
|
INT_LITERALS_UI64 = 0x2,
|
||||||
|
INT_LITERALS_64BIT = 0x2,
|
||||||
|
INT_LITERALS_ALL = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HksCompilerSettings
|
||||||
|
{
|
||||||
|
int m_emitStructCode;
|
||||||
|
const char** m_stripNames;
|
||||||
|
int m_emitGlobalMemoization;
|
||||||
|
int _m_isHksGlobalMemoTestingMode;
|
||||||
|
HksCompilerSettings_BytecodeSharingFormat m_bytecodeSharingFormat;
|
||||||
|
HksCompilerSettings_IntLiteralOptions m_enableIntLiterals;
|
||||||
|
int(*m_debugMap)(const char*, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksBytecodeSharingMode : __int64
|
||||||
|
{
|
||||||
|
HKS_BYTECODE_SHARING_OFF = 0,
|
||||||
|
HKS_BYTECODE_SHARING_ON = 1,
|
||||||
|
HKS_BYTECODE_SHARING_SECURE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HksGcWeights
|
||||||
|
{
|
||||||
|
int m_removeString;
|
||||||
|
int m_finalizeUserdataNoMM;
|
||||||
|
int m_finalizeUserdataGcMM;
|
||||||
|
int m_cleanCoroutine;
|
||||||
|
int m_removeWeak;
|
||||||
|
int m_markObject;
|
||||||
|
int m_traverseString;
|
||||||
|
int m_traverseUserdata;
|
||||||
|
int m_traverseCoroutine;
|
||||||
|
int m_traverseWeakTable;
|
||||||
|
int m_freeChunk;
|
||||||
|
int m_sweepTraverse;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GarbageCollector_Stack
|
||||||
|
{
|
||||||
|
void* m_storage;
|
||||||
|
unsigned int m_numEntries;
|
||||||
|
unsigned int m_numAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProtoList
|
||||||
|
{
|
||||||
|
void** m_protoList;
|
||||||
|
unsigned __int16 m_protoSize;
|
||||||
|
unsigned __int16 m_protoAllocSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemoryManager;
|
||||||
|
|
||||||
|
struct GarbageCollector
|
||||||
|
{
|
||||||
|
struct ResumeStack
|
||||||
|
{
|
||||||
|
void* m_storage;
|
||||||
|
hksInt32 m_numEntries;
|
||||||
|
hksUint32 m_numAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GreyStack
|
||||||
|
{
|
||||||
|
HksObject* m_storage;
|
||||||
|
hksSize m_numEntries;
|
||||||
|
hksSize m_numAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RemarkStack
|
||||||
|
{
|
||||||
|
HashTable** m_storage;
|
||||||
|
hksSize m_numAllocated;
|
||||||
|
hksSize m_numEntries;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeakStack_Entry
|
||||||
|
{
|
||||||
|
hksInt32 m_weakness;
|
||||||
|
HashTable* m_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeakStack
|
||||||
|
{
|
||||||
|
WeakStack_Entry* m_storage;
|
||||||
|
hksInt32 m_numEntries;
|
||||||
|
hksUint32 m_numAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
HksGcCost m_target;
|
||||||
|
HksGcCost m_stepsLeft;
|
||||||
|
HksGcCost m_stepLimit;
|
||||||
|
HksGcWeights m_costs;
|
||||||
|
HksGcCost m_unit;
|
||||||
|
void* m_jumpPoint;
|
||||||
|
lua_State* m_mainState;
|
||||||
|
lua_State* m_finalizerState;
|
||||||
|
MemoryManager* m_memory;
|
||||||
|
void* m_emergencyGCMemory;
|
||||||
|
hksInt32 m_phase;
|
||||||
|
ResumeStack m_resumeStack;
|
||||||
|
GreyStack m_greyStack;
|
||||||
|
RemarkStack m_remarkStack;
|
||||||
|
WeakStack m_weakStack;
|
||||||
|
hksBool m_finalizing;
|
||||||
|
HksObject m_safeTableValue;
|
||||||
|
lua_State* m_startOfStateStackList;
|
||||||
|
lua_State* m_endOfStateStackList;
|
||||||
|
lua_State* m_currentState;
|
||||||
|
HksObject m_safeValue;
|
||||||
|
void* m_compiler;
|
||||||
|
void* m_bytecodeReader;
|
||||||
|
void* m_bytecodeWriter;
|
||||||
|
hksInt32 m_pauseMultiplier;
|
||||||
|
HksGcCost m_stepMultiplier;
|
||||||
|
hksSize m_emergencyMemorySize;
|
||||||
|
bool m_stopped;
|
||||||
|
lua_CFunction m_gcPolicy;
|
||||||
|
hksSize m_pauseTriggerMemoryUsage;
|
||||||
|
hksInt32 m_stepTriggerCountdown;
|
||||||
|
hksUint32 m_stringTableIndex;
|
||||||
|
hksUint32 m_stringTableSize;
|
||||||
|
UserData* m_lastBlackUD;
|
||||||
|
UserData* m_activeUD;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemoryManager_ChunkColor
|
||||||
|
{
|
||||||
|
RED = 0x0,
|
||||||
|
BLACK = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Hks_DeleteCheckingMode
|
||||||
|
{
|
||||||
|
HKS_DELETE_CHECKING_OFF = 0x0,
|
||||||
|
HKS_DELETE_CHECKING_ACCURATE = 0x1,
|
||||||
|
HKS_DELETE_CHECKING_SAFE = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemoryManager
|
||||||
|
{
|
||||||
|
enum ChunkColor : __int32
|
||||||
|
{
|
||||||
|
WHITE = 0x0,
|
||||||
|
BLACK = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
lua_Alloc m_allocator;
|
||||||
|
void* m_allocatorUd;
|
||||||
|
ChunkColor m_chunkColor;
|
||||||
|
hksSize m_used;
|
||||||
|
hksSize m_highwatermark;
|
||||||
|
ChunkList m_allocationList;
|
||||||
|
ChunkList m_sweepList;
|
||||||
|
ChunkHeader* m_lastKeptChunk;
|
||||||
|
lua_State* m_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticStringCache
|
||||||
|
{
|
||||||
|
HksObject m_objects[41];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HksBytecodeEndianness
|
||||||
|
{
|
||||||
|
HKS_BYTECODE_DEFAULT_ENDIAN = 0x0,
|
||||||
|
HKS_BYTECODE_BIG_ENDIAN = 0x1,
|
||||||
|
HKS_BYTECODE_LITTLE_ENDIAN = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RuntimeProfileData_Stats
|
||||||
|
{
|
||||||
|
unsigned __int64 hksTime;
|
||||||
|
unsigned __int64 callbackTime;
|
||||||
|
unsigned __int64 gcTime;
|
||||||
|
unsigned __int64 cFinalizerTime;
|
||||||
|
unsigned __int64 compilerTime;
|
||||||
|
unsigned int hkssTimeSamples;
|
||||||
|
unsigned int callbackTimeSamples;
|
||||||
|
unsigned int gcTimeSamples;
|
||||||
|
unsigned int compilerTimeSamples;
|
||||||
|
unsigned int num_newuserdata;
|
||||||
|
unsigned int num_tablerehash;
|
||||||
|
unsigned int num_pushstring;
|
||||||
|
unsigned int num_pushcfunction;
|
||||||
|
unsigned int num_newtables;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RuntimeProfileData
|
||||||
|
{
|
||||||
|
__int64 stackDepth;
|
||||||
|
__int64 callbackDepth;
|
||||||
|
unsigned __int64 lastTimer;
|
||||||
|
RuntimeProfileData_Stats frameStats;
|
||||||
|
unsigned __int64 gcStartTime;
|
||||||
|
unsigned __int64 finalizerStartTime;
|
||||||
|
unsigned __int64 compilerStartTime;
|
||||||
|
unsigned __int64 compilerStartGCTime;
|
||||||
|
unsigned __int64 compilerStartGCFinalizerTime;
|
||||||
|
unsigned __int64 compilerCallbackStartTime;
|
||||||
|
__int64 compilerDepth;
|
||||||
|
void* outFile;
|
||||||
|
lua_State* rootState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HksGlobal
|
||||||
|
{
|
||||||
|
MemoryManager m_memory;
|
||||||
|
GarbageCollector m_collector;
|
||||||
|
StringTable m_stringTable;
|
||||||
|
__int64 padding3;
|
||||||
|
HksBytecodeSharingMode m_bytecodeSharingMode;
|
||||||
|
int padding;
|
||||||
|
HksObject m_registry;
|
||||||
|
ChunkList m_userDataList;
|
||||||
|
lua_State* m_root;
|
||||||
|
StaticStringCache m_staticStringCache;
|
||||||
|
void* m_debugger;
|
||||||
|
void* m_profiler;
|
||||||
|
RuntimeProfileData m_runProfilerData;
|
||||||
|
HksCompilerSettings m_compilerSettings;
|
||||||
|
int(*m_panicFunction)(lua_State*);
|
||||||
|
void* m_luaplusObjectList;
|
||||||
|
int m_heapAssertionFrequency;
|
||||||
|
int m_heapAssertionCount;
|
||||||
|
void (*m_logFunction)(lua_State*, const char*, ...);
|
||||||
|
void (*m_emergencyGCFailFunction)(lua_State*, size_t);
|
||||||
|
HksBytecodeEndianness m_bytecodeDumpEndianness;
|
||||||
|
int padding2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lua_State
|
||||||
|
{
|
||||||
|
ChunkHeader baseclass;
|
||||||
|
HksGlobal* m_global;
|
||||||
|
CallStack m_callStack;
|
||||||
|
ApiStack m_apistack;
|
||||||
|
UpValue* pending;
|
||||||
|
HksObject globals;
|
||||||
|
HksObject m_cEnv;
|
||||||
|
CallSite* m_callsites;
|
||||||
|
int m_numberOfCCalls;
|
||||||
|
void* m_context;
|
||||||
|
InternString* m_name;
|
||||||
|
lua_State* m_nextState;
|
||||||
|
lua_State* m_nextStateStack;
|
||||||
|
Status m_status;
|
||||||
|
HksError m_error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
typedef uint32_t ScrVarCanonicalName_t;
|
typedef uint32_t ScrVarCanonicalName_t;
|
||||||
|
|
||||||
enum svscmd_type
|
enum svscmd_type
|
||||||
@ -1019,6 +1656,7 @@ namespace game
|
|||||||
BeamDef* beamDef;
|
BeamDef* beamDef;
|
||||||
StreamerHint* streamerHint;*/
|
StreamerHint* streamerHint;*/
|
||||||
void* data;
|
void* data;
|
||||||
|
LuaFile* luaFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XAsset
|
struct XAsset
|
||||||
|
@ -21,13 +21,14 @@ namespace game
|
|||||||
WEAK symbol<void(int channel, unsigned int label, const char* fmt, ...)> Com_Printf{0x1421499C0, 0x140505630};
|
WEAK symbol<void(int channel, unsigned int label, const char* fmt, ...)> Com_Printf{0x1421499C0, 0x140505630};
|
||||||
WEAK symbol<void(const char* file, int line, int code, const char* fmt, ...)> Com_Error_{0x1420F8BD0};
|
WEAK symbol<void(const char* file, int line, int code, const char* fmt, ...)> Com_Error_{0x1420F8BD0};
|
||||||
WEAK symbol<bool(eModes mode)> Com_SessionMode_IsMode{0x1420F7DD0};
|
WEAK symbol<bool(eModes mode)> Com_SessionMode_IsMode{0x1420F7DD0};
|
||||||
|
WEAK symbol<bool()> Com_IsRunningUILevel{0x142148DB0};
|
||||||
WEAK symbol<void(uint32_t localClientNum, eModes fromMode, eModes toMode, uint32_t flags)> Com_SwitchMode{
|
WEAK symbol<void(uint32_t localClientNum, eModes fromMode, eModes toMode, uint32_t flags)> Com_SwitchMode{
|
||||||
0x14214AF30
|
0x14214AF30
|
||||||
};
|
};
|
||||||
|
|
||||||
WEAK symbol<void(uint32_t localClientNum, const char* text)> Cbuf_AddText{0x1420EC8B0, 0x1404F75B0};
|
WEAK symbol<void(uint32_t localClientNum, const char* text)> Cbuf_AddText{0x1420EC8B0, 0x1404F75B0};
|
||||||
WEAK symbol<void(int localClientNum, ControllerIndex_t controllerIndex, const char* buffer)> Cbuf_ExecuteBuffer{
|
WEAK symbol<void(int localClientNum, ControllerIndex_t controllerIndex, const char* buffer)> Cbuf_ExecuteBuffer{
|
||||||
0x0, 0x1404F78D0
|
0x14133BE10, 0x1404F78D0
|
||||||
};
|
};
|
||||||
WEAK symbol<void(const char* cmdName, xcommand_t function, cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{
|
WEAK symbol<void(const char* cmdName, xcommand_t function, cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{
|
||||||
0x1420ED530, 0x1404F8210
|
0x1420ED530, 0x1404F8210
|
||||||
@ -74,15 +75,33 @@ namespace game
|
|||||||
WEAK symbol<TLSData*()> Sys_IsDatabaseReady{0x1421844C0};
|
WEAK symbol<TLSData*()> Sys_IsDatabaseReady{0x1421844C0};
|
||||||
|
|
||||||
// Dvar
|
// Dvar
|
||||||
WEAK symbol<const dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730, 0x140575540};
|
WEAK symbol<dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730, 0x140575540};
|
||||||
WEAK symbol<unsigned int(const char* str)> Dvar_GenerateHash{0x14133DBF0};
|
WEAK symbol<unsigned int(const char* str)> Dvar_GenerateHash{0x14133DBF0};
|
||||||
WEAK symbol<dvar_t*(unsigned int hash)> Dvar_FindMalleableVar{0x1422BD6A0};
|
WEAK symbol<dvar_t*(unsigned int hash)> Dvar_FindMalleableVar{0x1422BD6A0};
|
||||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetDebugName{0x1422BDCB0};
|
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetDebugName{0x1422BDCB0};
|
||||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0, 0x140575E30};
|
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0, 0x140575E30};
|
||||||
|
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x1422BCAE0};
|
||||||
|
WEAK symbol<bool(const dvar_t* dvar)> Dvar_GetBool{ 0x1422BD930 };
|
||||||
|
WEAK symbol<dvar_t*(dvarStrHash_t hash, const char* dvarName, bool value, dvarFlags_e flags, const char* description)> Dvar_RegisterBool{
|
||||||
|
0x1422D1360
|
||||||
|
};
|
||||||
|
WEAK symbol<void (void (*callback)(const dvar_t*, void*), void* userData)> Dvar_ForEach{ 0x1422BD760 };
|
||||||
WEAK symbol<int(const dvar_t* dvar)> Dvar_GetInt{0x1422BF2C0, 0x140575C20};
|
WEAK symbol<int(const dvar_t* dvar)> Dvar_GetInt{0x1422BF2C0, 0x140575C20};
|
||||||
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
||||||
0x1422C7F60
|
0x1422C7F60
|
||||||
};
|
};
|
||||||
|
WEAK symbol<char> s_dvarPool{ 0x157AC8220 };
|
||||||
|
WEAK symbol<int> g_dvarCount{ 0x157AC81CC };
|
||||||
|
|
||||||
|
// UI
|
||||||
|
WEAK symbol<void(bool frontend)> UI_CoD_Init{ 0x141F298B0, 0x0 };
|
||||||
|
WEAK symbol<void()> UI_CoD_LobbyUI_Init{ 0x141F2C620, 0x0 };
|
||||||
|
WEAK symbol<void()> UI_CoD_Shutdown{ 0x141F336B0, 0x0 };
|
||||||
|
WEAK symbol<void(const char*, const char*, int, game::hks::lua_State*)> UI_AddMenu{ 0x1427024B0, 0x0 };
|
||||||
|
WEAK symbol<const char* (int)> UI_CoD_GetRootNameForController{ 0x141F291E0, 0x0 };
|
||||||
|
WEAK symbol<void(game::hks::lua_State*, const char*)> Lua_CoD_LoadLuaFile{ 0x141F122C0, 0x0 };
|
||||||
|
WEAK symbol<void(int localClientNum)> CG_LUIHUDRestart{ 0x140F7E970 };
|
||||||
|
WEAK symbol<void(int localClientNum)> CL_CheckKeepDrawingConnectScreen{ 0x1413CCAE0 };
|
||||||
|
|
||||||
// Scr
|
// Scr
|
||||||
WEAK symbol<void(scriptInstance_t inst, int value)> Scr_AddInt{0x0, 0x14016F160};
|
WEAK symbol<void(scriptInstance_t inst, int value)> Scr_AddInt{0x0, 0x14016F160};
|
||||||
@ -143,4 +162,24 @@ namespace game
|
|||||||
bool I_isupper(int c);
|
bool I_isupper(int c);
|
||||||
|
|
||||||
unsigned int Scr_CanonHash(const char* str);
|
unsigned int Scr_CanonHash(const char* str);
|
||||||
|
|
||||||
|
namespace hks
|
||||||
|
{
|
||||||
|
WEAK symbol<lua_State*> lua_state { 0x159C78D88 };
|
||||||
|
WEAK symbol<void(lua_State* s, const char* str, unsigned int l)> hksi_lua_pushlstring{ 0x140A18430 };
|
||||||
|
|
||||||
|
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)> hks_obj_settable{ 0x141D4B660 };
|
||||||
|
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{ 0x141D4ABF0 };
|
||||||
|
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{ 0x141D71070 };
|
||||||
|
WEAK symbol<HashTable* (lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{ 0x141D3B5F0 };
|
||||||
|
WEAK symbol<cclosure* (lua_State* s, lua_function function, int num_upvalues, int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{ 0x141D3B7E0 };
|
||||||
|
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{ 0x141D4D1A0 };
|
||||||
|
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{ 0x141D4D320 };
|
||||||
|
|
||||||
|
WEAK symbol<int(lua_State* s, const HksCompilerSettings* options, const char* buff, unsigned __int64 sz, const char* name)> hksi_hksL_loadbuffer{ 0x141D4BD80 };
|
||||||
|
WEAK symbol<int(lua_State* s, const char* what, lua_Debug* ar)> hksi_lua_getinfo{ 0x141D4D960 };
|
||||||
|
WEAK symbol<int(lua_State* s, int level, lua_Debug* ar)> hksi_lua_getstack{ 0x141D4DC20 };
|
||||||
|
WEAK symbol<void(lua_State* s, const char* fmt, ...)> hksi_luaL_error{ 0x141D4D050 };
|
||||||
|
WEAK symbol<const char*> s_compilerTypeName{ 0x140A18430 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
169
src/client/game/ui_scripting/execution.cpp
Normal file
169
src/client/game/ui_scripting/execution.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "execution.hpp"
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
script_value get_field(void* ptr, game::hks::HksObjectType type, const script_value& key)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(key);
|
||||||
|
|
||||||
|
game::hks::HksObject value{};
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = type;
|
||||||
|
obj.v.ptr = ptr;
|
||||||
|
|
||||||
|
game::hks::hks_obj_gettable(&value, state, &obj, &state->m_apistack.top[-1]);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_field(void* ptr, game::hks::HksObjectType type, const script_value& key, const script_value& value)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = type;
|
||||||
|
obj.v.ptr = ptr;
|
||||||
|
|
||||||
|
game::hks::hks_obj_settable(state, &obj, &key.get_raw(), &value.get_raw());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_value(const script_value& value)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
*state->m_apistack.top = value.get_raw();
|
||||||
|
state->m_apistack.top++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_value(const game::hks::HksObject& value)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
*state->m_apistack.top = value;
|
||||||
|
state->m_apistack.top++;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value get_return_value(std::int64_t offset)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
return state->m_apistack.top[-1 - offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments get_return_values()
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto count = state->m_apistack.top - state->m_apistack.base;
|
||||||
|
arguments values;
|
||||||
|
|
||||||
|
for (auto i = count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
values.push_back(get_return_value(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.empty())
|
||||||
|
{
|
||||||
|
values.push_back({});
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments get_return_values(game::hks::HksObject* base)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto count = state->m_apistack.top - base;
|
||||||
|
arguments values;
|
||||||
|
|
||||||
|
for (auto i = count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
values.push_back(get_return_value(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.empty())
|
||||||
|
{
|
||||||
|
values.push_back({});
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool notify(const std::string& name, const event_arguments& arguments)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
if (state == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const auto _0 = gsl::finally(game::LUI_LeaveCriticalSection);
|
||||||
|
//game::LUI_EnterCriticalSection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto globals = table((*::game::hks::lua_state)->globals.v.table);
|
||||||
|
const auto engine = globals.get("Engine").as<table>();
|
||||||
|
const auto root = engine.get("GetLuiRoot")()[0].as<userdata>();
|
||||||
|
const auto process_event = root.get("processEvent");
|
||||||
|
|
||||||
|
table event{};
|
||||||
|
event.set("name", name);
|
||||||
|
event.set("dispatchChildren", true);
|
||||||
|
|
||||||
|
for (const auto& arg : arguments)
|
||||||
|
{
|
||||||
|
event.set(arg.first, arg.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_event(root, event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
printf("Error processing event '%s' %s\n", name.data(), ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments call_script_function(const function& function, const arguments& arguments)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(function);
|
||||||
|
for (auto i = arguments.begin(); i != arguments.end(); ++i)
|
||||||
|
{
|
||||||
|
push_value(*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::hks::vm_call_internal(state, static_cast<int>(arguments.size()), -1, nullptr);
|
||||||
|
const auto args = get_return_values(top);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value get_field(const userdata& self, const script_value& key)
|
||||||
|
{
|
||||||
|
return get_field(self.ptr, game::hks::TUSERDATA, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value get_field(const table& self, const script_value& key)
|
||||||
|
{
|
||||||
|
return get_field(self.ptr, game::hks::TTABLE, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_field(const userdata& self, const script_value& key, const script_value& value)
|
||||||
|
{
|
||||||
|
set_field(self.ptr, game::hks::TUSERDATA, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_field(const table& self, const script_value& key, const script_value& value)
|
||||||
|
{
|
||||||
|
set_field(self.ptr, game::hks::TTABLE, key, value);
|
||||||
|
}
|
||||||
|
}
|
23
src/client/game/ui_scripting/execution.hpp
Normal file
23
src/client/game/ui_scripting/execution.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "script_value.hpp"
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
void push_value(const script_value& value);
|
||||||
|
void push_value(const game::hks::HksObject& value);
|
||||||
|
|
||||||
|
script_value get_return_value(std::int64_t offset);
|
||||||
|
arguments get_return_values();
|
||||||
|
arguments get_return_values(game::hks::HksObject* base);
|
||||||
|
|
||||||
|
bool notify(const std::string& name, const event_arguments& arguments);
|
||||||
|
|
||||||
|
arguments call_script_function(const function& function, const arguments& arguments);
|
||||||
|
|
||||||
|
script_value get_field(const userdata& self, const script_value& key);
|
||||||
|
script_value get_field(const table& self, const script_value& key);
|
||||||
|
void set_field(const userdata& self, const script_value& key, const script_value& value);
|
||||||
|
void set_field(const table& self, const script_value& key, const script_value& value);
|
||||||
|
}
|
400
src/client/game/ui_scripting/script_value.cpp
Normal file
400
src/client/game/ui_scripting/script_value.cpp
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "execution.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "script_value.hpp"
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
hks_object::hks_object(const game::hks::HksObject& value)
|
||||||
|
{
|
||||||
|
this->assign(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
hks_object::hks_object(const hks_object& other) noexcept
|
||||||
|
{
|
||||||
|
this->operator=(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
hks_object::hks_object(hks_object&& other) noexcept
|
||||||
|
{
|
||||||
|
this->operator=(std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
hks_object& hks_object::operator=(const hks_object& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->assign(other.value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
hks_object& hks_object::operator=(hks_object&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->value_ = other.value_;
|
||||||
|
other.value_.t = game::hks::TNONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
hks_object::~hks_object()
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
const game::hks::HksObject& hks_object::get() const
|
||||||
|
{
|
||||||
|
return this->value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hks_object::assign(const game::hks::HksObject& value)
|
||||||
|
{
|
||||||
|
this->value_ = value;
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(this->value_);
|
||||||
|
this->ref_ = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hks_object::release()
|
||||||
|
{
|
||||||
|
if (this->ref_)
|
||||||
|
{
|
||||||
|
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref_);
|
||||||
|
this->value_.t = game::hks::TNONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Constructors
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
script_value::script_value(const game::hks::HksObject& value)
|
||||||
|
: value_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const int value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TNUMBER;
|
||||||
|
obj.v.number = static_cast<float>(value);
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const unsigned int value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TNUMBER;
|
||||||
|
obj.v.number = static_cast<float>(value);
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const bool value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TBOOLEAN;
|
||||||
|
obj.v.boolean = value;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const float value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TNUMBER;
|
||||||
|
obj.v.number = static_cast<float>(value);
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const double value)
|
||||||
|
: script_value(static_cast<float>(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const char* value, const std::size_t len)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
if (state == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
game::hks::hksi_lua_pushlstring(state, value, static_cast<std::uint32_t>(len));
|
||||||
|
obj = state->m_apistack.top[-1];
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const char* value)
|
||||||
|
: script_value(value, std::strlen(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const std::string& value)
|
||||||
|
: script_value(value.data(), value.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const lightuserdata& value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TLIGHTUSERDATA;
|
||||||
|
obj.v.ptr = value.ptr;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const userdata& value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TUSERDATA;
|
||||||
|
obj.v.ptr = value.ptr;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const table& value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TTABLE;
|
||||||
|
obj.v.ptr = value.ptr;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value::script_value(const function& value)
|
||||||
|
{
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = value.type;
|
||||||
|
obj.v.ptr = value.ptr;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Integer
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<int>() const
|
||||||
|
{
|
||||||
|
const auto number = this->get_raw().v.number;
|
||||||
|
return this->get_raw().t == game::hks::TNUMBER && static_cast<int>(number) == number;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<unsigned int>() const
|
||||||
|
{
|
||||||
|
return this->is<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
int script_value::get() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(this->get_raw().v.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
unsigned int script_value::get() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(this->get_raw().v.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Boolean
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<bool>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TBOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Float
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<float>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TNUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<double>() const
|
||||||
|
{
|
||||||
|
return this->is<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
float script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
double script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* String
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<const char*>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TSTRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<std::string>() const
|
||||||
|
{
|
||||||
|
return this->is<const char*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const char* script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.str->m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get<const char*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Lightuserdata
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<lightuserdata>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TLIGHTUSERDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
lightuserdata script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Userdata
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<userdata>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TUSERDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
userdata script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Table
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<table>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
table script_value::get() const
|
||||||
|
{
|
||||||
|
return this->get_raw().v.table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Function
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<function>() const
|
||||||
|
{
|
||||||
|
return this->get_raw().t == game::hks::TIFUNCTION
|
||||||
|
|| this->get_raw().t == game::hks::TCFUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
function script_value::get() const
|
||||||
|
{
|
||||||
|
return { this->get_raw().v.cClosure, this->get_raw().t };
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
*
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
const game::hks::HksObject& script_value::get_raw() const
|
||||||
|
{
|
||||||
|
return this->value_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool script_value::operator==(const script_value& other) const
|
||||||
|
{
|
||||||
|
if (this->get_raw().t != other.get_raw().t)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->get_raw().t == game::hks::TSTRING)
|
||||||
|
{
|
||||||
|
return this->get<std::string>() == other.get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->get_raw().v.native == other.get_raw().v.native;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments script_value::operator()() const
|
||||||
|
{
|
||||||
|
return this->as<function>()();
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments script_value::operator()(const arguments& arguments) const
|
||||||
|
{
|
||||||
|
return this->as<function>()(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function_argument::function_argument(const arguments& args, const script_value& value, const int index)
|
||||||
|
: values_(args), value_(value), index_(index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function_arguments::function_arguments(const arguments& values)
|
||||||
|
: values_(values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
251
src/client/game/ui_scripting/script_value.hpp
Normal file
251
src/client/game/ui_scripting/script_value.hpp
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
class lightuserdata;
|
||||||
|
class userdata_value;
|
||||||
|
class userdata;
|
||||||
|
class table_value;
|
||||||
|
class table;
|
||||||
|
class function;
|
||||||
|
class script_value;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string get_typename()
|
||||||
|
{
|
||||||
|
auto& info = typeid(T);
|
||||||
|
|
||||||
|
if (info == typeid(std::string) ||
|
||||||
|
info == typeid(const char*))
|
||||||
|
{
|
||||||
|
return "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(lightuserdata))
|
||||||
|
{
|
||||||
|
return "lightuserdata";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(userdata))
|
||||||
|
{
|
||||||
|
return "userdata";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(table))
|
||||||
|
{
|
||||||
|
return "table";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(function))
|
||||||
|
{
|
||||||
|
return "function";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(int) ||
|
||||||
|
info == typeid(float) ||
|
||||||
|
info == typeid(unsigned int))
|
||||||
|
{
|
||||||
|
return "number";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == typeid(bool))
|
||||||
|
{
|
||||||
|
return "boolean";
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
class hks_object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
hks_object() = default;
|
||||||
|
hks_object(const game::hks::HksObject& value);
|
||||||
|
hks_object(const hks_object& other) noexcept;
|
||||||
|
hks_object(hks_object&& other) noexcept;
|
||||||
|
|
||||||
|
hks_object& operator=(const hks_object& other) noexcept;
|
||||||
|
hks_object& operator=(hks_object&& other) noexcept;
|
||||||
|
|
||||||
|
~hks_object();
|
||||||
|
|
||||||
|
const game::hks::HksObject& get() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void assign(const game::hks::HksObject& value);
|
||||||
|
void release();
|
||||||
|
|
||||||
|
game::hks::HksObject value_{ game::hks::TNONE, {} };
|
||||||
|
int ref_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
using arguments = std::vector<script_value>;
|
||||||
|
using event_arguments = std::unordered_map<std::string, script_value>;
|
||||||
|
|
||||||
|
class script_value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
script_value() = default;
|
||||||
|
script_value(const game::hks::HksObject& value);
|
||||||
|
|
||||||
|
script_value(int value);
|
||||||
|
script_value(unsigned int value);
|
||||||
|
script_value(bool value);
|
||||||
|
|
||||||
|
script_value(float value);
|
||||||
|
script_value(double value);
|
||||||
|
|
||||||
|
script_value(const char* value, std::size_t len);
|
||||||
|
script_value(const char* value);
|
||||||
|
script_value(const std::string& value);
|
||||||
|
|
||||||
|
script_value(const lightuserdata& value);
|
||||||
|
script_value(const userdata& value);
|
||||||
|
script_value(const table& value);
|
||||||
|
script_value(const function& value);
|
||||||
|
|
||||||
|
template <template<class, class> class C, class T, typename TableType = table>
|
||||||
|
script_value(const C<T, std::allocator<T>>& container)
|
||||||
|
{
|
||||||
|
TableType table_{};
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
for (const auto& value : container)
|
||||||
|
{
|
||||||
|
table_.set(index++, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::hks::HksObject obj{};
|
||||||
|
obj.t = game::hks::TTABLE;
|
||||||
|
obj.v.ptr = table_.ptr;
|
||||||
|
|
||||||
|
this->value_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
script_value(F f)
|
||||||
|
: script_value(function(f))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const script_value& other) const;
|
||||||
|
|
||||||
|
arguments operator()() const;
|
||||||
|
arguments operator()(const arguments& arguments) const;
|
||||||
|
|
||||||
|
template<class ...T>
|
||||||
|
arguments operator()(T... arguments) const
|
||||||
|
{
|
||||||
|
return this->as<function>().call({ arguments... });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Size>
|
||||||
|
table_value operator[](const char(&key)[Size]) const
|
||||||
|
{
|
||||||
|
return { this->as<table>(), key };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = script_value>
|
||||||
|
table_value operator[](const T& key) const
|
||||||
|
{
|
||||||
|
return { this->as<table>(), key };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] bool is() const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T as() const
|
||||||
|
{
|
||||||
|
if (!this->is<T>())
|
||||||
|
{
|
||||||
|
const auto hks_typename = game::hks::s_compilerTypeName[this->get_raw().t + 2];
|
||||||
|
const auto typename_ = get_typename<T>();
|
||||||
|
|
||||||
|
throw std::runtime_error(utils::string::va("%s expected, got %s", typename_.data(), hks_typename));
|
||||||
|
}
|
||||||
|
|
||||||
|
return get<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
operator T() const
|
||||||
|
{
|
||||||
|
return this->as<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const game::hks::HksObject& get_raw() const;
|
||||||
|
|
||||||
|
hks_object value_{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
T get() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class variadic_args : public arguments
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class function_argument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
function_argument(const arguments& args, const script_value& value, const int index);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T as() const
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return this->value_.as<T>();
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(utils::string::va("bad argument #%d (%s)", this->index_ + 1, e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
variadic_args as() const
|
||||||
|
{
|
||||||
|
variadic_args args{};
|
||||||
|
for (auto i = this->index_; i < this->values_.size(); i++)
|
||||||
|
{
|
||||||
|
args.push_back(this->values_[i]);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
operator T() const
|
||||||
|
{
|
||||||
|
return this->as<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
arguments values_{};
|
||||||
|
script_value value_{};
|
||||||
|
int index_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class function_arguments
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
function_arguments(const arguments& values);
|
||||||
|
|
||||||
|
function_argument operator[](const int index) const
|
||||||
|
{
|
||||||
|
if (static_cast<std::size_t>(index) >= values_.size())
|
||||||
|
{
|
||||||
|
return { values_, {}, index };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { values_, values_[index], index };
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
arguments values_{};
|
||||||
|
};
|
||||||
|
}
|
351
src/client/game/ui_scripting/types.cpp
Normal file
351
src/client/game/ui_scripting/types.cpp
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "execution.hpp"
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
/***************************************************************
|
||||||
|
* Lightuserdata
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
lightuserdata::lightuserdata(void* ptr_)
|
||||||
|
: ptr(ptr_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Userdata
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
userdata::userdata(void* ptr_)
|
||||||
|
: ptr(ptr_)
|
||||||
|
{
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata::userdata(const userdata& other)
|
||||||
|
{
|
||||||
|
this->operator=(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata::userdata(userdata&& other) noexcept
|
||||||
|
{
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata::~userdata()
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata& userdata::operator=(const userdata& other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata& userdata::operator=(userdata&& other) noexcept
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void userdata::add()
|
||||||
|
{
|
||||||
|
game::hks::HksObject value{};
|
||||||
|
value.v.ptr = this->ptr;
|
||||||
|
value.t = game::hks::TUSERDATA;
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(value);
|
||||||
|
|
||||||
|
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void userdata::release()
|
||||||
|
{
|
||||||
|
if (this->ref)
|
||||||
|
{
|
||||||
|
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void userdata::set(const script_value& key, const script_value& value) const
|
||||||
|
{
|
||||||
|
set_field(*this, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value userdata::get(const script_value& key) const
|
||||||
|
{
|
||||||
|
return get_field(*this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata_value userdata::operator[](const script_value& key) const
|
||||||
|
{
|
||||||
|
return { *this, key };
|
||||||
|
}
|
||||||
|
|
||||||
|
userdata_value::userdata_value(const userdata& table, const script_value& key)
|
||||||
|
: userdata_(table), key_(key)
|
||||||
|
{
|
||||||
|
this->value_ = this->userdata_.get(key).get_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void userdata_value::operator=(const script_value& value)
|
||||||
|
{
|
||||||
|
this->userdata_.set(this->key_, value);
|
||||||
|
this->value_ = value.get_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool userdata_value::operator==(const script_value& value)
|
||||||
|
{
|
||||||
|
return this->userdata_.get(this->key_) == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Table
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
table::table()
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
this->ptr = game::hks::Hashtable_Create(state, 0, 0);
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
table::table(game::hks::HashTable* ptr_)
|
||||||
|
: ptr(ptr_)
|
||||||
|
{
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
table::table(const table& other)
|
||||||
|
{
|
||||||
|
this->operator=(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
table::table(table&& other) noexcept
|
||||||
|
{
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table::~table()
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
table& table::operator=(const table& other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
table& table::operator=(table&& other) noexcept
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void table::add()
|
||||||
|
{
|
||||||
|
game::hks::HksObject value{};
|
||||||
|
value.v.table = this->ptr;
|
||||||
|
value.t = game::hks::TTABLE;
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(value);
|
||||||
|
|
||||||
|
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void table::release()
|
||||||
|
{
|
||||||
|
if (this->ref)
|
||||||
|
{
|
||||||
|
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void table::set(const script_value& key, const script_value& value) const
|
||||||
|
{
|
||||||
|
set_field(*this, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
table_value table::operator[](const script_value& key) const
|
||||||
|
{
|
||||||
|
return { *this, key };
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value table::get(const script_value& key) const
|
||||||
|
{
|
||||||
|
return get_field(*this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
table_value::table_value(const table& table, const script_value& key)
|
||||||
|
: table_(table), key_(key)
|
||||||
|
{
|
||||||
|
this->value_ = this->table_.get(key).get_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void table_value::operator=(const script_value& value)
|
||||||
|
{
|
||||||
|
this->table_.set(this->key_, value);
|
||||||
|
this->value_ = value.get_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void table_value::operator=(const table_value& value)
|
||||||
|
{
|
||||||
|
this->table_.set(this->key_, value);
|
||||||
|
this->value_ = value.get_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool table_value::operator==(const script_value& value)
|
||||||
|
{
|
||||||
|
return this->table_.get(this->key_) == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool table_value::operator==(const table_value& value)
|
||||||
|
{
|
||||||
|
return this->table_.get(this->key_) == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Function
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
function::function(game::hks::lua_function func)
|
||||||
|
{
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
this->ptr = game::hks::cclosure_Create(state, func, 0, 0, 0);
|
||||||
|
this->type = game::hks::HksObjectType::TCFUNCTION;
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_)
|
||||||
|
: ptr(ptr_), type(type_)
|
||||||
|
{
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
function::function(const function& other)
|
||||||
|
{
|
||||||
|
this->operator=(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
function::function(function&& other) noexcept
|
||||||
|
{
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->type = other.type;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function::~function()
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
function& function::operator=(const function& other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->type = other.type;
|
||||||
|
this->ref = other.ref;
|
||||||
|
this->add();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function& function::operator=(function&& other) noexcept
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
this->release();
|
||||||
|
this->ptr = other.ptr;
|
||||||
|
this->type = other.type;
|
||||||
|
this->ref = other.ref;
|
||||||
|
other.ref = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void function::add()
|
||||||
|
{
|
||||||
|
game::hks::HksObject value{};
|
||||||
|
value.v.cClosure = this->ptr;
|
||||||
|
value.t = this->type;
|
||||||
|
|
||||||
|
const auto state = *game::hks::lua_state;
|
||||||
|
const auto top = state->m_apistack.top;
|
||||||
|
|
||||||
|
push_value(value);
|
||||||
|
|
||||||
|
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||||
|
state->m_apistack.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void function::release()
|
||||||
|
{
|
||||||
|
if (this->ref)
|
||||||
|
{
|
||||||
|
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments function::call(const arguments& arguments) const
|
||||||
|
{
|
||||||
|
return call_script_function(*this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments function::operator()(const arguments& arguments) const
|
||||||
|
{
|
||||||
|
return this->call(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments function::operator()() const
|
||||||
|
{
|
||||||
|
return this->call({});
|
||||||
|
}
|
||||||
|
}
|
142
src/client/game/ui_scripting/types.hpp
Normal file
142
src/client/game/ui_scripting/types.hpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "script_value.hpp"
|
||||||
|
|
||||||
|
#include "component/ui_scripting.hpp"
|
||||||
|
|
||||||
|
namespace ui_scripting
|
||||||
|
{
|
||||||
|
class lightuserdata
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lightuserdata(void*);
|
||||||
|
void* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class userdata_value;
|
||||||
|
|
||||||
|
class userdata
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
userdata(void*);
|
||||||
|
|
||||||
|
userdata(const userdata& other);
|
||||||
|
userdata(userdata&& other) noexcept;
|
||||||
|
|
||||||
|
~userdata();
|
||||||
|
|
||||||
|
userdata& operator=(const userdata& other);
|
||||||
|
userdata& operator=(userdata&& other) noexcept;
|
||||||
|
|
||||||
|
script_value get(const script_value& key) const;
|
||||||
|
void set(const script_value& key, const script_value& value) const;
|
||||||
|
|
||||||
|
userdata_value operator[](const script_value& key) const;
|
||||||
|
|
||||||
|
void* ptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add();
|
||||||
|
void release();
|
||||||
|
|
||||||
|
int ref{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class userdata_value : public script_value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
userdata_value(const userdata& table, const script_value& key);
|
||||||
|
void operator=(const script_value& value);
|
||||||
|
bool operator==(const script_value& value);
|
||||||
|
private:
|
||||||
|
userdata userdata_;
|
||||||
|
script_value key_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class table_value;
|
||||||
|
|
||||||
|
class table
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
table();
|
||||||
|
table(game::hks::HashTable* ptr_);
|
||||||
|
|
||||||
|
table(const table& other);
|
||||||
|
table(table&& other) noexcept;
|
||||||
|
|
||||||
|
~table();
|
||||||
|
|
||||||
|
table& operator=(const table& other);
|
||||||
|
table& operator=(table&& other) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] script_value get(const script_value& key) const;
|
||||||
|
void set(const script_value& key, const script_value& value) const;
|
||||||
|
|
||||||
|
table_value operator[](const script_value& key) const;
|
||||||
|
|
||||||
|
game::hks::HashTable* ptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add();
|
||||||
|
void release();
|
||||||
|
|
||||||
|
int ref{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class table_value : public script_value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
table_value(const table& table, const script_value& key);
|
||||||
|
void operator=(const script_value& value);
|
||||||
|
void operator=(const table_value& value);
|
||||||
|
bool operator==(const script_value& value);
|
||||||
|
bool operator==(const table_value& value);
|
||||||
|
private:
|
||||||
|
table table_;
|
||||||
|
script_value key_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class function
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
function(game::hks::lua_function);
|
||||||
|
function(game::hks::cclosure*, game::hks::HksObjectType);
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
function(F f)
|
||||||
|
{
|
||||||
|
this->ptr = ui_scripting::convert_function(f);
|
||||||
|
this->type = game::hks::TCFUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
function(const function& other);
|
||||||
|
function(function&& other) noexcept;
|
||||||
|
|
||||||
|
~function();
|
||||||
|
|
||||||
|
function& operator=(const function& other);
|
||||||
|
function& operator=(function&& other) noexcept;
|
||||||
|
|
||||||
|
arguments call(const arguments& arguments) const;
|
||||||
|
|
||||||
|
arguments operator()(const arguments& arguments) const;
|
||||||
|
|
||||||
|
template<class ...T>
|
||||||
|
arguments operator()(T... arguments) const
|
||||||
|
{
|
||||||
|
return this->call({ arguments... });
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments operator()() const;
|
||||||
|
|
||||||
|
game::hks::cclosure* ptr;
|
||||||
|
game::hks::HksObjectType type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add();
|
||||||
|
void release();
|
||||||
|
|
||||||
|
int ref{};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user