mirror of
https://github.com/XLabsProject/s1x-client.git
synced 2023-08-02 15:02:12 +02:00
Merge pull request #376 from fedddddd/lui-scripting-
Use builtin lua compiler
This commit is contained in:
commit
4948fdfadb
@ -2,5 +2,5 @@ if (game:issingleplayer()) then
|
||||
return
|
||||
end
|
||||
|
||||
include("settings")
|
||||
include("hud")
|
||||
require("settings")
|
||||
require("hud")
|
@ -1,4 +1,4 @@
|
||||
local mphud = luiglobals.require("LUI.mp_hud.MPHud")
|
||||
local mphud = require("LUI.mp_hud.MPHud")
|
||||
local barheight = 18
|
||||
local textheight = 13
|
||||
local textoffsety = barheight / 2 - textheight / 2
|
||||
@ -71,10 +71,10 @@ function infoelement(data)
|
||||
g = 0.3,
|
||||
b = 0.3,
|
||||
},
|
||||
material = luiglobals.RegisterMaterial("distort_hud_bkgnd_ui_blur")
|
||||
material = RegisterMaterial("distort_hud_bkgnd_ui_blur")
|
||||
})
|
||||
|
||||
local labelfont = luiglobals.RegisterFont("fonts/bodyFontBold", textheight)
|
||||
local labelfont = RegisterFont("fonts/bodyFontBold", textheight)
|
||||
|
||||
local label = LUI.UIText.new({
|
||||
left = 5,
|
||||
@ -92,11 +92,11 @@ function infoelement(data)
|
||||
|
||||
label:setText(data.label)
|
||||
|
||||
local _, _, left = luiglobals.GetTextDimensions(data.label, labelfont, textheight)
|
||||
local _, _, left = GetTextDimensions(data.label, labelfont, textheight)
|
||||
local value = LUI.UIText.new({
|
||||
left = left + 5,
|
||||
top = textoffsety,
|
||||
font = luiglobals.RegisterFont("fonts/bodyFont", textheight),
|
||||
font = RegisterFont("fonts/bodyFont", textheight),
|
||||
height = textheight + 1,
|
||||
leftAnchor = true,
|
||||
topAnchor = true,
|
||||
@ -160,4 +160,4 @@ LUI.MenuBuilder.m_types_build["mp_hud"] = function()
|
||||
hud.static:addElement(infobar)
|
||||
|
||||
return hud
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
local pcoptions = luiglobals.require("LUI.PCOptions")
|
||||
local pcoptions = require("LUI.PCOptions")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_FPS", "FPS Counter")
|
||||
game:addlocalizedstring("LUA_MENU_FPS_DESC", "Show FPS Counter")
|
||||
@ -33,9 +33,9 @@ pcoptions.VideoOptionsFeeder = function()
|
||||
"profileMenuOption_blacklevel",
|
||||
"@MENU_BRIGHTNESS",
|
||||
"@MENU_BRIGHTNESS_DESC1",
|
||||
luiglobals.SliderBounds.PCBrightness.Min,
|
||||
luiglobals.SliderBounds.PCBrightness.Max,
|
||||
luiglobals.SliderBounds.PCBrightness.Step,
|
||||
SliderBounds.PCBrightness.Min,
|
||||
SliderBounds.PCBrightness.Max,
|
||||
SliderBounds.PCBrightness.Step,
|
||||
function(element)
|
||||
element:processEvent({
|
||||
name = "brightness_over",
|
||||
@ -143,7 +143,7 @@ pcoptions.VideoOptionsFeeder = function()
|
||||
type = "UIGenericButton",
|
||||
id = "option_advanced_video",
|
||||
properties = {
|
||||
style = luiglobals.GenericButtonSettings.Styles.GlassButton,
|
||||
style = GenericButtonSettings.Styles.GlassButton,
|
||||
button_text = Engine.Localize("@LUA_MENU_ADVANCED_VIDEO"),
|
||||
desc_text = "",
|
||||
button_action_func = pcoptions.ButtonMenuAction,
|
||||
|
@ -2,13 +2,13 @@ if (game:issingleplayer() or Engine.InFrontend()) then
|
||||
return
|
||||
end
|
||||
|
||||
function luiglobals.GetPartyMaxPlayers()
|
||||
function GetPartyMaxPlayers()
|
||||
return Engine.GetDvarInt("sv_maxclients")
|
||||
end
|
||||
|
||||
local scoreboard = LUI.mp_hud.Scoreboard
|
||||
|
||||
scoreboard.maxPlayersOnTeam = luiglobals.GetTeamLimitForMaxPlayers(luiglobals.GetPartyMaxPlayers())
|
||||
scoreboard.maxPlayersOnTeam = GetTeamLimitForMaxPlayers(GetPartyMaxPlayers())
|
||||
|
||||
scoreboard.scoreColumns.ping = {
|
||||
width = Engine.IsZombiesMode() and 90 or 60,
|
||||
@ -23,7 +23,7 @@ scoreboard.getColumnsForCurrentGameMode = function(a1)
|
||||
local columns = getcolumns(a1)
|
||||
|
||||
if (Engine.IsZombiesMode()) then
|
||||
luiglobals.table.insert(columns, scoreboard.scoreColumns.ping)
|
||||
table.insert(columns, scoreboard.scoreColumns.ping)
|
||||
end
|
||||
|
||||
return columns
|
||||
|
@ -1,6 +1,6 @@
|
||||
if (not LUI.mp_menus) then
|
||||
if (game:issingleplayer() or not Engine.InFrontend()) then
|
||||
return
|
||||
end
|
||||
|
||||
include("lobby")
|
||||
include("serverlist")
|
||||
require("lobby")
|
||||
require("serverlist")
|
||||
|
@ -1,4 +1,4 @@
|
||||
local Lobby = luiglobals.Lobby
|
||||
local Lobby = Lobby
|
||||
local MPLobbyOnline = LUI.mp_menus.MPLobbyOnline
|
||||
local MenuData = LUI.mp_menus.MenuData
|
||||
|
||||
@ -6,79 +6,79 @@ game:addlocalizedstring("LUA_MENU_SERVERLIST", "Server List")
|
||||
game:addlocalizedstring("LUA_MENU_SERVERLIST_DESC", "Browse available servers.");
|
||||
|
||||
function LeaveLobby(a1)
|
||||
LUI.MarketingPanel.ClearViewedMessages({LUI.MarketingLocation.CaC, LUI.MarketingLocation.PlayOnline,
|
||||
LUI.MarketingLocation.CaO})
|
||||
LeaveXboxLive()
|
||||
LUI.FlowManager.RequestLeaveMenuByName("menu_xboxlive", nil, true)
|
||||
LUI.MarketingPanel.ClearViewedMessages({LUI.MarketingLocation.CaC, LUI.MarketingLocation.PlayOnline,
|
||||
LUI.MarketingLocation.CaO})
|
||||
LeaveXboxLive()
|
||||
LUI.FlowManager.RequestLeaveMenuByName("menu_xboxlive", nil, true)
|
||||
end
|
||||
|
||||
function menu_xboxlive(a1, a2)
|
||||
Engine.SetDvarBool("ui_opensummary", false)
|
||||
local menu = LUI.MPLobbyBase.new(a1, {
|
||||
menu_title = "@PLATFORM_UI_HEADER_PLAY_MP_CAPS",
|
||||
memberListState = Lobby.MemberListStates.Prelobby,
|
||||
has_new_item_usage_widget = true
|
||||
})
|
||||
Engine.SetDvarBool("ui_opensummary", false)
|
||||
local menu = LUI.MPLobbyBase.new(a1, {
|
||||
menu_title = "@PLATFORM_UI_HEADER_PLAY_MP_CAPS",
|
||||
memberListState = Lobby.MemberListStates.Prelobby,
|
||||
has_new_item_usage_widget = true
|
||||
})
|
||||
|
||||
menu:setClass(LUI.MPLobbyOnline)
|
||||
menu:setClass(LUI.MPLobbyOnline)
|
||||
|
||||
menu.handleGamepadButton = MPLobbyOnline.menu_xboxlive_handleGamepadButton
|
||||
if Engine.IsCoreMode() then
|
||||
menu:AddNewItemsWidget()
|
||||
end
|
||||
menu.handleGamepadButton = MPLobbyOnline.menu_xboxlive_handleGamepadButton
|
||||
if Engine.IsCoreMode() then
|
||||
menu:AddNewItemsWidget()
|
||||
end
|
||||
|
||||
local serverListButton = menu:AddButton("@LUA_MENU_SERVERLIST", function(a1, a2)
|
||||
LUI.FlowManager.RequestAddMenu(a1, "menu_systemlink_join", true, nil)
|
||||
end)
|
||||
serverListButton:setDisabledRefreshRate(500)
|
||||
if Engine.IsCoreMode() then
|
||||
menu:AddCACButton()
|
||||
menu:AddCAOButton()
|
||||
menu:AddArmoryButton()
|
||||
end
|
||||
local serverListButton = menu:AddButton("@LUA_MENU_SERVERLIST", function(a1, a2)
|
||||
LUI.FlowManager.RequestAddMenu(a1, "menu_systemlink_join", true, nil)
|
||||
end)
|
||||
serverListButton:setDisabledRefreshRate(500)
|
||||
if Engine.IsCoreMode() then
|
||||
menu:AddCACButton()
|
||||
menu:AddCAOButton()
|
||||
menu:AddArmoryButton()
|
||||
end
|
||||
|
||||
serverListButton = menu:AddButton("@MENU_PRIVATE_MATCH", MPLobbyOnline.OnPrivateMatch,
|
||||
MPLobbyOnline.disablePrivateMatchButton)
|
||||
serverListButton:rename("menu_xboxlive_private_match")
|
||||
serverListButton:setDisabledRefreshRate(500)
|
||||
if not Engine.IsCoreMode() then
|
||||
local leaderboardButton = menu:AddButton("@LUA_MENU_LEADERBOARD", "OpLeaderboardMain")
|
||||
leaderboardButton:rename("OperatorMenu_leaderboard")
|
||||
end
|
||||
serverListButton = menu:AddButton("@MENU_PRIVATE_MATCH", MPLobbyOnline.OnPrivateMatch,
|
||||
MPLobbyOnline.disablePrivateMatchButton)
|
||||
serverListButton:rename("menu_xboxlive_private_match")
|
||||
serverListButton:setDisabledRefreshRate(500)
|
||||
if not Engine.IsCoreMode() then
|
||||
local leaderboardButton = menu:AddButton("@LUA_MENU_LEADERBOARD", "OpLeaderboardMain")
|
||||
leaderboardButton:rename("OperatorMenu_leaderboard")
|
||||
end
|
||||
|
||||
if Engine.IsZombiesMode() then
|
||||
menu:AddButton("@ZOMBIES_MENU_MOVIES", "ZombiesMoviesMenu")
|
||||
end
|
||||
if Engine.IsZombiesMode() then
|
||||
menu:AddButton("@ZOMBIES_MENU_MOVIES", "ZombiesMoviesMenu")
|
||||
end
|
||||
|
||||
menu:AddOptionsButton()
|
||||
local natType = Lobby.GetNATType()
|
||||
if natType then
|
||||
menu:AddHelp({
|
||||
name = "add_button_helper_text",
|
||||
button_ref = "nat",
|
||||
helper_text = Engine.Localize("NETWORK_YOURNATTYPE", natType),
|
||||
side = "left",
|
||||
clickable = false
|
||||
})
|
||||
end
|
||||
if Engine.IsZombiesMode() then
|
||||
menu:AddZombiesStats(true)
|
||||
end
|
||||
menu:AddOptionsButton()
|
||||
local natType = Lobby.GetNATType()
|
||||
if natType then
|
||||
menu:AddHelp({
|
||||
name = "add_button_helper_text",
|
||||
button_ref = "nat",
|
||||
helper_text = Engine.Localize("NETWORK_YOURNATTYPE", natType),
|
||||
side = "left",
|
||||
clickable = false
|
||||
})
|
||||
end
|
||||
if Engine.IsZombiesMode() then
|
||||
menu:AddZombiesStats(true)
|
||||
end
|
||||
|
||||
menu.isSignInMenu = true
|
||||
menu:registerEventHandler("gain_focus", LUI.MPLobbyOnline.OnGainFocus)
|
||||
menu:registerEventHandler("player_joined", luiglobals.Cac.PlayerJoinedEvent)
|
||||
menu:registerEventHandler("exit_live_lobby", LeaveLobby)
|
||||
menu.isSignInMenu = true
|
||||
menu:registerEventHandler("gain_focus", LUI.MPLobbyOnline.OnGainFocus)
|
||||
menu:registerEventHandler("player_joined", Cac.PlayerJoinedEvent)
|
||||
menu:registerEventHandler("exit_live_lobby", LeaveLobby)
|
||||
|
||||
if luiglobals.PersistentBackground.IsCurrent(luiglobals.PersistentBackground.Variants.AARBackground) then
|
||||
luiglobals.PersistentBackground.Hide(luiglobals.PersistentBackground.Duration)
|
||||
end
|
||||
if PersistentBackground.IsCurrent(PersistentBackground.Variants.AARBackground) then
|
||||
PersistentBackground.Hide(PersistentBackground.Duration)
|
||||
end
|
||||
|
||||
if Engine.IsCoreMode() then
|
||||
Engine.ExecNow("eliteclan_refresh", Engine.GetFirstActiveController())
|
||||
end
|
||||
if Engine.IsCoreMode() then
|
||||
Engine.ExecNow("eliteclan_refresh", Engine.GetFirstActiveController())
|
||||
end
|
||||
|
||||
return menu
|
||||
return menu
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["menu_xboxlive"] = menu_xboxlive
|
||||
|
@ -1,10 +1,9 @@
|
||||
local Lobby = luiglobals.Lobby
|
||||
local SystemLinkJoinMenu = LUI.mp_menus.SystemLinkJoinMenu
|
||||
|
||||
if (not SystemLinkJoinMenu) then
|
||||
if (game:issingleplayer() or not Engine.InFrontend()) then
|
||||
return
|
||||
end
|
||||
|
||||
local SystemLinkJoinMenu = LUI.mp_menus.SystemLinkJoinMenu
|
||||
|
||||
game:addlocalizedstring("PLATFORM_SYSTEM_LINK_TITLE", "SERVER LIST")
|
||||
game:addlocalizedstring("MENU_NUMPLAYERS", "Players")
|
||||
game:addlocalizedstring("MENU_PING", "Ping")
|
||||
|
@ -1,5 +1,5 @@
|
||||
if (game:issingleplayer() or not Engine.InFrontend()) then
|
||||
return
|
||||
return
|
||||
end
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_STATS", "Stats")
|
||||
@ -7,11 +7,11 @@ game:addlocalizedstring("LUA_MENU_STATS_DESC", "Edit player stats settings.")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS", "Unlock All Items")
|
||||
game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS_DESC",
|
||||
"Whether items should be locked based on the player's stats or always unlocked.")
|
||||
"Whether items should be locked based on the player's stats or always unlocked.")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES", "Unlock All Classes")
|
||||
game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES_DESC",
|
||||
"Whether classes should be locked based on the player's stats or always unlocked.")
|
||||
"Whether classes should be locked based on the player's stats or always unlocked.")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_PRESTIGE", "Prestige")
|
||||
game:addlocalizedstring("LUA_MENU_PRESTIGE_DESC", "Edit prestige level.")
|
||||
@ -20,176 +20,176 @@ game:addlocalizedstring("LUA_MENU_RANK_DESC", "Edit rank.")
|
||||
|
||||
local armorybutton = LUI.MPLobbyBase.AddArmoryButton
|
||||
LUI.MPLobbyBase.AddArmoryButton = function(menu)
|
||||
armorybutton(menu)
|
||||
menu:AddButton("@LUA_MENU_STATS", function(a1, a2)
|
||||
LUI.FlowManager.RequestAddMenu(a1, "menu_stats", true, nil)
|
||||
end)
|
||||
armorybutton(menu)
|
||||
menu:AddButton("@LUA_MENU_STATS", function(a1, a2)
|
||||
LUI.FlowManager.RequestAddMenu(a1, "menu_stats", true, nil)
|
||||
end)
|
||||
end
|
||||
|
||||
-- button stuff for configuring
|
||||
function IsEnabled(dvar)
|
||||
local enabled = Engine.GetDvarBool(dvar)
|
||||
if enabled then
|
||||
return Engine.Localize("@LUA_MENU_ENABLED")
|
||||
end
|
||||
local enabled = Engine.GetDvarBool(dvar)
|
||||
if enabled then
|
||||
return Engine.Localize("@LUA_MENU_ENABLED")
|
||||
end
|
||||
|
||||
return Engine.Localize("@LUA_MENU_DISABLED")
|
||||
return Engine.Localize("@LUA_MENU_DISABLED")
|
||||
end
|
||||
|
||||
function ToggleEnable(dvar)
|
||||
local enabled = Engine.GetDvarBool(dvar)
|
||||
if enabled then
|
||||
Engine.SetDvarBool(dvar, false)
|
||||
else
|
||||
Engine.SetDvarBool(dvar, true)
|
||||
end
|
||||
local enabled = Engine.GetDvarBool(dvar)
|
||||
if enabled then
|
||||
Engine.SetDvarBool(dvar, false)
|
||||
else
|
||||
Engine.SetDvarBool(dvar, true)
|
||||
end
|
||||
end
|
||||
|
||||
function GoDirection(dvar, direction, callback)
|
||||
local value = Engine.GetDvarString(dvar)
|
||||
value = tonumber(value)
|
||||
local value = Engine.GetDvarString(dvar)
|
||||
value = tonumber(value)
|
||||
|
||||
-- get rank data
|
||||
local max = nil
|
||||
if (dvar == "ui_rank_level_") then
|
||||
max = luiglobals.Rank.GetMaxRank(CoD.PlayMode.Core)
|
||||
elseif (dvar == "ui_prestige_level") then
|
||||
max = luiglobals.Lobby.GetMaxPrestigeLevel()
|
||||
end
|
||||
-- get rank data
|
||||
local max = nil
|
||||
if (dvar == "ui_rank_level_") then
|
||||
max = Rank.GetMaxRank(CoD.PlayMode.Core)
|
||||
elseif (dvar == "ui_prestige_level") then
|
||||
max = Lobby.GetMaxPrestigeLevel()
|
||||
end
|
||||
|
||||
local new_value = nil
|
||||
if (direction == "down") then
|
||||
new_value = value - 1
|
||||
elseif (direction == "up") then
|
||||
new_value = value + 1
|
||||
end
|
||||
local new_value = nil
|
||||
if (direction == "down") then
|
||||
new_value = value - 1
|
||||
elseif (direction == "up") then
|
||||
new_value = value + 1
|
||||
end
|
||||
|
||||
-- checking to make sure its < 0 or > max
|
||||
if (new_value < 0) then
|
||||
new_value = max
|
||||
elseif (new_value > max) then
|
||||
new_value = 0
|
||||
end
|
||||
-- checking to make sure its < 0 or > max
|
||||
if (new_value < 0) then
|
||||
new_value = max
|
||||
elseif (new_value > max) then
|
||||
new_value = 0
|
||||
end
|
||||
|
||||
callback(new_value)
|
||||
callback(new_value)
|
||||
|
||||
Engine.SetDvarFromString(dvar, new_value .. "")
|
||||
Engine.SetDvarFromString(dvar, new_value .. "")
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.registerType("menu_stats", function(a1, a2)
|
||||
local menu = LUI.MenuTemplate.new(a1, {
|
||||
menu_title = Engine.ToUpperCase(Engine.Localize("@LUA_MENU_STATS")),
|
||||
menu_width = luiglobals.GenericMenuDims.menu_right_wide - luiglobals.GenericMenuDims.menu_left,
|
||||
menu_height = 548
|
||||
})
|
||||
local menu = LUI.MenuTemplate.new(a1, {
|
||||
menu_title = Engine.ToUpperCase(Engine.Localize("@LUA_MENU_STATS")),
|
||||
menu_width = GenericMenuDims.menu_right_wide - GenericMenuDims.menu_left,
|
||||
menu_height = 548
|
||||
})
|
||||
|
||||
menu:setClass(LUI.Options)
|
||||
menu.controller = a2.exclusiveController
|
||||
menu:setClass(LUI.Options)
|
||||
menu.controller = a2.exclusiveController
|
||||
|
||||
local itemsbutton = menu:AddButtonVariant(luiglobals.GenericButtonSettings.Variants.Select,
|
||||
"@LUA_MENU_UNLOCKALL_ITEMS", "@LUA_MENU_UNLOCKALL_ITEMS_DESC", function()
|
||||
return IsEnabled("cg_unlockall_items")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_items")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_items")
|
||||
end)
|
||||
local itemsbutton = menu:AddButtonVariant(GenericButtonSettings.Variants.Select,
|
||||
"@LUA_MENU_UNLOCKALL_ITEMS", "@LUA_MENU_UNLOCKALL_ITEMS_DESC", function()
|
||||
return IsEnabled("cg_unlockall_items")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_items")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_items")
|
||||
end)
|
||||
|
||||
local classesbutton = menu:AddButtonVariant(luiglobals.GenericButtonSettings.Variants.Select,
|
||||
"@LUA_MENU_UNLOCKALL_CLASSES", "@LUA_MENU_UNLOCKALL_CLASSES_DESC", function()
|
||||
return IsEnabled("cg_unlockall_classes")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_classes")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_classes")
|
||||
end)
|
||||
local classesbutton = menu:AddButtonVariant(GenericButtonSettings.Variants.Select,
|
||||
"@LUA_MENU_UNLOCKALL_CLASSES", "@LUA_MENU_UNLOCKALL_CLASSES_DESC", function()
|
||||
return IsEnabled("cg_unlockall_classes")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_classes")
|
||||
end, function()
|
||||
ToggleEnable("cg_unlockall_classes")
|
||||
end)
|
||||
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0
|
||||
local rank = luiglobals.AAR.GetRankForXP(experience, prestige)
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0
|
||||
local rank = AAR.GetRankForXP(experience, prestige)
|
||||
|
||||
local prestigevalue = prestige
|
||||
local rankvalue = rank
|
||||
local prestigevalue = prestige
|
||||
local rankvalue = rank
|
||||
|
||||
-- save changes made
|
||||
local save_changes = function()
|
||||
Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige", tonumber(prestigevalue))
|
||||
-- save changes made
|
||||
local save_changes = function()
|
||||
Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige", tonumber(prestigevalue))
|
||||
|
||||
local rank = tonumber(rankvalue)
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = rank == 0 and 0 or luiglobals.Rank.GetRankMaxXP(tonumber(rankvalue) - 1, prestige)
|
||||
local rank = tonumber(rankvalue)
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = rank == 0 and 0 or Rank.GetRankMaxXP(tonumber(rankvalue) - 1, prestige)
|
||||
|
||||
Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience", experience)
|
||||
end
|
||||
Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience", experience)
|
||||
end
|
||||
|
||||
-- back callback
|
||||
local back = function()
|
||||
save_changes()
|
||||
LUI.common_menus.Options.HideOptionsBackground()
|
||||
LUI.FlowManager.RequestLeaveMenu(menu)
|
||||
end
|
||||
-- back callback
|
||||
local back = function()
|
||||
save_changes()
|
||||
LUI.common_menus.Options.HideOptionsBackground()
|
||||
LUI.FlowManager.RequestLeaveMenu(menu)
|
||||
end
|
||||
|
||||
-- create buttons and create callbacks
|
||||
CreateEditButton(menu, "ui_prestige_level", "@LUA_MENU_PRESTIGE", "@LUA_MENU_PRESTIGE_DESC", function(value)
|
||||
prestigevalue = value
|
||||
end)
|
||||
CreateEditButton(menu, "ui_rank_level_", "@LUA_MENU_RANK", "@LUA_MENU_RANK_DESC", function(value)
|
||||
rankvalue = value
|
||||
end)
|
||||
-- create buttons and create callbacks
|
||||
CreateEditButton(menu, "ui_prestige_level", "@LUA_MENU_PRESTIGE", "@LUA_MENU_PRESTIGE_DESC", function(value)
|
||||
prestigevalue = value
|
||||
end)
|
||||
CreateEditButton(menu, "ui_rank_level_", "@LUA_MENU_RANK", "@LUA_MENU_RANK_DESC", function(value)
|
||||
rankvalue = value
|
||||
end)
|
||||
|
||||
menu:AddBottomDescription(menu:InitScrolling())
|
||||
menu:AddBackButton(back)
|
||||
menu:AddBottomDescription(menu:InitScrolling())
|
||||
menu:AddBackButton(back)
|
||||
|
||||
LUI.common_menus.Options.ShowOptionsBackground()
|
||||
LUI.common_menus.Options.ShowOptionsBackground()
|
||||
|
||||
return menu
|
||||
return menu
|
||||
end)
|
||||
|
||||
function CreateEditButton(menu, dvar, name, desc, callback)
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0
|
||||
local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0
|
||||
local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0
|
||||
|
||||
local dvarValue = nil
|
||||
local max = nil
|
||||
if (dvar == "ui_rank_level_") then
|
||||
dvarValue = luiglobals.AAR.GetRankForXP(experience, prestige)
|
||||
max = luiglobals.Rank.GetMaxRank(CoD.PlayMode.Core)
|
||||
elseif (dvar == "ui_prestige_level") then
|
||||
dvarValue = prestige
|
||||
max = luiglobals.Lobby.GetMaxPrestigeLevel()
|
||||
end
|
||||
local dvarValue = nil
|
||||
local max = nil
|
||||
if (dvar == "ui_rank_level_") then
|
||||
dvarValue = AAR.GetRankForXP(experience, prestige)
|
||||
max = Rank.GetMaxRank(CoD.PlayMode.Core)
|
||||
elseif (dvar == "ui_prestige_level") then
|
||||
dvarValue = prestige
|
||||
max = Lobby.GetMaxPrestigeLevel()
|
||||
end
|
||||
|
||||
Engine.SetDvarFromString(dvar, dvarValue .. "")
|
||||
Engine.SetDvarFromString(dvar, dvarValue .. "")
|
||||
|
||||
menu:AddButtonVariant(luiglobals.GenericButtonSettings.Variants.Select, name, desc, function()
|
||||
local dvarString = Engine.GetDvarString(dvar)
|
||||
menu:AddButtonVariant(GenericButtonSettings.Variants.Select, name, desc, function()
|
||||
local dvarString = Engine.GetDvarString(dvar)
|
||||
|
||||
if (dvar == "ui_rank_level_") then
|
||||
dvarString = tonumber(dvarString) + 1
|
||||
end
|
||||
if (dvar == "ui_rank_level_") then
|
||||
dvarString = tonumber(dvarString) + 1
|
||||
end
|
||||
|
||||
return tostring(dvarString)
|
||||
end, function()
|
||||
GoDirection(dvar, "down", callback)
|
||||
end, function()
|
||||
GoDirection(dvar, "up", callback)
|
||||
end)
|
||||
return tostring(dvarString)
|
||||
end, function()
|
||||
GoDirection(dvar, "down", callback)
|
||||
end, function()
|
||||
GoDirection(dvar, "up", callback)
|
||||
end)
|
||||
end
|
||||
|
||||
local isclasslocked = luiglobals.Cac.IsCustomClassLocked
|
||||
luiglobals.Cac.IsCustomClassLocked = function(...)
|
||||
if (Engine.GetDvarBool("cg_unlockall_classes")) then
|
||||
return false
|
||||
end
|
||||
local isclasslocked = Cac.IsCustomClassLocked
|
||||
Cac.IsCustomClassLocked = function(...)
|
||||
if (Engine.GetDvarBool("cg_unlockall_classes")) then
|
||||
return false
|
||||
end
|
||||
|
||||
return isclasslocked(table.unpack({...}))
|
||||
return isclasslocked(table.unpack({...}))
|
||||
end
|
||||
|
||||
local isdlcclasslocked = luiglobals.Cac.IsCustomClassDlcLocked
|
||||
luiglobals.Cac.IsCustomClassDlcLocked = function(...)
|
||||
if (Engine.GetDvarBool("cg_unlockall_classes")) then
|
||||
return false
|
||||
end
|
||||
local isdlcclasslocked = Cac.IsCustomClassDlcLocked
|
||||
Cac.IsCustomClassDlcLocked = function(...)
|
||||
if (Engine.GetDvarBool("cg_unlockall_classes")) then
|
||||
return false
|
||||
end
|
||||
|
||||
return isdlcclasslocked(table.unpack({...}))
|
||||
return isdlcclasslocked(table.unpack({...}))
|
||||
end
|
||||
|
@ -174,6 +174,9 @@ namespace logger
|
||||
}
|
||||
|
||||
com_error_hook.create(game::Com_Error, com_error_stub);
|
||||
|
||||
// Make havok script's print function actually print
|
||||
utils::hook::jump(0x140701A1C, print);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -7,143 +7,350 @@
|
||||
#include "scheduler.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "ui_scripting.hpp"
|
||||
#include "localized_strings.hpp"
|
||||
#include "console.hpp"
|
||||
#include "game_module.hpp"
|
||||
#include "fps.hpp"
|
||||
|
||||
#include "game/ui_scripting/lua/engine.hpp"
|
||||
#include "game/ui_scripting/execution.hpp"
|
||||
#include "game/ui_scripting/lua/error.hpp"
|
||||
#include "game/scripting/execution.hpp"
|
||||
|
||||
#include "ui_scripting.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<game::hks::cclosure*, sol::protected_function> converted_functions;
|
||||
std::unordered_map<game::hks::cclosure*, std::function<arguments(const function_arguments& args)>> converted_functions;
|
||||
|
||||
utils::hook::detour hksi_lual_error_hook;
|
||||
utils::hook::detour hksi_lual_error_hook2;
|
||||
utils::hook::detour hks_start_hook;
|
||||
utils::hook::detour hks_shutdown_hook;
|
||||
utils::hook::detour hks_allocator_hook;
|
||||
utils::hook::detour hks_frame_hook;
|
||||
utils::hook::detour hks_package_require_hook;
|
||||
|
||||
bool error_hook_enabled = false;
|
||||
|
||||
void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...)
|
||||
struct script
|
||||
{
|
||||
char va_buffer[2048] = {0};
|
||||
std::string name;
|
||||
std::string root;
|
||||
};
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf_s(va_buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
struct globals_t
|
||||
{
|
||||
std::string in_require_script;
|
||||
std::vector<script> loaded_scripts;
|
||||
bool load_raw_script{};
|
||||
std::string raw_script_name{};
|
||||
};
|
||||
|
||||
const auto formatted = std::string(va_buffer);
|
||||
globals_t globals{};
|
||||
|
||||
if (!error_hook_enabled)
|
||||
bool is_loaded_script(const std::string& name)
|
||||
{
|
||||
for (auto i = globals.loaded_scripts.begin(); i != globals.loaded_scripts.end(); ++i)
|
||||
{
|
||||
return hksi_lual_error_hook.invoke<void>(s, formatted.data());
|
||||
if (i->name == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string get_root_script(const std::string& name)
|
||||
{
|
||||
for (auto i = globals.loaded_scripts.begin(); i != globals.loaded_scripts.end(); ++i)
|
||||
{
|
||||
throw std::runtime_error(formatted);
|
||||
if (i->name == name)
|
||||
{
|
||||
return i->root;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
table get_globals()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
return state->globals.v.table;
|
||||
}
|
||||
|
||||
void print_error(const std::string& error)
|
||||
{
|
||||
console::error("************** LUI script execution error **************\n");
|
||||
console::error("%s\n", error.data());
|
||||
console::error("********************************************************\n");
|
||||
}
|
||||
|
||||
void print_loading_script(const std::string& name)
|
||||
{
|
||||
console::info("Loading LUI script '%s'\n", name.data());
|
||||
}
|
||||
|
||||
std::string get_current_script()
|
||||
{
|
||||
const auto state = *game::hks::lua_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 = gsl::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.push_back({name, name});
|
||||
|
||||
const auto lua = get_globals();
|
||||
const auto load_results = lua["loadstring"](data, name);
|
||||
|
||||
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_scripts(const std::string& script_dir)
|
||||
{
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto scripts = utils::io::list_files(script_dir);
|
||||
|
||||
for (const auto& script : scripts)
|
||||
{
|
||||
std::string data{};
|
||||
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();
|
||||
|
||||
lua["io"]["fileexists"] = utils::io::file_exists;
|
||||
lua["io"]["writefile"] = utils::io::write_file;
|
||||
lua["io"]["movefile"] = utils::io::move_file;
|
||||
lua["io"]["filesize"] = utils::io::file_size;
|
||||
lua["io"]["createdirectory"] = utils::io::create_directory;
|
||||
lua["io"]["directoryexists"] = utils::io::directory_exists;
|
||||
lua["io"]["directoryisempty"] = utils::io::directory_is_empty;
|
||||
lua["io"]["listfiles"] = utils::io::list_files;
|
||||
lua["io"]["removefile"] = utils::io::remove_file;
|
||||
lua["io"]["readfile"] = static_cast<std::string(*)(const std::string&)>(utils::io::read_file);
|
||||
|
||||
using game = table;
|
||||
auto game_type = game();
|
||||
lua["game"] = game_type;
|
||||
|
||||
game_type["getfps"] = [](const game&)
|
||||
{
|
||||
return fps::get_fps();
|
||||
};
|
||||
|
||||
game_type["getping"] = [](const game&)
|
||||
{
|
||||
return *::game::mp::ping;
|
||||
};
|
||||
|
||||
game_type["issingleplayer"] = [](const game&)
|
||||
{
|
||||
return ::game::environment::is_sp();
|
||||
};
|
||||
|
||||
game_type["ismultiplayer"] = [](const game&)
|
||||
{
|
||||
return ::game::environment::is_mp();
|
||||
};
|
||||
|
||||
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
||||
const std::string& value)
|
||||
{
|
||||
localized_strings::override(string, value);
|
||||
};
|
||||
}
|
||||
|
||||
void enable_globals()
|
||||
{
|
||||
const auto lua = get_globals();
|
||||
const std::string script =
|
||||
"local g = getmetatable(_G)\n"
|
||||
"if not g then\n"
|
||||
"g = {}\n"
|
||||
"setmetatable(_G, g)\n"
|
||||
"end\n"
|
||||
"g.__newindex = nil\n";
|
||||
|
||||
lua["loadstring"](script)[0]();
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
globals = {};
|
||||
|
||||
const auto lua = get_globals();
|
||||
enable_globals();
|
||||
|
||||
setup_functions();
|
||||
|
||||
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14007CB70));
|
||||
lua["table"]["unpack"] = lua["unpack"];
|
||||
lua["luiglobals"] = lua;
|
||||
|
||||
load_scripts(game_module::get_host_module().get_folder() + "/data/ui_scripts/");
|
||||
load_scripts("s1x/ui_scripts/");
|
||||
load_scripts("data/ui_scripts/");
|
||||
}
|
||||
|
||||
void try_start()
|
||||
{
|
||||
try
|
||||
{
|
||||
start();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
console::error("Failed to load LUI scripts: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void* hks_start_stub(char a1)
|
||||
{
|
||||
const auto _1 = gsl::finally([]()
|
||||
{
|
||||
ui_scripting::lua::engine::start();
|
||||
});
|
||||
|
||||
const auto _0 = gsl::finally(&try_start);
|
||||
return hks_start_hook.invoke<void*>(a1);
|
||||
}
|
||||
|
||||
void hks_shutdown_stub()
|
||||
{
|
||||
ui_scripting::lua::engine::stop();
|
||||
hks_shutdown_hook.invoke<void*>();
|
||||
converted_functions.clear();
|
||||
globals = {};
|
||||
return hks_shutdown_hook.invoke<void>();
|
||||
}
|
||||
|
||||
void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize)
|
||||
void* hks_package_require_stub(game::hks::lua_State* state)
|
||||
{
|
||||
const auto closure = reinterpret_cast<game::hks::cclosure*>(oldMemory);
|
||||
if (converted_functions.find(closure) != converted_functions.end())
|
||||
const auto script = get_current_script();
|
||||
const auto root = get_root_script(script);
|
||||
globals.in_require_script = root;
|
||||
return hks_package_require_hook.invoke<void*>(state);
|
||||
}
|
||||
|
||||
game::XAssetHeader db_find_xasset_header_stub(game::XAssetType type, const char* name, int allow_create_default)
|
||||
{
|
||||
if (!is_loaded_script(globals.in_require_script))
|
||||
{
|
||||
converted_functions.erase(closure);
|
||||
return game::DB_FindXAssetHeader(type, name, allow_create_default);
|
||||
}
|
||||
|
||||
return hks_allocator_hook.invoke<void*>(userData, oldMemory, oldSize, newSize);
|
||||
const auto folder = globals.in_require_script.substr(0, globals.in_require_script.find_last_of("/\\"));
|
||||
const std::string name_ = name;
|
||||
const std::string target_script = folder + "/" + name_ + ".lua";
|
||||
|
||||
if (utils::io::file_exists(target_script))
|
||||
{
|
||||
globals.load_raw_script = true;
|
||||
globals.raw_script_name = target_script;
|
||||
return static_cast<game::XAssetHeader>(reinterpret_cast<game::LuaFile*>(1));
|
||||
}
|
||||
else if (name_.starts_with("ui/LUI/"))
|
||||
{
|
||||
return game::DB_FindXAssetHeader(type, name, allow_create_default);
|
||||
}
|
||||
|
||||
return static_cast<game::XAssetHeader>(nullptr);
|
||||
}
|
||||
|
||||
void hks_frame_stub()
|
||||
int hks_load_stub(game::hks::lua_State* state, void* compiler_options,
|
||||
void* reader, void* reader_data, const char* chunk_name)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
if (state)
|
||||
if (globals.load_raw_script)
|
||||
{
|
||||
ui_scripting::lua::engine::run_frame();
|
||||
globals.load_raw_script = false;
|
||||
globals.loaded_scripts.push_back({globals.raw_script_name, globals.in_require_script});
|
||||
return load_buffer(globals.raw_script_name, utils::io::read_file(globals.raw_script_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::hook::invoke<int>(0x14009CA10, state, compiler_options, reader,
|
||||
reader_data, chunk_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main_function_handler(game::hks::lua_State* state)
|
||||
{
|
||||
const auto value = state->m_apistack.base[-1];
|
||||
if (value.t != game::hks::TCFUNCTION)
|
||||
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.find(closure) == converted_functions.end())
|
||||
{
|
||||
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& e)
|
||||
{
|
||||
game::hks::hksi_luaL_error(state, e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto closure = value.v.cClosure;
|
||||
if (converted_functions.find(closure) == converted_functions.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto function = converted_functions[closure];
|
||||
const auto count = static_cast<int>(state->m_apistack.top - state->m_apistack.base);
|
||||
const auto arguments = get_return_values(count);
|
||||
const auto s = function.lua_state();
|
||||
|
||||
std::vector<sol::lua_value> converted_args;
|
||||
|
||||
for (const auto& argument : arguments)
|
||||
{
|
||||
converted_args.push_back(lua::convert(s, argument));
|
||||
}
|
||||
|
||||
const auto results = function(sol::as_args(converted_args));
|
||||
lua::handle_error(results);
|
||||
|
||||
for (const auto& result : results)
|
||||
{
|
||||
push_value(lua::convert({s, result}));
|
||||
}
|
||||
|
||||
return results.return_count();
|
||||
}
|
||||
|
||||
void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function)
|
||||
template <typename F>
|
||||
game::hks::cclosure* convert_function(F f)
|
||||
{
|
||||
converted_functions[closure] = function;
|
||||
}
|
||||
|
||||
void clear_converted_functions()
|
||||
{
|
||||
converted_functions.clear();
|
||||
}
|
||||
|
||||
void enable_error_hook()
|
||||
{
|
||||
error_hook_enabled = true;
|
||||
}
|
||||
|
||||
void disable_error_hook()
|
||||
{
|
||||
error_hook_enabled = false;
|
||||
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 component_interface
|
||||
@ -157,12 +364,13 @@ namespace ui_scripting
|
||||
return;
|
||||
}
|
||||
|
||||
utils::hook::call(0x1400CB68B, db_find_xasset_header_stub);
|
||||
utils::hook::call(0x1400CB7D6, db_find_xasset_header_stub);
|
||||
utils::hook::call(0x1400CB861, hks_load_stub);
|
||||
|
||||
hks_package_require_hook.create(0x1400781D0, hks_package_require_stub);
|
||||
hks_start_hook.create(0x1400E4E40, hks_start_stub);
|
||||
hks_shutdown_hook.create(0x1400DB9A0, hks_shutdown_stub);
|
||||
hksi_lual_error_hook.create(0x1400A03D0, hksi_lual_error_stub);
|
||||
hksi_lual_error_hook2.create(0x1400A77D0, hksi_lual_error_stub);
|
||||
hks_allocator_hook.create(0x14009C860, hks_allocator_stub);
|
||||
hks_frame_hook.create(0x1400E3910, hks_frame_stub);
|
||||
|
||||
command::add("lui_restart", []()
|
||||
{
|
||||
|
@ -1,12 +1,47 @@
|
||||
#pragma once
|
||||
#include "game/ui_scripting/lua/value_conversion.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
int main_function_handler(game::hks::lua_State* state);
|
||||
void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function);
|
||||
void clear_converted_functions();
|
||||
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{{}};
|
||||
};
|
||||
}
|
||||
|
||||
void enable_error_hook();
|
||||
void disable_error_hook();
|
||||
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);
|
||||
}
|
||||
|
@ -1496,6 +1496,10 @@ namespace game
|
||||
|
||||
namespace hks
|
||||
{
|
||||
struct lua_State;
|
||||
struct HashTable;
|
||||
struct cclosure;
|
||||
|
||||
struct GenericChunkHeader
|
||||
{
|
||||
unsigned __int64 m_flags;
|
||||
@ -1521,9 +1525,6 @@ namespace game
|
||||
char m_data[30];
|
||||
};
|
||||
|
||||
struct HashTable;
|
||||
struct cclosure;
|
||||
|
||||
union HksValue
|
||||
{
|
||||
cclosure* cClosure;
|
||||
@ -1535,6 +1536,8 @@ namespace game
|
||||
void* thread;
|
||||
void* ptr;
|
||||
float number;
|
||||
long long i64;
|
||||
unsigned long long ui64;
|
||||
unsigned int native;
|
||||
bool boolean;
|
||||
};
|
||||
@ -1620,6 +1623,14 @@ namespace game
|
||||
|
||||
enum HksError
|
||||
{
|
||||
HKS_NO_ERROR = 0x0,
|
||||
HKS_ERRSYNTAX = 0xFFFFFFFC,
|
||||
HKS_ERRFILE = 0xFFFFFFFB,
|
||||
HKS_ERRRUN = 0xFFFFFF9C,
|
||||
HKS_ERRMEM = 0xFFFFFF38,
|
||||
HKS_ERRERR = 0xFFFFFED4,
|
||||
HKS_THROWING_ERROR = 0xFFFFFE0C,
|
||||
HKS_GC_YIELD = 0x1,
|
||||
};
|
||||
|
||||
struct lua_Debug
|
||||
@ -1640,24 +1651,6 @@ namespace game
|
||||
int is_tail_call;
|
||||
};
|
||||
|
||||
struct lua_State : ChunkHeader
|
||||
{
|
||||
void* 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;
|
||||
};
|
||||
|
||||
using lua_function = int(__fastcall*)(lua_State*);
|
||||
|
||||
struct luaL_Reg
|
||||
@ -1696,5 +1689,231 @@ namespace game
|
||||
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(__fastcall* m_debugMap)(const char*, int);
|
||||
};
|
||||
|
||||
enum HksBytecodeSharingMode
|
||||
{
|
||||
HKS_BYTECODE_SHARING_OFF = 0x0,
|
||||
HKS_BYTECODE_SHARING_ON = 0x1,
|
||||
HKS_BYTECODE_SHARING_SECURE = 0x2,
|
||||
};
|
||||
|
||||
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 GarbageCollector
|
||||
{
|
||||
int m_target;
|
||||
int m_stepsLeft;
|
||||
int m_stepLimit;
|
||||
HksGcWeights m_costs;
|
||||
int m_unit;
|
||||
_SETJMP_FLOAT128(*m_jumpPoint)[16];
|
||||
lua_State* m_mainState;
|
||||
lua_State* m_finalizerState;
|
||||
void* m_memory;
|
||||
int m_phase;
|
||||
GarbageCollector_Stack m_resumeStack;
|
||||
GarbageCollector_Stack m_greyStack;
|
||||
GarbageCollector_Stack m_remarkStack;
|
||||
GarbageCollector_Stack m_weakStack;
|
||||
int 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;
|
||||
int m_pauseMultiplier;
|
||||
int m_stepMultiplier;
|
||||
bool m_stopped;
|
||||
int(__fastcall* m_gcPolicy)(lua_State*);
|
||||
unsigned __int64 m_pauseTriggerMemoryUsage;
|
||||
int m_stepTriggerCountdown;
|
||||
unsigned int m_stringTableIndex;
|
||||
unsigned int m_stringTableSize;
|
||||
UserData* m_lastBlackUD;
|
||||
UserData* m_activeUD;
|
||||
};
|
||||
|
||||
enum MemoryManager_ChunkColor
|
||||
{
|
||||
RED = 0x0,
|
||||
BLACK = 0x1,
|
||||
};
|
||||
|
||||
struct ChunkList
|
||||
{
|
||||
ChunkHeader m_prevToStart;
|
||||
};
|
||||
|
||||
enum Hks_DeleteCheckingMode
|
||||
{
|
||||
HKS_DELETE_CHECKING_OFF = 0x0,
|
||||
HKS_DELETE_CHECKING_ACCURATE = 0x1,
|
||||
HKS_DELETE_CHECKING_SAFE = 0x2,
|
||||
};
|
||||
|
||||
struct MemoryManager
|
||||
{
|
||||
void* (__fastcall* m_allocator)(void*, void*, unsigned __int64, unsigned __int64);
|
||||
void* m_allocatorUd;
|
||||
MemoryManager_ChunkColor m_chunkColor;
|
||||
unsigned __int64 m_used;
|
||||
unsigned __int64 m_highwatermark;
|
||||
ChunkList m_allocationList;
|
||||
ChunkList m_sweepList;
|
||||
ChunkHeader* m_lastKeptChunk;
|
||||
lua_State* m_state;
|
||||
ChunkList m_deletedList;
|
||||
int m_deleteMode;
|
||||
Hks_DeleteCheckingMode m_deleteCheckingMode;
|
||||
};
|
||||
|
||||
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;
|
||||
HksBytecodeSharingMode m_bytecodeSharingMode;
|
||||
unsigned int m_tableVersionInitializer;
|
||||
HksObject m_registry;
|
||||
ProtoList m_protoList;
|
||||
HashTable* m_structProtoByName;
|
||||
ChunkList m_userDataList;
|
||||
lua_State* m_root;
|
||||
StaticStringCache m_staticStringCache;
|
||||
void* m_debugger;
|
||||
void* m_profiler;
|
||||
RuntimeProfileData m_runProfilerData;
|
||||
HksCompilerSettings m_compilerSettings;
|
||||
int(__fastcall* m_panicFunction)(lua_State*);
|
||||
void* m_luaplusObjectList;
|
||||
int m_heapAssertionFrequency;
|
||||
int m_heapAssertionCount;
|
||||
void (*m_logFunction)(lua_State*, const char*, ...);
|
||||
HksBytecodeEndianness m_bytecodeDumpEndianness;
|
||||
};
|
||||
|
||||
struct lua_State : ChunkHeader
|
||||
{
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace game
|
||||
DB_EnumXAssets_Internal{0x14017D830, 0x14026EC80};
|
||||
WEAK symbol<XAssetEntry(XAssetType type, const char* name)>
|
||||
DB_FindXAssetEntry{0x14017D830, 0x14026F020};
|
||||
WEAK symbol<XAssetEntry(XAssetType type, const char *name, int allowCreateDefault)>
|
||||
WEAK symbol<XAssetHeader(XAssetType type, const char *name, int allowCreateDefault)>
|
||||
DB_FindXAssetHeader{0x14017DCA0, 0x14026F0F0};
|
||||
WEAK symbol<const char* (const XAsset* asset)> DB_GetXAssetName{0x140151C00, 0x140240DD0};
|
||||
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x140151C20, 0x140240DF0};
|
||||
@ -131,6 +131,8 @@ namespace game
|
||||
WEAK symbol<unsigned int(int)> Live_SyncOnlineDataFlags{0x1404459A0, 0x140562830};
|
||||
|
||||
WEAK symbol<void(int clientNum, const char* menu, int a3, int a4, unsigned int a5)> LUI_OpenMenu{0, 0x14048E450};
|
||||
WEAK symbol<void()> LUI_EnterCriticalSection{0, 0x1400D2B10};
|
||||
WEAK symbol<void()> LUI_LeaveCriticalSection{0, 0x1400D7620};
|
||||
|
||||
WEAK symbol<bool(int clientNum, const char* menu)> Menu_IsMenuOpenAndVisible{0, 0x140488570};
|
||||
|
||||
@ -303,5 +305,11 @@ namespace game
|
||||
int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0, 0x14008AD00};
|
||||
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{0, 0x1400A7D60};
|
||||
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{0, 0x1400A0660};
|
||||
WEAK symbol<int(lua_State* s, const HksCompilerSettings* options, const char* buff,
|
||||
unsigned __int64 sz, const char* name)> hksi_hksL_loadbuffer{0, 0x14009ECA0};
|
||||
WEAK symbol<int(lua_State* s, const char* what, lua_Debug* ar)> hksi_lua_getinfo{0, 0x1400A0C00};
|
||||
WEAK symbol<int(lua_State* s, int level, lua_Debug* ar)> hksi_lua_getstack{0, 0x1400A0EC0};
|
||||
WEAK symbol<void(lua_State* s, const char* fmt, ...)> hksi_luaL_error{0, 0x1400A03D0};
|
||||
WEAK symbol<const char*> typenames{0, 0x1409AB270};
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,54 @@
|
||||
#include <std_include.hpp>
|
||||
#include "execution.hpp"
|
||||
#include "component/ui_scripting.hpp"
|
||||
#include "component/console.hpp"
|
||||
|
||||
#include <utils/string.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;
|
||||
const auto value_ = value.get_raw();
|
||||
*state->m_apistack.top = value_;
|
||||
*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++;
|
||||
}
|
||||
|
||||
@ -20,13 +58,16 @@ namespace ui_scripting
|
||||
return state->m_apistack.top[-1 - offset];
|
||||
}
|
||||
|
||||
arguments get_return_values(int count)
|
||||
arguments get_return_values()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto count = static_cast<int>(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));
|
||||
const auto v = get_return_value(i);
|
||||
values.push_back(v);
|
||||
}
|
||||
|
||||
if (values.size() == 0)
|
||||
@ -37,10 +78,68 @@ namespace ui_scripting
|
||||
return values;
|
||||
}
|
||||
|
||||
arguments get_return_values(game::hks::HksObject* base)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto count = static_cast<int>(state->m_apistack.top - base);
|
||||
arguments values;
|
||||
|
||||
for (auto i = count - 1; i >= 0; i--)
|
||||
{
|
||||
const auto v = get_return_value(i);
|
||||
values.push_back(v);
|
||||
}
|
||||
|
||||
if (values.size() == 0)
|
||||
{
|
||||
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 _1 = 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& e)
|
||||
{
|
||||
console::error("Error processing event '%s' %s\n", name.data(), e.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
arguments call_script_function(const function& function, const arguments& arguments)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(function);
|
||||
for (auto i = arguments.begin(); i != arguments.end(); ++i)
|
||||
@ -48,114 +147,29 @@ namespace ui_scripting
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
|
||||
try
|
||||
{
|
||||
game::hks::vm_call_internal(state, static_cast<int>(arguments.size()), -1, 0);
|
||||
const auto count = static_cast<int>(state->m_apistack.top - state->m_apistack.base);
|
||||
return get_return_values(count);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error executing script function: ") + e.what());
|
||||
}
|
||||
game::hks::vm_call_internal(state, static_cast<int>(arguments.size()), -1, 0);
|
||||
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)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
|
||||
push_value(key);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
|
||||
game::hks::HksObject value{};
|
||||
game::hks::HksObject userdata{};
|
||||
userdata.t = game::hks::TUSERDATA;
|
||||
userdata.v.ptr = self.ptr;
|
||||
|
||||
try
|
||||
{
|
||||
game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]);
|
||||
return value;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error getting userdata field: ") + e.what());
|
||||
}
|
||||
return get_field(self.ptr, game::hks::TUSERDATA, key);
|
||||
}
|
||||
|
||||
script_value get_field(const table& self, const script_value& key)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
|
||||
push_value(key);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
|
||||
game::hks::HksObject value{};
|
||||
game::hks::HksObject userdata{};
|
||||
userdata.t = game::hks::TTABLE;
|
||||
userdata.v.ptr = self.ptr;
|
||||
|
||||
try
|
||||
{
|
||||
game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]);
|
||||
return value;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error getting table field: ") + e.what());
|
||||
}
|
||||
return get_field(self.ptr, game::hks::TTABLE, key);
|
||||
}
|
||||
|
||||
void set_field(const userdata& self, const script_value& key, const script_value& value)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
|
||||
game::hks::HksObject userdata{};
|
||||
userdata.t = game::hks::TUSERDATA;
|
||||
userdata.v.ptr = self.ptr;
|
||||
|
||||
try
|
||||
{
|
||||
game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error setting userdata field: ") + e.what());
|
||||
}
|
||||
set_field(self.ptr, game::hks::TUSERDATA, key, value);
|
||||
}
|
||||
|
||||
void set_field(const table& self, const script_value& key, const script_value& value)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
|
||||
game::hks::HksObject userdata{};
|
||||
userdata.t = game::hks::TTABLE;
|
||||
userdata.v.ptr = self.ptr;
|
||||
|
||||
try
|
||||
{
|
||||
game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error setting table field: ") + e.what());
|
||||
}
|
||||
set_field(self.ptr, game::hks::TTABLE, key, value);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,13 @@
|
||||
namespace ui_scripting
|
||||
{
|
||||
void push_value(const script_value& value);
|
||||
void push_value(const game::hks::HksObject& value);
|
||||
|
||||
script_value get_return_value(int offset);
|
||||
arguments get_return_values(int count);
|
||||
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);
|
||||
|
||||
|
@ -1,232 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "context.hpp"
|
||||
#include "error.hpp"
|
||||
#include "value_conversion.hpp"
|
||||
#include "../script_value.hpp"
|
||||
#include "../execution.hpp"
|
||||
|
||||
#include "../../../component/ui_scripting.hpp"
|
||||
#include "../../../component/command.hpp"
|
||||
#include "../../../component/fps.hpp"
|
||||
#include "../../../component/localized_strings.hpp"
|
||||
|
||||
#include "component/game_console.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void setup_types(sol::state& state, scheduler& scheduler)
|
||||
{
|
||||
struct game
|
||||
{
|
||||
};
|
||||
auto game_type = state.new_usertype<game>("game_");
|
||||
state["game"] = game();
|
||||
|
||||
game_type["ontimeout"] = [&scheduler](const game&, const sol::protected_function& callback,
|
||||
const long long milliseconds)
|
||||
{
|
||||
return scheduler.add(callback, milliseconds, true);
|
||||
};
|
||||
|
||||
game_type["oninterval"] = [&scheduler](const game&, const sol::protected_function& callback,
|
||||
const long long milliseconds)
|
||||
{
|
||||
return scheduler.add(callback, milliseconds, false);
|
||||
};
|
||||
|
||||
game_type["getfps"] = [](const game&)
|
||||
{
|
||||
return fps::get_fps();
|
||||
};
|
||||
|
||||
game_type["getping"] = [](const game&)
|
||||
{
|
||||
return *::game::mp::ping;
|
||||
};
|
||||
|
||||
game_type["issingleplayer"] = [](const game&)
|
||||
{
|
||||
return ::game::environment::is_sp();
|
||||
};
|
||||
|
||||
game_type["ismultiplayer"] = [](const game&)
|
||||
{
|
||||
return ::game::environment::is_mp();
|
||||
};
|
||||
|
||||
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
||||
const std::string& value)
|
||||
{
|
||||
localized_strings::override(string, value);
|
||||
};
|
||||
|
||||
auto userdata_type = state.new_usertype<userdata>("userdata_");
|
||||
|
||||
userdata_type["new"] = sol::property(
|
||||
[](const userdata& userdata, const sol::this_state s)
|
||||
{
|
||||
return convert(s, userdata.get("new"));
|
||||
},
|
||||
[](const userdata& userdata, const sol::this_state s, const sol::lua_value& value)
|
||||
{
|
||||
userdata.set("new", convert({s, value}));
|
||||
}
|
||||
);
|
||||
|
||||
userdata_type["get"] = [](const userdata& userdata, const sol::this_state s,
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, userdata.get(convert({s, key})));
|
||||
};
|
||||
|
||||
userdata_type["set"] = [](const userdata& userdata, const sol::this_state s,
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
userdata.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s,
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, userdata.get(convert({s, key})));
|
||||
};
|
||||
|
||||
userdata_type[sol::meta_function::new_index] = [](const userdata& userdata, const sol::this_state s,
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
userdata.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
auto table_type = state.new_usertype<table>("table_");
|
||||
|
||||
table_type["new"] = sol::property(
|
||||
[](const table& table, const sol::this_state s)
|
||||
{
|
||||
return convert(s, table.get("new"));
|
||||
},
|
||||
[](const table& table, const sol::this_state s, const sol::lua_value& value)
|
||||
{
|
||||
table.set("new", convert({s, value}));
|
||||
}
|
||||
);
|
||||
|
||||
table_type["get"] = [](const table& table, const sol::this_state s,
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, table.get(convert({s, key})));
|
||||
};
|
||||
|
||||
table_type["set"] = [](const table& table, const sol::this_state s,
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
table.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
table_type[sol::meta_function::index] = [](const table& table, const sol::this_state s,
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, table.get(convert({s, key})));
|
||||
};
|
||||
|
||||
table_type[sol::meta_function::new_index] = [](const table& table, const sol::this_state s,
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
table.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
auto function_type = state.new_usertype<function>("function_");
|
||||
|
||||
function_type[sol::meta_function::call] = [](const function& function, const sol::this_state s, sol::variadic_args va)
|
||||
{
|
||||
arguments arguments{};
|
||||
|
||||
for (auto arg : va)
|
||||
{
|
||||
arguments.push_back(convert({s, arg}));
|
||||
}
|
||||
|
||||
const auto values = function.call(arguments);
|
||||
std::vector<sol::lua_value> returns;
|
||||
|
||||
for (const auto& value : values)
|
||||
{
|
||||
returns.push_back(convert(s, value));
|
||||
}
|
||||
|
||||
return sol::as_returns(returns);
|
||||
};
|
||||
|
||||
state["luiglobals"] = table((*::game::hks::lua_state)->globals.v.table);
|
||||
state["CoD"] = state["luiglobals"]["CoD"];
|
||||
state["LUI"] = state["luiglobals"]["LUI"];
|
||||
state["Engine"] = state["luiglobals"]["Engine"];
|
||||
state["Game"] = state["luiglobals"]["Game"];
|
||||
}
|
||||
}
|
||||
|
||||
context::context(std::string folder)
|
||||
: folder_(std::move(folder))
|
||||
, scheduler_(state_)
|
||||
{
|
||||
this->state_.open_libraries(sol::lib::base,
|
||||
sol::lib::package,
|
||||
sol::lib::io,
|
||||
sol::lib::string,
|
||||
sol::lib::os,
|
||||
sol::lib::math,
|
||||
sol::lib::table);
|
||||
|
||||
this->state_["include"] = [this](const std::string& file)
|
||||
{
|
||||
this->load_script(file);
|
||||
};
|
||||
|
||||
sol::function old_require = this->state_["require"];
|
||||
auto base_path = utils::string::replace(this->folder_, "/", ".") + ".";
|
||||
this->state_["require"] = [base_path, old_require](const std::string& path)
|
||||
{
|
||||
return old_require(base_path + path);
|
||||
};
|
||||
|
||||
this->state_["scriptdir"] = [this]()
|
||||
{
|
||||
return this->folder_;
|
||||
};
|
||||
|
||||
setup_types(this->state_, this->scheduler_);
|
||||
|
||||
printf("Loading ui script '%s'\n", this->folder_.data());
|
||||
this->load_script("__init__");
|
||||
}
|
||||
|
||||
context::~context()
|
||||
{
|
||||
this->state_.collect_garbage();
|
||||
this->scheduler_.clear();
|
||||
this->state_ = {};
|
||||
}
|
||||
|
||||
void context::run_frame()
|
||||
{
|
||||
this->scheduler_.run_frame();
|
||||
this->state_.collect_garbage();
|
||||
}
|
||||
|
||||
void context::load_script(const std::string& script)
|
||||
{
|
||||
if (!this->loaded_scripts_.emplace(script).second)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto file = (std::filesystem::path{this->folder_} / (script + ".lua")).generic_string();
|
||||
handle_error(this->state_.safe_script_file(file, &sol::script_pass_on_error));
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4702)
|
||||
|
||||
#define SOL_ALL_SAFETIES_ON 1
|
||||
#define SOL_PRINT_ERRORS 0
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include "scheduler.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
class context
|
||||
{
|
||||
public:
|
||||
context(std::string folder);
|
||||
~context();
|
||||
|
||||
context(context&&) noexcept = delete;
|
||||
context& operator=(context&&) noexcept = delete;
|
||||
|
||||
context(const context&) = delete;
|
||||
context& operator=(const context&) = delete;
|
||||
|
||||
void run_frame();
|
||||
|
||||
private:
|
||||
sol::state state_{};
|
||||
std::string folder_;
|
||||
std::unordered_set<std::string> loaded_scripts_;
|
||||
|
||||
scheduler scheduler_;
|
||||
|
||||
void load_script(const std::string& script);
|
||||
};
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "engine.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
#include "../../../component/ui_scripting.hpp"
|
||||
#include "../../../component/game_module.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace ui_scripting::lua::engine
|
||||
{
|
||||
namespace
|
||||
{
|
||||
auto& get_scripts()
|
||||
{
|
||||
static std::vector<std::unique_ptr<context>> scripts{};
|
||||
return scripts;
|
||||
}
|
||||
|
||||
void load_scripts(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_directory(script) && utils::io::file_exists(script + "/__init__.lua"))
|
||||
{
|
||||
get_scripts().push_back(std::make_unique<context>(script));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
clear_converted_functions();
|
||||
get_scripts().clear();
|
||||
load_scripts(game_module::get_host_module().get_folder() + "/data/ui_scripts/");
|
||||
load_scripts("s1x/ui_scripts/");
|
||||
load_scripts("data/ui_scripts/");
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
clear_converted_functions();
|
||||
get_scripts().clear();
|
||||
}
|
||||
|
||||
void run_frame()
|
||||
{
|
||||
for (auto& script : get_scripts())
|
||||
{
|
||||
script->run_frame();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ui_scripting::lua::engine
|
||||
{
|
||||
void start();
|
||||
void stop();
|
||||
void run_frame();
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "error.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
void handle_error(const sol::protected_function_result& result)
|
||||
{
|
||||
if (!result.valid())
|
||||
{
|
||||
printf("************** UI Script execution error **************\n");
|
||||
|
||||
const sol::error err = result;
|
||||
printf("%s\n", err.what());
|
||||
|
||||
printf("****************************************************\n");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
void handle_error(const sol::protected_function_result& result);
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
scheduler::scheduler(sol::state& state)
|
||||
{
|
||||
auto task_handle_type = state.new_usertype<task_handle>("task_handle");
|
||||
|
||||
task_handle_type["clear"] = [this](const task_handle& handle)
|
||||
{
|
||||
this->remove(handle);
|
||||
};
|
||||
}
|
||||
|
||||
void scheduler::run_frame()
|
||||
{
|
||||
callbacks_.access([&](task_list& tasks)
|
||||
{
|
||||
this->merge_callbacks();
|
||||
|
||||
for (auto i = tasks.begin(); i != tasks.end();)
|
||||
{
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
const auto diff = now - i->last_call;
|
||||
|
||||
if (diff < i->delay)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
i->last_call = now;
|
||||
|
||||
if (!i->is_deleted)
|
||||
{
|
||||
handle_error(i->callback());
|
||||
}
|
||||
|
||||
if (i->is_volatile || i->is_deleted)
|
||||
{
|
||||
i = tasks.erase(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void scheduler::clear()
|
||||
{
|
||||
callbacks_.access([&](task_list& tasks)
|
||||
{
|
||||
new_callbacks_.access([&](task_list& new_tasks)
|
||||
{
|
||||
new_tasks.clear();
|
||||
tasks.clear();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const sol::protected_function& callback, const long long milliseconds,
|
||||
const bool is_volatile)
|
||||
{
|
||||
return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile);
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const sol::protected_function& callback, const std::chrono::milliseconds delay,
|
||||
const bool is_volatile)
|
||||
{
|
||||
const uint64_t id = ++this->current_task_id_;
|
||||
|
||||
task task;
|
||||
task.is_volatile = is_volatile;
|
||||
task.callback = callback;
|
||||
task.delay = delay;
|
||||
task.last_call = std::chrono::steady_clock::now();
|
||||
task.id = id;
|
||||
task.is_deleted = false;
|
||||
|
||||
new_callbacks_.access([&task](task_list& tasks)
|
||||
{
|
||||
tasks.emplace_back(std::move(task));
|
||||
});
|
||||
|
||||
return {id};
|
||||
}
|
||||
|
||||
void scheduler::remove(const task_handle& handle)
|
||||
{
|
||||
auto mask_as_deleted = [&](task_list& tasks)
|
||||
{
|
||||
for (auto& task : tasks)
|
||||
{
|
||||
if (task.id == handle.id)
|
||||
{
|
||||
task.is_deleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
callbacks_.access(mask_as_deleted);
|
||||
new_callbacks_.access(mask_as_deleted);
|
||||
}
|
||||
|
||||
void scheduler::merge_callbacks()
|
||||
{
|
||||
callbacks_.access([&](task_list& tasks)
|
||||
{
|
||||
new_callbacks_.access([&](task_list& new_tasks)
|
||||
{
|
||||
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()),
|
||||
std::move_iterator<task_list::iterator>(new_tasks.end()));
|
||||
new_tasks = {};
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
class context;
|
||||
|
||||
class task_handle
|
||||
{
|
||||
public:
|
||||
uint64_t id = 0;
|
||||
};
|
||||
|
||||
class task final : public task_handle
|
||||
{
|
||||
public:
|
||||
std::chrono::steady_clock::time_point last_call{};
|
||||
sol::protected_function callback{};
|
||||
std::chrono::milliseconds delay{};
|
||||
bool is_volatile = false;
|
||||
bool is_deleted = false;
|
||||
};
|
||||
|
||||
class scheduler final
|
||||
{
|
||||
public:
|
||||
scheduler(sol::state& state);
|
||||
|
||||
scheduler(scheduler&&) noexcept = delete;
|
||||
scheduler& operator=(scheduler&&) noexcept = delete;
|
||||
|
||||
scheduler(const scheduler&) = delete;
|
||||
scheduler& operator=(const scheduler&) = delete;
|
||||
|
||||
void run_frame();
|
||||
void clear();
|
||||
|
||||
task_handle add(const sol::protected_function& callback, long long milliseconds, bool is_volatile);
|
||||
task_handle add(const sol::protected_function& callback, std::chrono::milliseconds delay, bool is_volatile);
|
||||
|
||||
private:
|
||||
using task_list = std::vector<task>;
|
||||
utils::concurrency::container<task_list> new_callbacks_;
|
||||
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
|
||||
std::atomic_int64_t current_task_id_ = 0;
|
||||
|
||||
void remove(const task_handle& handle);
|
||||
void merge_callbacks();
|
||||
};
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "value_conversion.hpp"
|
||||
#include "../execution.hpp"
|
||||
#include "../../../component/ui_scripting.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
namespace
|
||||
{
|
||||
table convert_table(const sol::table& t)
|
||||
{
|
||||
table res{};
|
||||
|
||||
t.for_each([res](const sol::object& key, const sol::object& value)
|
||||
{
|
||||
res.set(convert(key), convert(value));
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
script_value convert_function(const sol::protected_function& function)
|
||||
{
|
||||
const auto closure = game::hks::cclosure_Create(*game::hks::lua_state, main_function_handler, 0, 0, 0);
|
||||
add_converted_function(closure, function);
|
||||
|
||||
game::hks::HksObject value{};
|
||||
value.t = game::hks::TCFUNCTION;
|
||||
value.v.cClosure = closure;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
script_value convert(const sol::lua_value& value)
|
||||
{
|
||||
if (value.is<bool>())
|
||||
{
|
||||
return {value.as<bool>()};
|
||||
}
|
||||
|
||||
if (value.is<int>())
|
||||
{
|
||||
return {value.as<int>()};
|
||||
}
|
||||
|
||||
if (value.is<unsigned int>())
|
||||
{
|
||||
return {value.as<unsigned int>()};
|
||||
}
|
||||
|
||||
if (value.is<double>())
|
||||
{
|
||||
return {value.as<double>()};
|
||||
}
|
||||
|
||||
if (value.is<float>())
|
||||
{
|
||||
return {value.as<float>()};
|
||||
}
|
||||
|
||||
if (value.is<std::string>())
|
||||
{
|
||||
return {value.as<std::string>()};
|
||||
}
|
||||
|
||||
if (value.is<lightuserdata>())
|
||||
{
|
||||
return {value.as<lightuserdata>()};
|
||||
}
|
||||
|
||||
if (value.is<userdata>())
|
||||
{
|
||||
return {value.as<userdata>()};
|
||||
}
|
||||
|
||||
if (value.is<table>())
|
||||
{
|
||||
return {value.as<table>()};
|
||||
}
|
||||
|
||||
if (value.is<function>())
|
||||
{
|
||||
return {value.as<function>()};
|
||||
}
|
||||
|
||||
if (value.is<sol::table>())
|
||||
{
|
||||
return {convert_table(value.as<sol::table>())};
|
||||
}
|
||||
|
||||
if (value.is<sol::protected_function>())
|
||||
{
|
||||
return {convert_function(value.as<sol::protected_function>())};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
sol::lua_value convert(lua_State* state, const script_value& value)
|
||||
{
|
||||
if (value.is<int>())
|
||||
{
|
||||
return {state, value.as<int>()};
|
||||
}
|
||||
|
||||
if (value.is<float>())
|
||||
{
|
||||
return {state, value.as<float>()};
|
||||
}
|
||||
|
||||
if (value.is<bool>())
|
||||
{
|
||||
return {state, value.as<bool>()};
|
||||
}
|
||||
|
||||
if (value.is<std::string>())
|
||||
{
|
||||
return {state, value.as<std::string>()};
|
||||
}
|
||||
|
||||
if (value.is<lightuserdata>())
|
||||
{
|
||||
return {state, value.as<lightuserdata>()};
|
||||
}
|
||||
|
||||
if (value.is<userdata>())
|
||||
{
|
||||
return {state, value.as<userdata>()};
|
||||
}
|
||||
|
||||
if (value.is<table>())
|
||||
{
|
||||
return {state, value.as<table>()};
|
||||
}
|
||||
|
||||
if (value.is<function>())
|
||||
{
|
||||
return {state, value.as<function>()};
|
||||
}
|
||||
|
||||
return {state, sol::lua_nil};
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "context.hpp"
|
||||
#include "../script_value.hpp"
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
script_value convert(const sol::lua_value& value);
|
||||
sol::lua_value convert(lua_State* state, const script_value& value);
|
||||
}
|
@ -2,9 +2,79 @@
|
||||
#include "execution.hpp"
|
||||
#include "types.hpp"
|
||||
#include "script_value.hpp"
|
||||
#include "../../component/ui_scripting.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
|
||||
**************************************************************/
|
||||
@ -32,6 +102,24 @@ namespace ui_scripting
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const long long value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TUI64;
|
||||
obj.v.i64 = value;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const unsigned long long value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TUI64;
|
||||
obj.v.ui64 = value;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const bool value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
@ -55,46 +143,68 @@ namespace ui_scripting
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const char* value)
|
||||
script_value::script_value(const char* value, const size_t len)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
if (state == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::hks::hksi_lua_pushlstring(state, value, (unsigned int)strlen(value));
|
||||
const auto top = state->m_apistack.top;
|
||||
game::hks::hksi_lua_pushlstring(state, value, static_cast<unsigned int>(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, strlen(value))
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const std::string& value)
|
||||
: script_value(value.data())
|
||||
: script_value(value.data(), value.size())
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const lightuserdata& value)
|
||||
{
|
||||
this->value_.t = game::hks::TLIGHTUSERDATA;
|
||||
this->value_.v.ptr = value.ptr;
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TLIGHTUSERDATA;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const userdata& value)
|
||||
{
|
||||
this->value_.t = game::hks::TUSERDATA;
|
||||
this->value_.v.ptr = value.ptr;
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TUSERDATA;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const table& value)
|
||||
{
|
||||
this->value_.t = game::hks::TTABLE;
|
||||
this->value_.v.ptr = value.ptr;
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TTABLE;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const function& value)
|
||||
{
|
||||
this->value_.t = value.type;
|
||||
this->value_.v.ptr = value.ptr;
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = value.type;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
@ -126,6 +236,34 @@ namespace ui_scripting
|
||||
return static_cast<unsigned int>(this->get_raw().v.number);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Integer 64
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<long long>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TUI64;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<unsigned long long>() const
|
||||
{
|
||||
return this->is<long long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
long long script_value::get() const
|
||||
{
|
||||
return static_cast<long long>(this->get_raw().v.ui64);
|
||||
}
|
||||
|
||||
template <>
|
||||
unsigned long long script_value::get() const
|
||||
{
|
||||
return static_cast<unsigned long long>(this->get_raw().v.ui64);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Boolean
|
||||
**************************************************************/
|
||||
@ -260,7 +398,7 @@ namespace ui_scripting
|
||||
template <>
|
||||
function script_value::get() const
|
||||
{
|
||||
return { this->get_raw().v.cClosure, this->get_raw().t };
|
||||
return {this->get_raw().v.cClosure, this->get_raw().t};
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
@ -269,6 +407,43 @@ namespace ui_scripting
|
||||
|
||||
const game::hks::HksObject& script_value::get_raw() const
|
||||
{
|
||||
return this->value_;
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,92 @@
|
||||
#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;
|
||||
|
||||
namespace
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -16,12 +96,15 @@ namespace ui_scripting
|
||||
|
||||
script_value(int value);
|
||||
script_value(unsigned int value);
|
||||
script_value(long long value);
|
||||
script_value(unsigned long long value);
|
||||
script_value(bool value);
|
||||
|
||||
script_value(float value);
|
||||
script_value(double value);
|
||||
|
||||
script_value(const char* value);
|
||||
script_value(const char* value, const size_t len);
|
||||
script_value(const std::string& value);
|
||||
|
||||
script_value(const lightuserdata& value);
|
||||
@ -29,6 +112,53 @@ namespace ui_scripting
|
||||
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>
|
||||
bool is() const;
|
||||
|
||||
@ -37,20 +167,93 @@ namespace ui_scripting
|
||||
{
|
||||
if (!this->is<T>())
|
||||
{
|
||||
throw std::runtime_error("Invalid type");
|
||||
const auto hks_typename = game::hks::typenames[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>();
|
||||
}
|
||||
|
||||
const game::hks::HksObject& get_raw() const;
|
||||
|
||||
hks_object value_{};
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T get() const;
|
||||
|
||||
game::hks::HksObject value_{};
|
||||
};
|
||||
|
||||
using arguments = std::vector<script_value>;
|
||||
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 (index >= values_.size())
|
||||
{
|
||||
return {values_, {}, index};
|
||||
}
|
||||
|
||||
return {values_, values_[index], index};
|
||||
}
|
||||
private:
|
||||
arguments values_{};
|
||||
};
|
||||
}
|
||||
|
@ -1,276 +1,355 @@
|
||||
#include <std_include.hpp>
|
||||
#include "types.hpp"
|
||||
#include "execution.hpp"
|
||||
#include "../../component/ui_scripting.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
/***************************************************************
|
||||
* Lightuserdata
|
||||
**************************************************************/
|
||||
/***************************************************************
|
||||
* Lightuserdata
|
||||
**************************************************************/
|
||||
|
||||
lightuserdata::lightuserdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
}
|
||||
lightuserdata::lightuserdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Userdata
|
||||
**************************************************************/
|
||||
/***************************************************************
|
||||
* Userdata
|
||||
**************************************************************/
|
||||
|
||||
userdata::userdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
userdata::userdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
userdata::userdata(const userdata& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
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(userdata&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
userdata::~userdata()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
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();
|
||||
}
|
||||
userdata& userdata::operator=(const userdata& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
userdata& userdata::operator=(userdata&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
userdata& userdata::operator=(userdata&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void userdata::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.ptr = this->ptr;
|
||||
value.t = game::hks::TUSERDATA;
|
||||
void userdata::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.ptr = this->ptr;
|
||||
value.t = game::hks::TUSERDATA;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(value);
|
||||
push_value(value);
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
}
|
||||
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::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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
script_value userdata::get(const script_value& key) const
|
||||
{
|
||||
return get_field(*this, key);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Table
|
||||
**************************************************************/
|
||||
userdata_value userdata::operator[](const script_value& key) const
|
||||
{
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
table::table()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
this->ptr = game::hks::Hashtable_Create(state, 0, 0);
|
||||
this->add();
|
||||
}
|
||||
userdata_value::userdata_value(const userdata& table, const script_value& key)
|
||||
: userdata_(table)
|
||||
, key_(key)
|
||||
{
|
||||
this->value_ = this->userdata_.get(key).get_raw();
|
||||
}
|
||||
|
||||
table::table(game::hks::HashTable* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
void userdata_value::operator=(const script_value& value)
|
||||
{
|
||||
this->userdata_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
table::table(const table& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
bool userdata_value::operator==(const script_value& value)
|
||||
{
|
||||
return this->userdata_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
table::table(table&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
/***************************************************************
|
||||
* Table
|
||||
**************************************************************/
|
||||
|
||||
table::~table()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
table::table()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
this->ptr = game::hks::Hashtable_Create(state, 0, 0);
|
||||
this->add();
|
||||
}
|
||||
|
||||
table& table::operator=(const table& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
table::table(game::hks::HashTable* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
table::table(const table& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
table& table::operator=(table&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
table::table(table&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
table::~table()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
void table::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.table = this->ptr;
|
||||
value.t = game::hks::TTABLE;
|
||||
table& table::operator=(const table& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
return *this;
|
||||
}
|
||||
|
||||
push_value(value);
|
||||
table& table::operator=(table&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void table::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
void table::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.table = this->ptr;
|
||||
value.t = game::hks::TTABLE;
|
||||
|
||||
void table::set(const script_value& key, const script_value& value) const
|
||||
{
|
||||
set_field(*this, key, value);
|
||||
}
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
script_value table::get(const script_value& key) const
|
||||
{
|
||||
return get_field(*this, key);
|
||||
}
|
||||
push_value(value);
|
||||
|
||||
/***************************************************************
|
||||
* Function
|
||||
**************************************************************/
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
state->m_apistack.top = top;
|
||||
}
|
||||
|
||||
function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_)
|
||||
: ptr(ptr_)
|
||||
, type(type_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
void table::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
|
||||
function::function(const function& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
void table::set(const script_value& key, const script_value& value) const
|
||||
{
|
||||
set_field(*this, key, value);
|
||||
}
|
||||
|
||||
function::function(function&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->type = other.type;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
table_value table::operator[](const script_value& key) const
|
||||
{
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
function::~function()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
script_value table::get(const script_value& key) const
|
||||
{
|
||||
return get_field(*this, key);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
table_value::table_value(const table& table, const script_value& key)
|
||||
: table_(table)
|
||||
, key_(key)
|
||||
{
|
||||
this->value_ = this->table_.get(key).get_raw();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
void table_value::operator=(const script_value& value)
|
||||
{
|
||||
this->table_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void table_value::operator=(const table_value& value)
|
||||
{
|
||||
this->table_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
bool table_value::operator==(const script_value& value)
|
||||
{
|
||||
return this->table_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
void function::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.cClosure = this->ptr;
|
||||
value.t = this->type;
|
||||
bool table_value::operator==(const table_value& value)
|
||||
{
|
||||
return this->table_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_apistack.top = state->m_apistack.base;
|
||||
/***************************************************************
|
||||
* Function
|
||||
**************************************************************/
|
||||
|
||||
push_value(value);
|
||||
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();
|
||||
}
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
}
|
||||
function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_)
|
||||
: ptr(ptr_)
|
||||
, type(type_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
void function::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
function::function(const function& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
arguments function::call(const arguments& arguments) const
|
||||
{
|
||||
return call_script_function(*this, arguments);
|
||||
}
|
||||
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({});
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,140 @@
|
||||
#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 lightuserdata
|
||||
{
|
||||
public:
|
||||
lightuserdata(void*);
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
class userdata
|
||||
{
|
||||
public:
|
||||
userdata(void*);
|
||||
class userdata_value;
|
||||
|
||||
userdata(const userdata& other);
|
||||
userdata(userdata&& other) noexcept;
|
||||
class userdata
|
||||
{
|
||||
public:
|
||||
userdata(void*);
|
||||
|
||||
~userdata();
|
||||
userdata(const userdata& other);
|
||||
userdata(userdata&& other) noexcept;
|
||||
|
||||
userdata& operator=(const userdata& other);
|
||||
userdata& operator=(userdata&& other) noexcept;
|
||||
~userdata();
|
||||
|
||||
script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
userdata& operator=(const userdata& other);
|
||||
userdata& operator=(userdata&& other) noexcept;
|
||||
|
||||
void* ptr;
|
||||
script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
userdata_value operator[](const script_value& key) const;
|
||||
|
||||
int ref{};
|
||||
};
|
||||
void* ptr;
|
||||
|
||||
class table
|
||||
{
|
||||
public:
|
||||
table();
|
||||
table(game::hks::HashTable* ptr_);
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
|
||||
table(const table& other);
|
||||
table(table&& other) noexcept;
|
||||
int ref{};
|
||||
};
|
||||
|
||||
~table();
|
||||
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_;
|
||||
};
|
||||
|
||||
table& operator=(const table& other);
|
||||
table& operator=(table&& other) noexcept;
|
||||
class table_value;
|
||||
|
||||
script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
class table
|
||||
{
|
||||
public:
|
||||
table();
|
||||
table(game::hks::HashTable* ptr_);
|
||||
|
||||
game::hks::HashTable* ptr;
|
||||
table(const table& other);
|
||||
table(table&& other) noexcept;
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
~table();
|
||||
|
||||
int ref{};
|
||||
};
|
||||
table& operator=(const table& other);
|
||||
table& operator=(table&& other) noexcept;
|
||||
|
||||
class function
|
||||
{
|
||||
public:
|
||||
function(game::hks::cclosure*, game::hks::HksObjectType);
|
||||
script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
|
||||
function(const function& other);
|
||||
function(function&& other) noexcept;
|
||||
table_value operator[](const script_value& key) const;
|
||||
|
||||
~function();
|
||||
game::hks::HashTable* ptr;
|
||||
|
||||
function& operator=(const function& other);
|
||||
function& operator=(function&& other) noexcept;
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
|
||||
arguments call(const arguments& arguments) const;
|
||||
int ref{};
|
||||
};
|
||||
|
||||
game::hks::cclosure* ptr;
|
||||
game::hks::HksObjectType type;
|
||||
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_;
|
||||
};
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
class function
|
||||
{
|
||||
public:
|
||||
function(game::hks::lua_function);
|
||||
function(game::hks::cclosure*, game::hks::HksObjectType);
|
||||
|
||||
int ref{};
|
||||
};
|
||||
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