commit
c344037c11
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -22,9 +22,6 @@
|
||||
[submodule "deps/asmjit"]
|
||||
path = deps/asmjit
|
||||
url = https://github.com/asmjit/asmjit.git
|
||||
[submodule "deps/protobuf"]
|
||||
path = deps/protobuf
|
||||
url = https://github.com/google/protobuf.git
|
||||
[submodule "deps/udis86"]
|
||||
path = deps/udis86
|
||||
url = https://github.com/vmt/udis86.git
|
||||
|
@ -2,7 +2,7 @@
|
||||
[![open bugs](https://img.shields.io/github/issues/fedddddd/h2-mod/bug?label=bugs)](https://github.com/fedddddd/h2-mod/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
||||
[![Build](https://github.com/fedddddd/h2-mod/workflows/Build/badge.svg)](https://github.com/fedddddd/h2-mod/actions)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/0sh80kdnsvm53rno?svg=true)](https://ci.appveyor.com/project/fedddddd/h2-mod)
|
||||
|
||||
[![Discord](https://img.shields.io/discord/955362057581129738?color=%237289DA&label=members&logo=discord&logoColor=%23FFFFFF)](https://discord.gg/dpnRn2tKT9)
|
||||
|
||||
# H2: Mod
|
||||
<p align="center">
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
**NOTE**: Cracked/Pirated versions of the game are NOT compatible with this mod, if you run such a version and have issues/crashes launching the client refer to [this issue](https://github.com/fedddddd/h2-mod/issues/111).
|
||||
|
||||
- **[Click here to get the latest release](https://ci.appveyor.com/api/projects/fedddddd/h2-mod/artifacts/build%2Fbin%2Fx64%2FRelease%2Fh2-mod.exe?branch=develop&job=Environment%3A%20APPVEYOR_BUILD_WORKER_IMAGE%3DVisual%20Studio%202019%2C%20PREMAKE_ACTION%3Dvs2019%2C%20CI%3D1%3B%20Configuration%3A%20Release)**
|
||||
- **[Click here to get the latest release](https://ci.appveyor.com/api/projects/fedddddd/h2-mod/artifacts/build%2Fbin%2Fx64%2FRelease%2Fh2-mod.exe?branch=develop&job=Environment%3A%20APPVEYOR_BUILD_WORKER_IMAGE%3DVisual%20Studio%202022%2C%20PREMAKE_ACTION%3Dvs2022%2C%20CI%3D1%3B%20Configuration%3A%20Release)**
|
||||
- **You will need to drop this in your Call of Duty: Modern Warfare 2 Campaign Remastered installation folder. If you don't have Call of Duty: Modern Warfare 2 Campaign Remastered, get those game files first.**
|
||||
|
||||
## Compile from source
|
||||
|
@ -1,3 +1,14 @@
|
||||
game:addlocalizedstring("MENU_MODS", "MODS")
|
||||
game:addlocalizedstring("MENU_MODS_DESC", "Load installed mods.")
|
||||
game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.")
|
||||
game:addlocalizedstring("LUA_MENU_MOD_DESC", "&&1\nAuthor: &&2\nVersion: &&3")
|
||||
game:addlocalizedstring("LUA_MENU_OPEN_STORE", "Open store")
|
||||
game:addlocalizedstring("LUA_MENU_OPEN_STORE_DESC", "Download and install mods.")
|
||||
game:addlocalizedstring("LUA_MENU_LOADED_MOD", "Loaded mod: ^3&&1")
|
||||
game:addlocalizedstring("LUA_MENU_AVAILABLE_MODS", "Available mods")
|
||||
game:addlocalizedstring("LUA_MENU_UNLOAD", "Unload")
|
||||
game:addlocalizedstring("LUA_MENU_UNLOAD_DESC", "Unload the currently loaded mod.")
|
||||
|
||||
function createdivider(menu, text)
|
||||
local element = LUI.UIElement.new( {
|
||||
leftAnchor = true,
|
||||
@ -12,7 +23,7 @@ function createdivider(menu, text)
|
||||
|
||||
element.scrollingToNext = true
|
||||
element:addElement(LUI.MenuBuilder.BuildRegisteredType("h1_option_menu_titlebar", {
|
||||
title_bar_text = Engine.ToUpperCase(Engine.Localize(text))
|
||||
title_bar_text = Engine.ToUpperCase(text)
|
||||
}))
|
||||
|
||||
menu.list:addElement(element)
|
||||
@ -28,8 +39,8 @@ end
|
||||
|
||||
LUI.addmenubutton("main_campaign", {
|
||||
index = 6,
|
||||
text = "$_MODS",
|
||||
description = "Load installed mods.",
|
||||
text = "@MENU_MODS",
|
||||
description = Engine.Localize("@MENU_MODS_DESC"),
|
||||
callback = function()
|
||||
LUI.FlowManager.RequestAddMenu(nil, "mods_menu")
|
||||
end
|
||||
@ -37,13 +48,13 @@ LUI.addmenubutton("main_campaign", {
|
||||
|
||||
function getmodname(path)
|
||||
local name = path
|
||||
local desc = "Load " .. name
|
||||
local desc = Engine.Localize("@LUA_MENU_MOD_DESC_DEFAULT", name)
|
||||
local infofile = path .. "/info.json"
|
||||
|
||||
if (io.fileexists(infofile)) then
|
||||
pcall(function()
|
||||
local data = json.decode(io.readfile(infofile))
|
||||
desc = string.format("%s\nAuthor: %s\nVersion: %s",
|
||||
desc = Engine.Localize("@LUA_MENU_MOD_DESC",
|
||||
data.description, data.author, data.version)
|
||||
name = data.name
|
||||
end)
|
||||
@ -54,33 +65,33 @@ end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
|
||||
local menu = LUI.MenuTemplate.new(a1, {
|
||||
menu_title = "$_MODS",
|
||||
menu_title = "@MENU_MODS",
|
||||
exclusiveController = 0,
|
||||
menu_width = 400,
|
||||
menu_top_indent = LUI.MenuTemplate.spMenuOffset,
|
||||
showTopRightSmallBar = true
|
||||
})
|
||||
|
||||
menu:AddButton("$_OPEN STORE", function()
|
||||
menu:AddButton("@LUA_MENU_OPEN_STORE", function()
|
||||
if (LUI.MenuBuilder.m_types_build["mod_store_menu"]) then
|
||||
LUI.FlowManager.RequestAddMenu(nil, "mod_store_menu")
|
||||
end
|
||||
end, nil, true, nil, {
|
||||
desc_text = "Download and install mods."
|
||||
desc_text = Engine.Localize("@LUA_MENU_OPEN_STORE_DESC")
|
||||
})
|
||||
|
||||
local modfolder = game:getloadedmod()
|
||||
if (modfolder ~= "") then
|
||||
createdivider(menu, "$_Loaded mod: ^3" .. getmodname(modfolder):truncate(20))
|
||||
createdivider(menu, Engine.Localize("@LUA_MENU_LOADED_MOD", getmodname(modfolder):truncate(24)))
|
||||
|
||||
menu:AddButton("$_UNLOAD", function()
|
||||
menu:AddButton("@LUA_MENU_UNLOAD", function()
|
||||
game:executecommand("unloadmod")
|
||||
end, nil, true, nil, {
|
||||
desc_text = "Unload the currently loaded mod."
|
||||
desc_text = Engine.Localize("@LUA_MENU_UNLOAD_DESC")
|
||||
})
|
||||
end
|
||||
|
||||
createdivider(menu, "$_Available mods")
|
||||
createdivider(menu, Engine.Localize("@LUA_MENU_AVAILABLE_MODS"))
|
||||
|
||||
if (io.directoryexists("mods")) then
|
||||
local mods = io.listfiles("mods/")
|
||||
@ -89,7 +100,8 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
|
||||
local name, desc = getmodname(mods[i])
|
||||
|
||||
if (mods[i] ~= modfolder) then
|
||||
menu:AddButton("$_" .. name, function()
|
||||
game:addlocalizedstring(name, name)
|
||||
menu:AddButton(name, function()
|
||||
game:executecommand("loadmod " .. mods[i])
|
||||
end, nil, true, nil, {
|
||||
desc_text = desc
|
||||
@ -110,14 +122,3 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
local localize = Engine.Localize
|
||||
Engine.Localize = function(...)
|
||||
local args = {...}
|
||||
|
||||
if (type(args[1]) == "string" and args[1]:sub(1, 2) == "$_") then
|
||||
return args[1]:sub(3, -1)
|
||||
end
|
||||
|
||||
return localize(table.unpack(args))
|
||||
end
|
@ -1,3 +1,28 @@
|
||||
game:addlocalizedstring("MENU_GENERAL", "GENERAL")
|
||||
game:addlocalizedstring("MENU_GENERAL_DESC", "Set the client's settings.")
|
||||
game:addlocalizedstring("LUA_MENU_AUTO_UPDATE", "Automatic updates")
|
||||
game:addlocalizedstring("LUA_MENU_CHECK_UPDATES", "Check for updates")
|
||||
game:addlocalizedstring("LUA_MENU_CHECK_UPDATES_DESC", "Check for updates.")
|
||||
game:addlocalizedstring("LUA_MENU_DRAWING", "Drawing")
|
||||
game:addlocalizedstring("LUA_MENU_UPDATES", "Updates")
|
||||
game:addlocalizedstring("LUA_MENU_RENDERING", "Rendering")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_FPS", "Draw FPS")
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_FPS_DESC", "Enable or disable drawing fps or viewpos on screen.")
|
||||
game:addlocalizedstring("LUA_MENU_FPS_ONLY", "FPS only")
|
||||
game:addlocalizedstring("LUA_MENU_FPS_AND_VIEWPOS", "FPS and View Pos")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_SPEED", "Draw speed")
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_SPEED_DESC", "Enable or disable drawing the player speed on screen.")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_SPEEDGRAPH", "Draw speed graph")
|
||||
game:addlocalizedstring("LUA_MENU_DRAW_SPEEDGRAPH_DESC", "Enable or disable the speed graph.")
|
||||
|
||||
game:addlocalizedstring("LUA_MENU_R_FULLBRIGHT", "Fullbright")
|
||||
game:addlocalizedstring("LUA_MENU_R_FULLBRIGHT_DESC", "Change the fullbright mode.")
|
||||
game:addlocalizedstring("LUA_MENU_MODE2", "Mode 2")
|
||||
game:addlocalizedstring("LUA_MENU_MODE3", "Mode 3")
|
||||
|
||||
function createdivider(menu, text)
|
||||
local element = LUI.UIElement.new({
|
||||
leftAnchor = true,
|
||||
@ -20,8 +45,8 @@ end
|
||||
|
||||
LUI.addmenubutton("pc_controls", {
|
||||
index = 4,
|
||||
text = "$_GENERAL",
|
||||
description = "Set the client's settings.",
|
||||
text = "@MENU_GENERAL",
|
||||
description = Engine.Localize("@MENU_GENERAL_DESC"),
|
||||
callback = function()
|
||||
LUI.FlowManager.RequestAddMenu(nil, "settings_menu")
|
||||
end
|
||||
@ -29,134 +54,118 @@ LUI.addmenubutton("pc_controls", {
|
||||
|
||||
LUI.MenuBuilder.m_types_build["settings_menu"] = function(a1)
|
||||
local menu = LUI.MenuTemplate.new(a1, {
|
||||
menu_title = "$_GENERAL",
|
||||
menu_title = "@MENU_GENERAL",
|
||||
menu_list_divider_top_offset = -(LUI.H1MenuTab.tabChangeHoldingElementHeight + luiglobals.H1MenuDims.spacing),
|
||||
menu_width = luiglobals.GenericMenuDims.OptionMenuWidth
|
||||
})
|
||||
|
||||
Engine.SetDvarFromString("ui_cg_autoUpdate", Engine.GetDvarBool("cg_autoUpdate") and "1" or "0")
|
||||
Engine.SetDvarFromString("ui_cg_drawFps", Engine.GetDvarInt("cg_drawFps") .. "")
|
||||
Engine.SetDvarFromString("ui_cg_speedGraph", Engine.GetDvarBool("cg_speedGraph") and "1" or "0")
|
||||
Engine.SetDvarFromString("ui_cg_drawSpeed", Engine.GetDvarBool("cg_drawSpeed") and "1" or "0")
|
||||
Engine.SetDvarFromString("ui_r_fullbright", Engine.GetDvarInt("r_fullbright") .. "")
|
||||
|
||||
createdivider(menu, "$_UPDATES")
|
||||
createdivider(menu, "@LUA_MENU_UPDATES")
|
||||
|
||||
LUI.Options.CreateOptionButton(
|
||||
menu,
|
||||
"ui_cg_autoUpdate",
|
||||
"$_AUTOMATIC UPDATES",
|
||||
"cg_auto_update",
|
||||
"@LUA_MENU_AUTO_UPDATE",
|
||||
"Enable or disable automatic updates on startup.",
|
||||
{
|
||||
{
|
||||
text = "$_ENABLED",
|
||||
value = "1"
|
||||
text = "@LUA_MENU_ENABLED",
|
||||
value = true
|
||||
},
|
||||
{
|
||||
text = "$_DISABLED",
|
||||
value = "0"
|
||||
text = "@LUA_MENU_DISABLED",
|
||||
value = false
|
||||
}
|
||||
}
|
||||
}, nil, nil, function(value)
|
||||
Engine.SetDvarBool("cg_autoUpdate", Engine.GetDvarString("ui_cg_autoUpdate") == "1")
|
||||
end
|
||||
)
|
||||
|
||||
menu:AddButton("$_CHECK FOR UPDATES", function()
|
||||
menu:AddButton("@LUA_MENU_CHECK_UPDATES", function()
|
||||
LUI.tryupdating(false)
|
||||
end, nil, true, nil, {
|
||||
desc_text = "Check for updates."
|
||||
desc_text = Engine.Localize("@LUA_MENU_CHECK_UPDATES_DESC")
|
||||
})
|
||||
|
||||
createdivider(menu, "$_DRAWING")
|
||||
createdivider(menu, "@LUA_MENU_DRAWING")
|
||||
|
||||
LUI.Options.CreateOptionButton(
|
||||
menu,
|
||||
"ui_cg_drawFps",
|
||||
"$_DRAW FPS",
|
||||
"Enable or disable drawing fps or viewpos on screen.",
|
||||
"cg_drawFps",
|
||||
"@LUA_MENU_DRAW_FPS",
|
||||
"@LUA_MENU_DRAW_FPS_DESC",
|
||||
{
|
||||
{
|
||||
text = "$_DISABLED",
|
||||
value = "0"
|
||||
text = "@LUA_MENU_DISABLED",
|
||||
value = 0
|
||||
},
|
||||
{
|
||||
text = "$_FPS ONLY",
|
||||
value = "1"
|
||||
text = "@LUA_MENU_FPS_ONLY",
|
||||
value = 1
|
||||
},
|
||||
{
|
||||
text = "$_FPS AND VIEWPOS",
|
||||
value = "2"
|
||||
text = "@LUA_MENU_FPS_AND_VIEWPOS",
|
||||
value = 2
|
||||
}
|
||||
}
|
||||
}, nil, nil, function(value)
|
||||
Engine.SetDvarInt("cg_drawFps", tonumber(Engine.GetDvarString("ui_cg_drawFps")))
|
||||
end
|
||||
)
|
||||
|
||||
LUI.Options.CreateOptionButton(
|
||||
menu,
|
||||
"ui_cg_drawSpeed",
|
||||
"$_DRAW SPEED",
|
||||
"cg_drawSpeed",
|
||||
"@LUA_MENU_DRAW_SPEED",
|
||||
"Enable or disable drawing the player speed on screen.",
|
||||
{
|
||||
{
|
||||
text = "$_DISABLED",
|
||||
value = "0"
|
||||
text = "@LUA_MENU_ENABLED",
|
||||
value = true
|
||||
},
|
||||
{
|
||||
text = "$_ENABLED",
|
||||
value = "1"
|
||||
text = "@LUA_MENU_DISABLED",
|
||||
value = false
|
||||
}
|
||||
}
|
||||
}, nil, nil, function(value)
|
||||
Engine.SetDvarBool("cg_drawSpeed", Engine.GetDvarString("ui_cg_drawSpeed") == "1")
|
||||
end
|
||||
)
|
||||
|
||||
LUI.Options.CreateOptionButton(
|
||||
menu,
|
||||
"ui_cg_speedGraph",
|
||||
"$_DRAW SPEED GRAPH",
|
||||
"Enable or disable the speed graph.",
|
||||
"cg_speedGraph",
|
||||
"@LUA_MENU_DRAW_SPEEDGRAPH",
|
||||
"@LUA_MENU_DRAW_SPEEDGRAPH_DESC",
|
||||
{
|
||||
{
|
||||
text = "$_DISABLED",
|
||||
value = "0"
|
||||
text = "@LUA_MENU_ENABLED",
|
||||
value = true
|
||||
},
|
||||
{
|
||||
text = "$_ENABLED",
|
||||
value = "1"
|
||||
text = "@LUA_MENU_DISABLED",
|
||||
value = false
|
||||
}
|
||||
}
|
||||
}, nil, nil, function(value)
|
||||
Engine.SetDvarBool("cg_speedGraph", Engine.GetDvarString("ui_cg_speedGraph") == "1")
|
||||
end
|
||||
)
|
||||
|
||||
createdivider(menu, "$_RENDERING")
|
||||
createdivider(menu, "@LUA_MENU_RENDERING")
|
||||
|
||||
LUI.Options.CreateOptionButton(
|
||||
menu,
|
||||
"ui_r_fullbright",
|
||||
"$_FULLBRIGHT",
|
||||
"Change the fullbright mode.",
|
||||
"r_fullbright",
|
||||
"@LUA_MENU_R_FULLBRIGHT",
|
||||
"@LUA_MENU_R_FULLBRIGHT_DESC",
|
||||
{
|
||||
{
|
||||
text = "$_DISABLED",
|
||||
value = "0"
|
||||
text = "@LUA_MENU_DISABLED",
|
||||
value = 0
|
||||
},
|
||||
{
|
||||
text = "$_ENABLED",
|
||||
value = "1"
|
||||
text = "@LUA_MENU_ENABLED",
|
||||
value = 1
|
||||
},
|
||||
{
|
||||
text = "$_MODE 2",
|
||||
value = "2"
|
||||
text = "@LUA_MENU_MODE2",
|
||||
value = 2
|
||||
},
|
||||
{
|
||||
text = "$_MODE 3",
|
||||
value = "3"
|
||||
text = "@LUA_MENU_MODE3",
|
||||
value = 3
|
||||
}
|
||||
}
|
||||
}, nil, nil, function(value)
|
||||
Engine.SetDvarInt("r_fullbright", tonumber(Engine.GetDvarString("ui_r_fullbright")))
|
||||
end
|
||||
)
|
||||
|
||||
LUI.Options.InitScrollingList(menu.list, nil)
|
||||
|
2
deps/GSL
vendored
2
deps/GSL
vendored
@ -1 +1 @@
|
||||
Subproject commit 4377f6e603c64a86c934f1546aa9db482f2e1a4e
|
||||
Subproject commit 383723676cd548d615159701ac3d050f8dd1e128
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
||||
Subproject commit 28c4d8c528527141955006f09124ce672ddfbe3f
|
||||
Subproject commit 21a31b8a338da3341d2b423f85913597b8ec3d63
|
2
deps/curl
vendored
2
deps/curl
vendored
@ -1 +1 @@
|
||||
Subproject commit 049f3765c7016a3f7a92b7f88aae6405c49b84fb
|
||||
Subproject commit 47048e02878c59367db1d42813f32dcce543eed3
|
2
deps/imgui
vendored
2
deps/imgui
vendored
@ -1 +1 @@
|
||||
Subproject commit fc84214988b74179b3941d35393c24ee8ba7a794
|
||||
Subproject commit 22e9093da37f0443f008b947caa6221724e760d6
|
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
||||
Subproject commit 673f5ce29015a9bba3c96792920a10601b5b0718
|
||||
Subproject commit 06a81aeb227424182125363f7554fad5146d6d2a
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
||||
Subproject commit 04e9d1e7a0493910b2eb5e757d623870692ada04
|
||||
Subproject commit 66de86426e9cdb88526974c765108f01554af2b0
|
2
deps/lua
vendored
2
deps/lua
vendored
@ -1 +1 @@
|
||||
Subproject commit 5d708c3f9cae12820e415d4f89c9eacbe2ab964b
|
||||
Subproject commit 8426d9b4d4df1da3c5b2d759e509ae1c50a86667
|
60
deps/premake/protobuf.lua
vendored
60
deps/premake/protobuf.lua
vendored
@ -1,60 +0,0 @@
|
||||
protobuf = {
|
||||
source = path.join(dependencies.basePath, "protobuf"),
|
||||
}
|
||||
|
||||
function protobuf.import()
|
||||
links {
|
||||
"protobuf"
|
||||
}
|
||||
|
||||
protobuf.includes()
|
||||
end
|
||||
|
||||
function protobuf.includes()
|
||||
includedirs {
|
||||
path.join(protobuf.source, "src"),
|
||||
}
|
||||
end
|
||||
|
||||
function protobuf.project()
|
||||
project "protobuf"
|
||||
language "C++"
|
||||
|
||||
protobuf.includes()
|
||||
|
||||
files {
|
||||
path.join(protobuf.source, "src/**.cc"),
|
||||
"./src/**.proto",
|
||||
}
|
||||
|
||||
removefiles {
|
||||
path.join(protobuf.source, "src/**/*test.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/*test*.cc"),
|
||||
|
||||
path.join(protobuf.source, "src/google/protobuf/testing/**.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"),
|
||||
|
||||
path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"),
|
||||
path.join(protobuf.source, "**/*_gcc.cc"),
|
||||
}
|
||||
|
||||
rules {
|
||||
"ProtobufCompiler"
|
||||
}
|
||||
|
||||
defines {
|
||||
"_SCL_SECURE_NO_WARNINGS",
|
||||
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS",
|
||||
"_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS",
|
||||
}
|
||||
|
||||
linkoptions {
|
||||
"-IGNORE:4221"
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, protobuf)
|
1
deps/protobuf
vendored
1
deps/protobuf
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 2f7ee91e326d95915b63918f968244cfefbc022a
|
2
deps/rapidjson
vendored
2
deps/rapidjson
vendored
@ -1 +1 @@
|
||||
Subproject commit e4bde977440d4a00f820b6586899e48a972d2493
|
||||
Subproject commit 8261c1ddf43f10de00fd8c9a67811d1486b2c784
|
@ -1,4 +1,3 @@
|
||||
@echo off
|
||||
git submodule update --init --recursive
|
||||
tools\premake5 %* vs2022
|
||||
pause
|
@ -118,13 +118,13 @@ namespace binding
|
||||
void post_unpack() override
|
||||
{
|
||||
// write all bindings to config file
|
||||
key_write_bindings_to_buffer_hook.create(0x3D3840_b, key_write_bindings_to_buffer_stub);
|
||||
key_write_bindings_to_buffer_hook.create(0x1403D3840, key_write_bindings_to_buffer_stub);
|
||||
|
||||
// links a custom command to an index
|
||||
utils::hook::jump(0x59AE30_b, key_get_binding_for_cmd_stub, true);
|
||||
utils::hook::jump(0x14059AE30, key_get_binding_for_cmd_stub, true);
|
||||
|
||||
// execute custom binds
|
||||
cl_execute_key_hook.create(0x3CF1E0_b, &cl_execute_key_stub);
|
||||
cl_execute_key_hook.create(0x1403CF1E0, &cl_execute_key_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace branding
|
||||
localized_strings::override("MENU_SYSINFO_DONATION_LINK", "Donation Link:");
|
||||
localized_strings::override("MENU_SYSINFO_DONATION_URL", "https://paypal.me/fedecek");
|
||||
|
||||
utils::hook::jump(0x33D550_b, get_build_number_stub, true);
|
||||
utils::hook::jump(0x14033D550, get_build_number_stub, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "chat.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#define chat_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25)
|
||||
|
||||
namespace chat
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct message
|
||||
{
|
||||
std::string text;
|
||||
std::chrono::steady_clock::time_point time;
|
||||
};
|
||||
|
||||
std::deque<message> history;
|
||||
|
||||
float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
float screen_max[2];
|
||||
|
||||
void check_resize()
|
||||
{
|
||||
screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0];
|
||||
screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1];
|
||||
}
|
||||
|
||||
float relative(float value)
|
||||
{
|
||||
const auto ratio = screen_max[0] / 2560.f;
|
||||
|
||||
return value * ratio;
|
||||
}
|
||||
|
||||
void draw_chat()
|
||||
{
|
||||
check_resize();
|
||||
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
for (auto i = 0; i < std::min(15, (int)history.size()); i++)
|
||||
{
|
||||
if (now - history[i].time > 11s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto diff = now - history[i].time;
|
||||
|
||||
float color[4] = { color_white[0], color_white[1], color_white[2], 1.f };
|
||||
|
||||
if (diff > 10.5s)
|
||||
{
|
||||
const auto milliseconds = (float)(11000 - std::chrono::duration_cast<std::chrono::milliseconds>(diff).count());
|
||||
|
||||
color[3] = (float)(milliseconds / 500.f);
|
||||
}
|
||||
|
||||
game::R_AddCmdDrawText(history[i].text.data(), 0x7FFFFFFF, chat_font, relative(15.f), relative(600.f + i * 25), 1.f, 1.f, 0.f, color, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print(const std::string& msg)
|
||||
{
|
||||
message m;
|
||||
m.text = msg;
|
||||
m.time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
history.push_front(m);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop([]()
|
||||
{
|
||||
draw_chat();
|
||||
}, scheduler::pipeline::renderer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(chat::component)
|
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace chat
|
||||
{
|
||||
void print(const std::string& msg);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
#include "command.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "chat.hpp"
|
||||
#include "fastfiles.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
@ -116,7 +115,9 @@ namespace command
|
||||
const auto command = utils::string::to_lower(name);
|
||||
|
||||
if (handlers.find(command) == handlers.end())
|
||||
{
|
||||
add_raw(name, main_handler);
|
||||
}
|
||||
|
||||
handlers[command] = callback;
|
||||
}
|
||||
@ -148,7 +149,7 @@ namespace command
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x5A74F0_b, dvar_command_stub, true);
|
||||
utils::hook::jump(0x1405A74F0, dvar_command_stub, true);
|
||||
|
||||
add("quit", game::Quit);
|
||||
|
||||
@ -156,7 +157,7 @@ namespace command
|
||||
{
|
||||
const auto map = params.get(1);
|
||||
|
||||
const auto exists = utils::hook::invoke<bool>(0x412B50_b, map, 0);
|
||||
const auto exists = utils::hook::invoke<bool>(0x140412B50, map, 0);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
@ -165,12 +166,7 @@ namespace command
|
||||
}
|
||||
|
||||
// SV_SpawnServer
|
||||
utils::hook::invoke<void>(0x6B3AA0_b, map, 0, 0, 0, 0);
|
||||
});
|
||||
|
||||
add("say", [](const params& params)
|
||||
{
|
||||
chat::print(params.join(1));
|
||||
utils::hook::invoke<void>(0x1406B3AA0, map, 0, 0, 0, 0);
|
||||
});
|
||||
|
||||
add("listassetpool", [](const params& params)
|
||||
@ -207,11 +203,6 @@ namespace command
|
||||
}
|
||||
});
|
||||
|
||||
add("baseAddress", []()
|
||||
{
|
||||
printf("%p\n", (void*)game::base_address);
|
||||
});
|
||||
|
||||
add("commandDump", []()
|
||||
{
|
||||
printf("======== Start command dump =========\n");
|
||||
@ -333,8 +324,7 @@ namespace command
|
||||
}
|
||||
else if (arg == "health"s)
|
||||
{
|
||||
|
||||
if (params.size() > 3)
|
||||
if (params.size() > 2)
|
||||
{
|
||||
const auto amount = atoi(params.get(2));
|
||||
const auto health = player.get("health").as<int>();
|
||||
@ -414,7 +404,7 @@ namespace command
|
||||
|
||||
try
|
||||
{
|
||||
const scripting::entity player = scripting::call("getentbynum", {0}).as<scripting::entity>();
|
||||
const auto player = scripting::call("getentbynum", {0}).as<scripting::entity>();
|
||||
if (weapon == "all"s)
|
||||
{
|
||||
player.call("takeallweapons");
|
||||
|
@ -1,24 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "game_console.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
namespace config
|
||||
{
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
dvars::register_bool("cg_autoUpdate", true, game::DvarFlags::DVAR_FLAG_SAVED);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(config::component)
|
@ -158,7 +158,6 @@ namespace exception
|
||||
line("Timestamp: "s + get_timestamp());
|
||||
line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode));
|
||||
line(utils::string::va("Address: 0x%llX", exceptioninfo->ExceptionRecord->ExceptionAddress));
|
||||
line(utils::string::va("Base: 0x%llX", game::base_address));
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
|
@ -51,7 +51,7 @@ namespace fastfiles
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
db_try_load_x_file_internal_hook.create(0x4173B0_b, &db_try_load_x_file_internal);
|
||||
db_try_load_x_file_internal_hook.create(0x1404173B0, &db_try_load_x_file_internal);
|
||||
|
||||
command::add("loadzone", [](const command::params& params)
|
||||
{
|
||||
|
56
src/client/component/filesystem.cpp
Normal file
56
src/client/component/filesystem.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace filesystem
|
||||
{
|
||||
std::unordered_set<std::string>& get_search_paths()
|
||||
{
|
||||
static std::unordered_set<std::string> search_paths{};
|
||||
return search_paths;
|
||||
}
|
||||
|
||||
std::string read_file(const std::string& path)
|
||||
{
|
||||
for (const auto& search_path : get_search_paths())
|
||||
{
|
||||
const auto path_ = search_path + "/" + path;
|
||||
if (utils::io::file_exists(path_))
|
||||
{
|
||||
return utils::io::read_file(path_);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool read_file(const std::string& path, std::string* data)
|
||||
{
|
||||
for (const auto& search_path : get_search_paths())
|
||||
{
|
||||
const auto path_ = search_path + "/" + path;
|
||||
if (utils::io::read_file(path_, data))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
get_search_paths().insert(".");
|
||||
get_search_paths().insert("h2-mod");
|
||||
get_search_paths().insert("data");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(filesystem::component)
|
8
src/client/component/filesystem.hpp
Normal file
8
src/client/component/filesystem.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace filesystem
|
||||
{
|
||||
std::unordered_set<std::string>& get_search_paths();
|
||||
std::string read_file(const std::string& path);
|
||||
bool read_file(const std::string& path, std::string* data);
|
||||
}
|
131
src/client/component/fonts.cpp
Normal file
131
src/client/component/fonts.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "fonts.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/image.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace fonts
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct font_data_t
|
||||
{
|
||||
std::unordered_map<std::string, game::TTF*> fonts;
|
||||
std::unordered_map<std::string, std::string> raw_fonts;
|
||||
};
|
||||
|
||||
utils::concurrency::container<font_data_t> font_data;
|
||||
|
||||
game::TTF* create_font(const std::string& name, const std::string& data)
|
||||
{
|
||||
const auto font = utils::memory::get_allocator()->allocate<game::TTF>();
|
||||
font->name = utils::memory::get_allocator()->duplicate_string(name);
|
||||
font->buffer = utils::memory::get_allocator()->duplicate_string(data);
|
||||
font->len = static_cast<int>(data.size());
|
||||
font->fontFace = 0;
|
||||
return font;
|
||||
}
|
||||
|
||||
void free_font(game::TTF* font)
|
||||
{
|
||||
utils::memory::get_allocator()->free(font->buffer);
|
||||
utils::memory::get_allocator()->free(font->name);
|
||||
utils::memory::get_allocator()->free(font);
|
||||
}
|
||||
|
||||
game::TTF* load_font(const std::string& name)
|
||||
{
|
||||
return font_data.access<game::TTF*>([&](font_data_t& data_) -> game::TTF*
|
||||
{
|
||||
if (const auto i = data_.fonts.find(name); i != data_.fonts.end())
|
||||
{
|
||||
return i->second;
|
||||
}
|
||||
|
||||
std::string data{};
|
||||
if (const auto i = data_.raw_fonts.find(name); i != data_.raw_fonts.end())
|
||||
{
|
||||
data = i->second;
|
||||
}
|
||||
|
||||
if (data.empty() && !filesystem::read_file(name, &data))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto material = create_font(name, data);
|
||||
data_.fonts[name] = material;
|
||||
|
||||
return material;
|
||||
});
|
||||
}
|
||||
|
||||
game::TTF* try_load_font(const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return load_font(name);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Failed to load font %s: %s\n", name.data(), e.what());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
game::TTF* db_find_xasset_header_stub(game::XAssetType type, const char* name, int create_default)
|
||||
{
|
||||
auto result = try_load_font(name);
|
||||
if (result == nullptr)
|
||||
{
|
||||
result = game::DB_FindXAssetHeader(type, name, create_default).ttf;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void add(const std::string& name, const std::string& data)
|
||||
{
|
||||
font_data.access([&](font_data_t& data_)
|
||||
{
|
||||
data_.raw_fonts[name] = data;
|
||||
});
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
font_data.access([&](font_data_t& data_)
|
||||
{
|
||||
for (auto& font : data_.fonts)
|
||||
{
|
||||
free_font(font.second);
|
||||
}
|
||||
|
||||
data_.fonts.clear();
|
||||
utils::hook::set<int>(0x14EE3ACB8, 0); // reset registered font count
|
||||
});
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::call(0x140747096, db_find_xasset_header_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(fonts::component)
|
7
src/client/component/fonts.hpp
Normal file
7
src/client/component/fonts.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace fonts
|
||||
{
|
||||
void add(const std::string& name, const std::string& data);
|
||||
void clear();
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "chat.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
@ -303,7 +302,7 @@ namespace fps
|
||||
{
|
||||
scheduler::loop(draw, scheduler::pipeline::renderer);
|
||||
|
||||
sub_7C55D0_hook.create(0x7C55D0_b, perf_update);
|
||||
sub_7C55D0_hook.create(0x1407C55D0, perf_update);
|
||||
|
||||
cg_drawSpeed = dvars::register_bool("cg_drawSpeed", 0, game::DVAR_FLAG_SAVED);
|
||||
cg_drawFps = dvars::register_int("cg_drawFPS", 0, 0, 4, game::DVAR_FLAG_SAVED);
|
||||
|
@ -46,10 +46,10 @@ namespace gameplay
|
||||
a.jnz(allsolid);
|
||||
|
||||
a.bind(stand);
|
||||
a.jmp(0x6878CD_b);
|
||||
a.jmp(0x1406878CD);
|
||||
|
||||
a.bind(allsolid);
|
||||
a.jmp(0x6878D4_b);
|
||||
a.jmp(0x1406878D4);
|
||||
}
|
||||
|
||||
void pm_crashland_stub(void* ps, void* pm)
|
||||
@ -70,12 +70,12 @@ namespace gameplay
|
||||
dvars::jump_enableFallDamage = dvars::register_bool("jump_enableFallDamage", true, game::DVAR_FLAG_REPLICATED);
|
||||
|
||||
// Influence PM_JitterPoint code flow so the trace->startsolid checks are 'ignored'
|
||||
pm_player_trace_hook.create(0x068F0A0_b, &pm_player_trace_stub);
|
||||
pm_player_trace_hook.create(0x14068F0A0, &pm_player_trace_stub);
|
||||
|
||||
// If g_enableElevators is 1 the 'ducked' flag will always be removed from the player state
|
||||
utils::hook::jump(0x6878C1_b, utils::hook::assemble(pm_trace_stub), true);
|
||||
utils::hook::jump(0x1406878C1, utils::hook::assemble(pm_trace_stub), true);
|
||||
|
||||
pm_crashland_hook.create(0x688A20_b, pm_crashland_stub);
|
||||
pm_crashland_hook.create(0x140688A20, pm_crashland_stub);
|
||||
|
||||
dvars::register_float("jump_height", 39, 0, 1000, game::DVAR_FLAG_REPLICATED);
|
||||
dvars::register_float("g_gravity", 800, 1, 1000, game::DVAR_FLAG_REPLICATED);
|
||||
|
@ -208,7 +208,7 @@ namespace gui
|
||||
a.call_aligned(rbx);
|
||||
a.mov(ecx, eax);
|
||||
|
||||
a.jmp(0x7A14D1_b);
|
||||
a.jmp(0x1407A14D1);
|
||||
}
|
||||
|
||||
utils::hook::detour wnd_proc_hook;
|
||||
@ -301,8 +301,8 @@ namespace gui
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x7A14C4_b, utils::hook::assemble(dxgi_swap_chain_present_stub), true);
|
||||
wnd_proc_hook.create(0x650F10_b, wnd_proc_stub);
|
||||
utils::hook::jump(0x1407A14C4, utils::hook::assemble(dxgi_swap_chain_present_stub), true);
|
||||
wnd_proc_hook.create(0x140650F10, wnd_proc_stub);
|
||||
|
||||
on_frame([]()
|
||||
{
|
||||
@ -312,10 +312,13 @@ namespace gui
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
ImGui_ImplWin32_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,13 +22,13 @@ namespace asset_list
|
||||
|
||||
void on_frame()
|
||||
{
|
||||
if (!gui::enabled_menus["asset_list"])
|
||||
static auto* enabled = &gui::enabled_menus["asset_list"];
|
||||
if (!*enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ImGui::Begin("Asset list", &gui::enabled_menus["asset_list"]);
|
||||
ImGui::Begin("Asset list", enabled);
|
||||
|
||||
ImGui::InputText("asset type", &asset_type_filter);
|
||||
ImGui::BeginChild("asset type list");
|
||||
@ -46,7 +46,6 @@ namespace asset_list
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace gui_console
|
||||
namespace gui::console
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -52,7 +52,7 @@ namespace gui_console
|
||||
}
|
||||
case ImGuiInputTextFlags_CallbackHistory:
|
||||
{
|
||||
const auto history = game_console::get_history();
|
||||
const auto& history = game_console::get_history();
|
||||
|
||||
if (data->EventKey == ImGuiKey_UpArrow)
|
||||
{
|
||||
@ -96,7 +96,7 @@ namespace gui_console
|
||||
{
|
||||
std::string text{};
|
||||
|
||||
const auto output = game_console::get_output();
|
||||
const auto& output = game_console::get_output();
|
||||
for (const auto& line : output)
|
||||
{
|
||||
if (utils::string::find_lower(line, filter))
|
||||
@ -116,7 +116,8 @@ namespace gui_console
|
||||
|
||||
void on_frame()
|
||||
{
|
||||
if (!gui::enabled_menus["console"])
|
||||
static auto* enabled = &gui::enabled_menus["console"];
|
||||
if (!*enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -126,7 +127,7 @@ namespace gui_console
|
||||
static const auto input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion |
|
||||
ImGuiInputTextFlags_CallbackHistory;
|
||||
|
||||
ImGui::Begin("Console", &gui::enabled_menus["console"]);
|
||||
ImGui::Begin("Console", enabled);
|
||||
|
||||
if (ImGui::BeginPopup("Options"))
|
||||
{
|
||||
@ -159,7 +160,7 @@ namespace gui_console
|
||||
|
||||
ImGui::BeginChild("console_scroll", ImVec2(0, -footer_height_to_reserve), false);
|
||||
|
||||
const auto output = game_console::get_output();
|
||||
const auto& output = game_console::get_output();
|
||||
for (const auto& line : output)
|
||||
{
|
||||
if (utils::string::find_lower(line, filter))
|
||||
@ -177,7 +178,7 @@ namespace gui_console
|
||||
|
||||
if (ImGui::InputText("Input", &input, input_text_flags, input_text_edit))
|
||||
{
|
||||
auto history = game_console::get_history();
|
||||
auto& history = game_console::get_history();
|
||||
|
||||
if (history_index != -1)
|
||||
{
|
||||
@ -209,4 +210,4 @@ namespace gui_console
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(gui_console::component)
|
||||
REGISTER_COMPONENT(gui::console::component)
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace gui_debug
|
||||
namespace gui::debug
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -403,12 +403,13 @@ namespace gui_debug
|
||||
|
||||
void draw_window()
|
||||
{
|
||||
if (!gui::enabled_menus["debug"])
|
||||
static auto* enabled = &gui::enabled_menus["debug"];
|
||||
if (!*enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Begin("Debug", &gui::enabled_menus["debug"]);
|
||||
ImGui::Begin("Debug", enabled);
|
||||
|
||||
if (ImGui::TreeNode("Path nodes"))
|
||||
{
|
||||
@ -724,4 +725,4 @@ namespace gui_debug
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(gui_debug::component)
|
||||
REGISTER_COMPONENT(gui::debug::component)
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace entity_list
|
||||
namespace gui::entity_list
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -593,8 +593,9 @@ namespace entity_list
|
||||
|
||||
void show_entity_list_window(data_t& data)
|
||||
{
|
||||
static auto* enabled = &gui::enabled_menus["entity_list"];
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(500, 500), ImVec2(1000, 1000));
|
||||
ImGui::Begin("Entity list", &gui::enabled_menus["entity_list"]);
|
||||
ImGui::Begin("Entity list", enabled);
|
||||
|
||||
if (ImGui::Button("Update list"))
|
||||
{
|
||||
@ -808,7 +809,8 @@ namespace entity_list
|
||||
|
||||
void on_frame()
|
||||
{
|
||||
if (!gui::enabled_menus["entity_list"])
|
||||
static auto* enabled = &gui::enabled_menus["entity_list"];
|
||||
if (!*enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -858,4 +860,4 @@ namespace entity_list
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(entity_list::component)
|
||||
REGISTER_COMPONENT(gui::entity_list::component)
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace gui_script_console
|
||||
namespace gui::script_console
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -228,4 +228,4 @@ namespace gui_script_console
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(gui_script_console::component)
|
||||
REGISTER_COMPONENT(gui::script_console::component)
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "images.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
@ -29,7 +32,7 @@ namespace images
|
||||
}
|
||||
});
|
||||
|
||||
if (data.empty() && !utils::io::read_file(utils::string::va("images/%s.png", image->name), &data))
|
||||
if (data.empty() && !filesystem::read_file(utils::string::va("images/%s.png", image->name), &data))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@ -111,8 +114,8 @@ namespace images
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
setup_texture_hook.create(0x74A390_b, setup_texture_stub);
|
||||
load_texture_hook.create(0x2A7940_b, load_texture_stub);
|
||||
setup_texture_hook.create(0x14074A390, setup_texture_stub);
|
||||
load_texture_hook.create(0x1402A7940, load_texture_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "game_console.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "game/ui_scripting/lua/engine.hpp"
|
||||
#include "game/ui_scripting/execution.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
@ -25,7 +26,11 @@ namespace input
|
||||
|
||||
void cl_char_event_stub(const int local_client_num, const int key)
|
||||
{
|
||||
ui_scripting::lua::engine::ui_event("char", {key});
|
||||
ui_scripting::notify("keypress",
|
||||
{
|
||||
{"keynum", key},
|
||||
{"key", game::Key_KeynumToString(key, 0, 1)},
|
||||
});
|
||||
|
||||
if (!game_console::console_char_event(local_client_num, key))
|
||||
{
|
||||
@ -42,7 +47,11 @@ namespace input
|
||||
|
||||
void cl_key_event_stub(const int local_client_num, const int key, const int down)
|
||||
{
|
||||
ui_scripting::lua::engine::ui_event("key", {key, down});
|
||||
ui_scripting::notify(down ? "keydown" : "keyup",
|
||||
{
|
||||
{"keynum", key},
|
||||
{"key", game::Key_KeynumToString(key, 0, 1)},
|
||||
});
|
||||
|
||||
if (!game_console::console_key_event(local_client_num, key, down))
|
||||
{
|
||||
@ -64,7 +73,6 @@ namespace input
|
||||
return;
|
||||
}
|
||||
|
||||
ui_scripting::lua::engine::ui_event("mousemove", {x, y});
|
||||
cl_mouse_move_hook.invoke<void>(local_client_num, x, y);
|
||||
}
|
||||
}
|
||||
@ -74,9 +82,9 @@ namespace input
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
cl_char_event_hook.create(0x3D27B0_b, cl_char_event_stub);
|
||||
cl_key_event_hook.create(0x3D2AE0_b, cl_key_event_stub);
|
||||
cl_mouse_move_hook.create(0x3296F0_b, cl_mouse_move_stub);
|
||||
cl_char_event_hook.create(0x1403D27B0, cl_char_event_stub);
|
||||
cl_key_event_hook.create(0x1403D2AE0, cl_key_event_stub);
|
||||
cl_mouse_move_hook.create(0x1403296F0, cl_mouse_move_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace localized_strings
|
||||
void post_unpack() override
|
||||
{
|
||||
// Change some localized strings
|
||||
seh_string_ed_get_string_hook.create(0x5E5FD0_b, &seh_string_ed_get_string);
|
||||
seh_string_ed_get_string_hook.create(0x1405E5FD0, &seh_string_ed_get_string);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -142,10 +142,10 @@ namespace logger
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x32C620_b, print_warning, true);
|
||||
utils::hook::jump(0x32C630_b, print_warning, true);
|
||||
utils::hook::jump(0x32AEF0_b, lui_print, true);
|
||||
com_error_hook.create(0x5A2D80_b, com_error_stub);
|
||||
utils::hook::jump(0x14032C620, print_warning, true);
|
||||
utils::hook::jump(0x14032C630, print_warning, true);
|
||||
utils::hook::jump(0x14032AEF0, lui_print, true);
|
||||
com_error_hook.create(0x1405A2D80, com_error_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ namespace lui
|
||||
|
||||
command::add("lui_restart", []()
|
||||
{
|
||||
utils::hook::invoke<void>(0x3203B0_b);
|
||||
utils::hook::invoke<void>(0x32D370_b);
|
||||
utils::hook::invoke<void>(0x1403203B0);
|
||||
utils::hook::invoke<void>(0x14032D370);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
200
src/client/component/materials.cpp
Normal file
200
src/client/component/materials.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "materials.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/image.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace materials
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour db_material_streaming_fail_hook;
|
||||
utils::hook::detour material_register_handle_hook;
|
||||
utils::hook::detour db_get_material_index_hook;
|
||||
|
||||
struct material_data_t
|
||||
{
|
||||
std::unordered_map<std::string, game::Material*> materials;
|
||||
std::unordered_map<std::string, std::string> images;
|
||||
};
|
||||
|
||||
char constant_table[0x20] = {};
|
||||
|
||||
utils::concurrency::container<material_data_t> material_data;
|
||||
|
||||
game::GfxImage* setup_image(game::GfxImage* image, const utils::image& raw_image)
|
||||
{
|
||||
image->imageFormat = 0x1000003;
|
||||
image->resourceSize = -1;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA data{};
|
||||
data.SysMemPitch = raw_image.get_width() * 4;
|
||||
data.SysMemSlicePitch = data.SysMemPitch * raw_image.get_height();
|
||||
data.pSysMem = raw_image.get_buffer();
|
||||
|
||||
game::Image_Setup(image, raw_image.get_width(), raw_image.get_height(), image->depth, image->numElements,
|
||||
image->imageFormat, DXGI_FORMAT_R8G8B8A8_UNORM, 0, image->name, &data);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
game::Material* create_material(const std::string& name, const std::string& data)
|
||||
{
|
||||
const auto white = *reinterpret_cast<game::Material**>(0x141B09208);
|
||||
|
||||
const auto material = utils::memory::get_allocator()->allocate<game::Material>();
|
||||
const auto texture_table = utils::memory::get_allocator()->allocate<game::MaterialTextureDef>();
|
||||
const auto image = utils::memory::get_allocator()->allocate<game::GfxImage>();
|
||||
|
||||
std::memcpy(material, white, sizeof(game::Material));
|
||||
std::memcpy(texture_table, white->textureTable, sizeof(game::MaterialTextureDef));
|
||||
std::memcpy(image, white->textureTable->u.image, sizeof(game::GfxImage));
|
||||
|
||||
material->constantTable = &constant_table;
|
||||
material->name = utils::memory::get_allocator()->duplicate_string(name);
|
||||
image->name = material->name;
|
||||
|
||||
material->textureTable = texture_table;
|
||||
material->textureTable->u.image = setup_image(image, data);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
void free_material(game::Material* material)
|
||||
{
|
||||
material->textureTable->u.image->textures.___u0.map->Release();
|
||||
material->textureTable->u.image->textures.shaderView->Release();
|
||||
utils::memory::get_allocator()->free(material->textureTable->u.image);
|
||||
utils::memory::get_allocator()->free(material->textureTable);
|
||||
utils::memory::get_allocator()->free(material->name);
|
||||
utils::memory::get_allocator()->free(material);
|
||||
}
|
||||
|
||||
game::Material* load_material(const std::string& name)
|
||||
{
|
||||
return material_data.access<game::Material*>([&](material_data_t& data_) -> game::Material*
|
||||
{
|
||||
if (const auto i = data_.materials.find(name); i != data_.materials.end())
|
||||
{
|
||||
return i->second;
|
||||
}
|
||||
|
||||
std::string data{};
|
||||
if (const auto i = data_.images.find(name); i != data_.images.end())
|
||||
{
|
||||
data = i->second;
|
||||
}
|
||||
|
||||
if (data.empty() && !filesystem::read_file(utils::string::va("materials/%s.png", name.data()), &data))
|
||||
{
|
||||
data_.materials[name] = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto material = create_material(name, data);
|
||||
data_.materials[name] = material;
|
||||
|
||||
return material;
|
||||
});
|
||||
}
|
||||
|
||||
game::Material* try_load_material(const std::string& name)
|
||||
{
|
||||
if (name == "white")
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return load_material(name);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Failed to load material %s: %s\n", name.data(), e.what());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
game::Material* material_register_handle_stub(const char* name)
|
||||
{
|
||||
auto result = try_load_material(name);
|
||||
if (result == nullptr)
|
||||
{
|
||||
result = material_register_handle_hook.invoke<game::Material*>(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int db_material_streaming_fail_stub(game::Material* material)
|
||||
{
|
||||
if (material->constantTable == &constant_table)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return db_material_streaming_fail_hook.invoke<int>(material);
|
||||
}
|
||||
|
||||
unsigned int db_get_material_index_stub(game::Material* material)
|
||||
{
|
||||
if (material->constantTable == &constant_table)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return db_get_material_index_hook.invoke<unsigned int>(material);
|
||||
}
|
||||
}
|
||||
|
||||
void add(const std::string& name, const std::string& data)
|
||||
{
|
||||
material_data.access([&](material_data_t& data_)
|
||||
{
|
||||
data_.images[name] = data;
|
||||
});
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
material_data.access([&](material_data_t& data_)
|
||||
{
|
||||
for (auto& material : data_.materials)
|
||||
{
|
||||
if (material.second == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
free_material(material.second);
|
||||
}
|
||||
|
||||
data_.materials.clear();
|
||||
});
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
material_register_handle_hook.create(game::Material_RegisterHandle.get(), material_register_handle_stub);
|
||||
db_material_streaming_fail_hook.create(0x14041D140, db_material_streaming_fail_stub);
|
||||
db_get_material_index_hook.create(0x140413BC0, db_get_material_index_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(materials::component)
|
7
src/client/component/materials.hpp
Normal file
7
src/client/component/materials.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace materials
|
||||
{
|
||||
void add(const std::string& name, const std::string& data);
|
||||
void clear();
|
||||
}
|
@ -6,12 +6,45 @@
|
||||
#include "command.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "materials.hpp"
|
||||
#include "fonts.hpp"
|
||||
#include "mods.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace mods
|
||||
{
|
||||
std::string mod_path{};
|
||||
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour db_release_xassets_hook;
|
||||
bool release_assets = false;
|
||||
|
||||
void db_release_xassets_stub()
|
||||
{
|
||||
if (release_assets)
|
||||
{
|
||||
materials::clear();
|
||||
fonts::clear();
|
||||
}
|
||||
|
||||
db_release_xassets_hook.invoke<void>();
|
||||
}
|
||||
|
||||
void restart()
|
||||
{
|
||||
scheduler::once([]()
|
||||
{
|
||||
release_assets = true;
|
||||
game::Com_Shutdown("");
|
||||
release_assets = false;
|
||||
}, scheduler::pipeline::main);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
@ -22,6 +55,8 @@ namespace mods
|
||||
utils::io::create_directory("mods");
|
||||
}
|
||||
|
||||
db_release_xassets_hook.create(0x140416A80, db_release_xassets_stub);
|
||||
|
||||
command::add("loadmod", [](const command::params& params)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
@ -30,7 +65,7 @@ namespace mods
|
||||
return;
|
||||
}
|
||||
|
||||
if (::game::SV_Loaded())
|
||||
if (!game::Com_InFrontend())
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Cannot load mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
@ -38,44 +73,38 @@ namespace mods
|
||||
}
|
||||
|
||||
const auto path = params.get(1);
|
||||
game_console::print(game_console::con_type_info, "Loading mod %s\n", path);
|
||||
|
||||
if (!utils::io::directory_exists(path))
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Mod %s not found!\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
game::mod_folder = path;
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
command::execute("lui_restart", true);
|
||||
}, scheduler::pipeline::renderer);
|
||||
game_console::print(game_console::con_type_info, "Loading mod %s\n", path);
|
||||
filesystem::get_search_paths().erase(mod_path);
|
||||
filesystem::get_search_paths().insert(path);
|
||||
mod_path = path;
|
||||
restart();
|
||||
});
|
||||
|
||||
command::add("unloadmod", [](const command::params& params)
|
||||
{
|
||||
if (game::mod_folder.empty())
|
||||
if (mod_path.empty())
|
||||
{
|
||||
game_console::print(game_console::con_type_info, "No mod loaded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (::game::SV_Loaded())
|
||||
if (!game::Com_InFrontend())
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Cannot unload mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
return;
|
||||
}
|
||||
|
||||
game_console::print(game_console::con_type_info, "Unloading mod %s\n", game::mod_folder.data());
|
||||
game::mod_folder.clear();
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
command::execute("lui_restart", true);
|
||||
}, scheduler::pipeline::renderer);
|
||||
game_console::print(game_console::con_type_info, "Unloading mod %s\n", mod_path.data());
|
||||
filesystem::get_search_paths().erase(mod_path);
|
||||
mod_path.clear();
|
||||
restart();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
6
src/client/component/mods.hpp
Normal file
6
src/client/component/mods.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace mods
|
||||
{
|
||||
extern std::string mod_path;
|
||||
}
|
@ -32,20 +32,20 @@ namespace notifies
|
||||
{
|
||||
if (vm_execute_hooks.find(pos) == vm_execute_hooks.end())
|
||||
{
|
||||
hook_enabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hook_enabled && pos > (char*)vm_execute_hooks.size())
|
||||
if (!hook_enabled && pos > reinterpret_cast<char*>(vm_execute_hooks.size()))
|
||||
{
|
||||
hook_enabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto hook = vm_execute_hooks[pos];
|
||||
const auto& hook = vm_execute_hooks[pos];
|
||||
const auto state = hook.lua_state();
|
||||
|
||||
const auto self_id = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
|
||||
const auto self = scripting::entity(self_id);
|
||||
const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
|
||||
|
||||
std::vector<sol::lua_value> args;
|
||||
|
||||
@ -59,16 +59,6 @@ namespace notifies
|
||||
const auto result = hook(self, sol::as_args(args));
|
||||
scripting::lua::handle_error(result);
|
||||
|
||||
const auto value = scripting::lua::convert({state, result});
|
||||
const auto type = value.get_raw().type;
|
||||
|
||||
game::Scr_ClearOutParams();
|
||||
|
||||
if (result.valid() && type && type < game::SCRIPT_END)
|
||||
{
|
||||
scripting::push_value(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -94,12 +84,12 @@ namespace notifies
|
||||
a.inc(r14);
|
||||
a.mov(dword_ptr(rbp, 0xA4), r15d);
|
||||
|
||||
a.jmp(0x5C90B3_b);
|
||||
a.jmp(0x1405C90B3);
|
||||
|
||||
a.bind(replace);
|
||||
|
||||
a.popad64();
|
||||
a.mov(r14, (char*)empty_function);
|
||||
a.mov(r14, reinterpret_cast<char*>(empty_function));
|
||||
a.jmp(end);
|
||||
}
|
||||
|
||||
@ -137,7 +127,7 @@ namespace notifies
|
||||
|
||||
std::string convert_mod(const int meansOfDeath)
|
||||
{
|
||||
const auto value = reinterpret_cast<game::scr_string_t**>(0xBF49B0_b)[meansOfDeath];
|
||||
const auto value = reinterpret_cast<game::scr_string_t**>(0x140BF49B0)[meansOfDeath];
|
||||
const auto string = game::SL_ConvertToString(*value);
|
||||
|
||||
return string;
|
||||
@ -147,7 +137,7 @@ namespace notifies
|
||||
int damage, int dflags, const unsigned int hitLoc, const unsigned int weapon, bool isAlternate, unsigned int a11, const int meansOfDeath, unsigned int a13, unsigned int a14)
|
||||
{
|
||||
{
|
||||
const std::string _hitLoc = reinterpret_cast<const char**>(0xBF4AA0_b)[hitLoc];
|
||||
const std::string _hitLoc = reinterpret_cast<const char**>(0x140BF4AA0)[hitLoc];
|
||||
const auto _mod = convert_mod(meansOfDeath);
|
||||
const auto _weapon = get_weapon_name(weapon, isAlternate);
|
||||
|
||||
@ -199,9 +189,9 @@ namespace notifies
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x5C90A5_b, utils::hook::assemble(vm_execute_stub), true);
|
||||
utils::hook::jump(0x1405C90A5, utils::hook::assemble(vm_execute_stub), true);
|
||||
|
||||
scr_entity_damage_hook.create(0x4BD2E0_b, scr_entity_damage_stub);
|
||||
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace patches
|
||||
|
||||
void* sub_46148()
|
||||
{
|
||||
static uint64_t off_11C52460 = 0xAD0C58_b;
|
||||
static uint64_t off_11C52460 = 0x140AD0C58;
|
||||
return &off_11C52460;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ namespace patches
|
||||
|
||||
void gscr_set_save_dvar_stub()
|
||||
{
|
||||
const auto string = utils::string::to_lower(utils::hook::invoke<const char*>(0x5C7C20_b, 0));
|
||||
const auto string = utils::string::to_lower(utils::hook::invoke<const char*>(0x1405C7C20, 0));
|
||||
if (string == "cg_fov" || string == "cg_fovscale")
|
||||
{
|
||||
return;
|
||||
@ -65,24 +65,24 @@ namespace patches
|
||||
void post_unpack() override
|
||||
{
|
||||
// Fix startup crashes
|
||||
utils::hook::set(0x633080_b, 0xC301B0);
|
||||
utils::hook::set(0x272F70_b, 0xC301B0);
|
||||
utils::hook::jump(0x46148_b, sub_46148, true);
|
||||
utils::hook::set(0x140633080, 0xC301B0);
|
||||
utils::hook::set(0x140272F70, 0xC301B0);
|
||||
utils::hook::jump(0x140046148, sub_46148, true);
|
||||
|
||||
utils::hook::jump(0x64EF10_b, quit_stub, true);
|
||||
utils::hook::jump(0x14064EF10, quit_stub, true);
|
||||
|
||||
// Unlock fps in main menu
|
||||
utils::hook::set<BYTE>(0x3D8E1B_b, 0xEB);
|
||||
utils::hook::set<BYTE>(0x1403D8E1B, 0xEB);
|
||||
|
||||
// Disable battle net popup
|
||||
utils::hook::nop(0x5F4496_b, 5);
|
||||
utils::hook::nop(0x1405F4496, 5);
|
||||
|
||||
// Allow kbam input when gamepad is enabled
|
||||
utils::hook::nop(0x3D2F8E_b, 2);
|
||||
utils::hook::nop(0x3D0C9C_b, 6);
|
||||
utils::hook::nop(0x1403D2F8E, 2);
|
||||
utils::hook::nop(0x1403D0C9C, 6);
|
||||
|
||||
// Prevent game from overriding cg_fov and cg_fovscale values
|
||||
gscr_set_save_dvar_hook.create(0x504C60_b, &gscr_set_save_dvar_stub);
|
||||
gscr_set_save_dvar_hook.create(0x140504C60, &gscr_set_save_dvar_stub);
|
||||
|
||||
// Make cg_fov and cg_fovscale saved dvars
|
||||
|
||||
|
@ -63,8 +63,8 @@ namespace renderer
|
||||
{
|
||||
dvars::r_fullbright = dvars::register_int("r_fullbright", 0, 0, 3, game::DVAR_FLAG_SAVED);
|
||||
|
||||
r_init_draw_method_hook.create(0x72F950_b, &r_init_draw_method_stub);
|
||||
r_update_front_end_dvar_options_hook.create(0x76EE70_b, &r_update_front_end_dvar_options_stub);
|
||||
r_init_draw_method_hook.create(0x14072F950, &r_init_draw_method_stub);
|
||||
r_update_front_end_dvar_options_hook.create(0x14076EE70, &r_update_front_end_dvar_options_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -183,9 +183,9 @@ namespace scheduler
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
r_end_frame_hook.create(0x76D7B0_b, scheduler::r_end_frame_stub);
|
||||
g_run_frame_hook.create(0x4CB030_b, scheduler::server_frame_stub);
|
||||
main_frame_hook.create(0x417FA0_b, scheduler::main_frame_stub);
|
||||
r_end_frame_hook.create(0x14076D7B0, scheduler::r_end_frame_stub);
|
||||
g_run_frame_hook.create(0x1404CB030, scheduler::server_frame_stub);
|
||||
main_frame_hook.create(0x140417FA0, scheduler::main_frame_stub);
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
|
@ -25,7 +25,8 @@ namespace scripting
|
||||
utils::hook::detour vm_notify_hook;
|
||||
|
||||
utils::hook::detour g_shutdown_game_hook;
|
||||
utils::hook::detour player_spawn_hook;
|
||||
utils::hook::detour client_spawn_hook;
|
||||
utils::hook::detour sv_check_load_level_hook;
|
||||
|
||||
utils::hook::detour scr_add_class_field_hook;
|
||||
|
||||
@ -55,9 +56,9 @@ namespace scripting
|
||||
vm_notify_hook.invoke<void>(notify_list_owner_id, string_value, top);
|
||||
}
|
||||
|
||||
void player_spawn_stub(const game::gentity_s* player)
|
||||
void client_spawn_stub(const game::gentity_s* client)
|
||||
{
|
||||
player_spawn_hook.invoke<void>(player);
|
||||
client_spawn_hook.invoke<void>(client);
|
||||
lua::engine::start();
|
||||
}
|
||||
|
||||
@ -67,16 +68,16 @@ namespace scripting
|
||||
g_shutdown_game_hook.invoke<void>(free_scripts);
|
||||
}
|
||||
|
||||
void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t _name, unsigned int canonicalString, unsigned int offset)
|
||||
void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t name, unsigned int canonicalString, unsigned int offset)
|
||||
{
|
||||
const auto name = game::SL_ConvertToString(_name);
|
||||
const auto name_ = game::SL_ConvertToString(name);
|
||||
|
||||
if (fields_table[classnum].find(name) == fields_table[classnum].end())
|
||||
if (fields_table[classnum].find(name_) == fields_table[classnum].end())
|
||||
{
|
||||
fields_table[classnum][name] = offset;
|
||||
fields_table[classnum][name_] = offset;
|
||||
}
|
||||
|
||||
scr_add_class_field_hook.invoke<void>(classnum, _name, canonicalString, offset);
|
||||
scr_add_class_field_hook.invoke<void>(classnum, name, canonicalString, offset);
|
||||
}
|
||||
|
||||
void process_script_stub(const char* filename)
|
||||
@ -99,11 +100,10 @@ namespace scripting
|
||||
scr_set_thread_position_hook.invoke<void>(threadName, codePos);
|
||||
}
|
||||
|
||||
utils::hook::detour sub_6B2940_hook;
|
||||
char sub_6B2940_stub(void* a1)
|
||||
char sv_check_load_level_stub(void* save_game)
|
||||
{
|
||||
const auto result = sub_6B2940_hook.invoke<char>(a1);
|
||||
if (a1 != nullptr)
|
||||
const auto result = sv_check_load_level_hook.invoke<char>(save_game);
|
||||
if (save_game != nullptr)
|
||||
{
|
||||
lua::engine::start();
|
||||
}
|
||||
@ -116,19 +116,15 @@ namespace scripting
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
vm_notify_hook.create(0x5CC450_b, vm_notify_stub);
|
||||
vm_notify_hook.create(0x1405CC450, vm_notify_stub);
|
||||
|
||||
g_shutdown_game_hook.create(0x4CBAD0_b, g_shutdown_game_stub);
|
||||
player_spawn_hook.create(0x4B0710_b, player_spawn_stub);
|
||||
g_shutdown_game_hook.create(0x1404CBAD0, g_shutdown_game_stub);
|
||||
client_spawn_hook.create(0x1404B0710, client_spawn_stub);
|
||||
sv_check_load_level_hook.create(0x1406B2940, sv_check_load_level_stub);
|
||||
|
||||
scr_add_class_field_hook.create(0x5C2C30_b, scr_add_class_field_stub);
|
||||
scr_set_thread_position_hook.create(0x5BC7E0_b, scr_set_thread_position_stub);
|
||||
process_script_hook.create(0x5C6160_b, process_script_stub);
|
||||
|
||||
// Loading last checkpoint doesn't call spawn player again (player_spawn_hook)
|
||||
// Not sure what this function does but `a1` is != nullptr when loading
|
||||
// the last checkpoint so we need to start lua in this context
|
||||
sub_6B2940_hook.create(0x6B2940_b, sub_6B2940_stub);
|
||||
scr_add_class_field_hook.create(0x1405C2C30, scr_add_class_field_stub);
|
||||
scr_set_thread_position_hook.create(0x1405BC7E0, scr_set_thread_position_stub);
|
||||
process_script_hook.create(0x1405C6160, process_script_stub);
|
||||
|
||||
scheduler::loop([]()
|
||||
{
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "chat.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
@ -27,8 +26,12 @@ namespace ui_scripting
|
||||
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 lui_error_hook;
|
||||
utils::hook::detour hksi_hks_error_hook;
|
||||
utils::hook::detour hks_frame_hook;
|
||||
|
||||
bool error_hook_enabled = false;
|
||||
int error_hook_enabled = 0;
|
||||
|
||||
void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...)
|
||||
{
|
||||
@ -45,10 +48,37 @@ namespace ui_scripting
|
||||
{
|
||||
return hksi_lual_error_hook.invoke<void>(s, formatted.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
throw std::runtime_error(formatted);
|
||||
}
|
||||
|
||||
void hksi_hks_error_stub(game::hks::lua_State* s, int a2)
|
||||
{
|
||||
if (!error_hook_enabled)
|
||||
{
|
||||
return hksi_hks_error_hook.invoke<void>(s, a2);
|
||||
}
|
||||
|
||||
throw std::runtime_error("unknown error");
|
||||
}
|
||||
|
||||
void lui_error_stub(game::hks::lua_State* s)
|
||||
{
|
||||
if (!error_hook_enabled)
|
||||
{
|
||||
return lui_error_hook.invoke<void>(s);
|
||||
}
|
||||
|
||||
const auto count = static_cast<int>(s->m_apistack.top - s->m_apistack.base);
|
||||
const auto arguments = get_return_values(count);
|
||||
|
||||
std::string error_str = "LUI Error";
|
||||
if (count && arguments[0].is<std::string>())
|
||||
{
|
||||
error_str = arguments[0].as<std::string>();
|
||||
}
|
||||
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
|
||||
void* hks_start_stub(char a1)
|
||||
@ -66,6 +96,26 @@ namespace ui_scripting
|
||||
ui_scripting::lua::engine::stop();
|
||||
hks_shutdown_hook.invoke<void*>();
|
||||
}
|
||||
|
||||
void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize)
|
||||
{
|
||||
const auto closure = reinterpret_cast<game::hks::cclosure*>(oldMemory);
|
||||
if (converted_functions.find(closure) != converted_functions.end())
|
||||
{
|
||||
converted_functions.erase(closure);
|
||||
}
|
||||
|
||||
return hks_allocator_hook.invoke<void*>(userData, oldMemory, oldSize, newSize);
|
||||
}
|
||||
|
||||
void hks_frame_stub()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
if (state)
|
||||
{
|
||||
ui_scripting::lua::engine::run_frame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main_function_handler(game::hks::lua_State* state)
|
||||
@ -117,17 +167,12 @@ namespace ui_scripting
|
||||
|
||||
void enable_error_hook()
|
||||
{
|
||||
error_hook_enabled = true;
|
||||
error_hook_enabled++;
|
||||
}
|
||||
|
||||
void disable_error_hook()
|
||||
{
|
||||
error_hook_enabled = false;
|
||||
}
|
||||
|
||||
void notify(const event& e)
|
||||
{
|
||||
lua::engine::notify(e);
|
||||
error_hook_enabled--;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -136,12 +181,14 @@ namespace ui_scripting
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(ui_scripting::lua::engine::run_frame, scheduler::pipeline::lui);
|
||||
|
||||
hks_start_hook.create(0x328BE0_b, hks_start_stub);
|
||||
hks_shutdown_hook.create(0x3203B0_b, hks_shutdown_stub);
|
||||
hksi_lual_error_hook.create(0x2E3E40_b, hksi_lual_error_stub);
|
||||
hksi_lual_error_hook2.create(0x2DCB40_b, hksi_lual_error_stub);
|
||||
hks_frame_hook.create(0x140327880, hks_frame_stub);
|
||||
hks_start_hook.create(0x140328BE0, hks_start_stub);
|
||||
hks_shutdown_hook.create(0x1403203B0, hks_shutdown_stub);
|
||||
hksi_lual_error_hook.create(0x1402E3E40, hksi_lual_error_stub);
|
||||
hksi_lual_error_hook2.create(0x1402DCB40, hksi_lual_error_stub);
|
||||
hks_allocator_hook.create(0x1402D92A0, hks_allocator_stub);
|
||||
lui_error_hook.create(0x1402B9D90, lui_error_stub);
|
||||
hksi_hks_error_hook.create(0x1402DBC00, hksi_hks_error_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -10,6 +10,4 @@ namespace ui_scripting
|
||||
|
||||
void enable_error_hook();
|
||||
void disable_error_hook();
|
||||
|
||||
void notify(const event& e);
|
||||
}
|
||||
|
408
src/client/component/updater.cpp
Normal file
408
src/client/component/updater.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "updater.hpp"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/http.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#define MASTER "https://master.fed0001.xyz/"
|
||||
|
||||
#define FILES_PATH "files.json"
|
||||
#define FILES_PATH_DEV "files-dev.json"
|
||||
|
||||
#define DATA_PATH "data/"
|
||||
#define DATA_PATH_DEV "data-dev/"
|
||||
|
||||
#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates"
|
||||
#define ERR_DOWNLOAD_FAIL "Failed to download file "
|
||||
#define ERR_WRITE_FAIL "Failed to write file "
|
||||
|
||||
namespace updater
|
||||
{
|
||||
namespace
|
||||
{
|
||||
game::dvar_t* cl_auto_update;
|
||||
bool has_tried_update = false;
|
||||
|
||||
struct status
|
||||
{
|
||||
bool done;
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct file_data
|
||||
{
|
||||
std::string name;
|
||||
std::string data;
|
||||
};
|
||||
|
||||
struct update_data_t
|
||||
{
|
||||
bool restart_required{};
|
||||
bool cancelled{};
|
||||
status check{};
|
||||
status download{};
|
||||
std::string error{};
|
||||
std::string current_file{};
|
||||
std::vector<std::string> required_files{};
|
||||
};
|
||||
|
||||
utils::concurrency::container<update_data_t> update_data;
|
||||
|
||||
std::string select(const std::string& main, const std::string& develop)
|
||||
{
|
||||
if (GIT_BRANCH == "develop"s)
|
||||
{
|
||||
return develop;
|
||||
}
|
||||
|
||||
return main;
|
||||
}
|
||||
|
||||
void set_update_check_status(bool done, bool success, const std::string& error = {})
|
||||
{
|
||||
update_data.access([done, success, error](update_data_t& data_)
|
||||
{
|
||||
data_.check.done = done;
|
||||
data_.check.success = success;
|
||||
data_.error = error;
|
||||
});
|
||||
}
|
||||
|
||||
void set_update_download_status(bool done, bool success, const std::string& error = {})
|
||||
{
|
||||
update_data.access([done, success, error](update_data_t& data_)
|
||||
{
|
||||
data_.download.done = done;
|
||||
data_.download.success = success;
|
||||
data_.error = error;
|
||||
});
|
||||
}
|
||||
|
||||
bool check_file(const std::string& name, const std::string& sha)
|
||||
{
|
||||
std::string data;
|
||||
if (!utils::io::read_file(name, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (utils::cryptography::sha1::compute(data, true) != sha)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string load_binary_name()
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
}
|
||||
|
||||
std::string get_binary_name()
|
||||
{
|
||||
static const auto name = load_binary_name();
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_time_str()
|
||||
{
|
||||
return utils::string::va("%i", uint32_t(time(nullptr)));
|
||||
}
|
||||
|
||||
std::optional<std::string> download_file(const std::string& name)
|
||||
{
|
||||
return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str());
|
||||
}
|
||||
|
||||
bool is_update_cancelled()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.cancelled;
|
||||
});
|
||||
}
|
||||
|
||||
bool write_file(const std::string& name, const std::string& data)
|
||||
{
|
||||
if (get_binary_name() == name &&
|
||||
utils::io::file_exists(name) &&
|
||||
!utils::io::move_file(name, name + ".old"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return utils::io::write_file(name, data);
|
||||
}
|
||||
|
||||
void delete_old_file()
|
||||
{
|
||||
utils::io::remove_file(get_binary_name() + ".old");
|
||||
}
|
||||
|
||||
void reset_data()
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_ = {};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void relaunch()
|
||||
{
|
||||
utils::nt::relaunch_self("-singleplayer");
|
||||
utils::nt::terminate();
|
||||
}
|
||||
|
||||
void set_has_tried_update(bool tried)
|
||||
{
|
||||
has_tried_update = tried;
|
||||
}
|
||||
|
||||
bool get_has_tried_update()
|
||||
{
|
||||
return has_tried_update;
|
||||
}
|
||||
|
||||
bool auto_updates_enabled()
|
||||
{
|
||||
return cl_auto_update->current.enabled;
|
||||
}
|
||||
|
||||
bool is_update_check_done()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.check.done;
|
||||
});
|
||||
}
|
||||
|
||||
bool is_update_download_done()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.download.done;
|
||||
});
|
||||
}
|
||||
|
||||
bool get_update_check_status()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.check.success;
|
||||
});
|
||||
}
|
||||
|
||||
bool get_update_download_status()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.download.success;
|
||||
});
|
||||
}
|
||||
|
||||
bool is_update_available()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.required_files.size() > 0;
|
||||
});
|
||||
}
|
||||
|
||||
bool is_restart_required()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.restart_required;
|
||||
});
|
||||
}
|
||||
|
||||
std::string get_last_error()
|
||||
{
|
||||
return update_data.access<std::string>([](update_data_t& data_)
|
||||
{
|
||||
return data_.error;
|
||||
});
|
||||
}
|
||||
|
||||
std::string get_current_file()
|
||||
{
|
||||
return update_data.access<std::string>([](update_data_t& data_)
|
||||
{
|
||||
return data_.current_file;
|
||||
});
|
||||
}
|
||||
|
||||
void cancel_update()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] Cancelling update\n");
|
||||
#endif
|
||||
|
||||
return update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_.cancelled = true;
|
||||
});
|
||||
}
|
||||
|
||||
void start_update_check()
|
||||
{
|
||||
cancel_update();
|
||||
reset_data();
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] starting update check\n");
|
||||
#endif
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
const auto files_data = utils::http::get_data(MASTER + select(FILES_PATH, FILES_PATH_DEV) + "?" + get_time_str());
|
||||
|
||||
if (is_update_cancelled())
|
||||
{
|
||||
reset_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!files_data.has_value())
|
||||
{
|
||||
set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
rapidjson::Document j;
|
||||
j.Parse(files_data.value().data());
|
||||
|
||||
if (!j.IsArray())
|
||||
{
|
||||
set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> required_files;
|
||||
|
||||
const auto files = j.GetArray();
|
||||
for (const auto& file : files)
|
||||
{
|
||||
if (!file.IsArray() || file.Size() != 3 || !file[0].IsString() || !file[2].IsString())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto name = file[0].GetString();
|
||||
const auto sha = file[2].GetString();
|
||||
|
||||
if (!check_file(name, sha))
|
||||
{
|
||||
if (get_binary_name() == name)
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_.restart_required = true;
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] need file %s\n", name);
|
||||
#endif
|
||||
|
||||
required_files.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
update_data.access([&required_files](update_data_t& data_)
|
||||
{
|
||||
data_.check.done = true;
|
||||
data_.check.success = true;
|
||||
data_.required_files = required_files;
|
||||
});
|
||||
}, scheduler::pipeline::async);
|
||||
}
|
||||
|
||||
void start_update_download()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] starting update download\n");
|
||||
#endif
|
||||
|
||||
if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
const auto required_files = update_data.access<std::vector<std::string>>([](update_data_t& data_)
|
||||
{
|
||||
return data_.required_files;
|
||||
});
|
||||
|
||||
std::vector<file_data> downloads;
|
||||
|
||||
for (const auto& file : required_files)
|
||||
{
|
||||
update_data.access([file](update_data_t& data_)
|
||||
{
|
||||
data_.current_file = file;
|
||||
});
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] downloading file %s\n", file.data());
|
||||
#endif
|
||||
|
||||
const auto data = download_file(file);
|
||||
|
||||
if (is_update_cancelled())
|
||||
{
|
||||
reset_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.has_value())
|
||||
{
|
||||
set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file);
|
||||
return;
|
||||
}
|
||||
|
||||
downloads.push_back({file, data.value()});
|
||||
}
|
||||
|
||||
for (const auto& download : downloads)
|
||||
{
|
||||
if (!write_file(download.name, download.data))
|
||||
{
|
||||
set_update_download_status(true, false, ERR_WRITE_FAIL + download.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
set_update_download_status(true, true);
|
||||
}, scheduler::pipeline::async);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
delete_old_file();
|
||||
cl_auto_update = dvars::register_bool("cg_auto_update", true, game::DVAR_FLAG_SAVED);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(updater::component)
|
26
src/client/component/updater.hpp
Normal file
26
src/client/component/updater.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
namespace updater
|
||||
{
|
||||
void relaunch();
|
||||
|
||||
void set_has_tried_update(bool tried);
|
||||
bool get_has_tried_update();
|
||||
bool auto_updates_enabled();
|
||||
|
||||
bool is_update_available();
|
||||
bool is_update_check_done();
|
||||
bool get_update_check_status();
|
||||
|
||||
bool is_update_download_done();
|
||||
bool get_update_download_status();
|
||||
|
||||
bool is_restart_required();
|
||||
|
||||
std::string get_last_error();
|
||||
std::string get_current_file();
|
||||
|
||||
void start_update_check();
|
||||
void start_update_download();
|
||||
void cancel_update();
|
||||
}
|
@ -3,16 +3,6 @@
|
||||
|
||||
namespace game
|
||||
{
|
||||
uint64_t base_address;
|
||||
|
||||
void load_base_address()
|
||||
{
|
||||
const auto module = GetModuleHandle(NULL);
|
||||
base_address = uint64_t(module);
|
||||
}
|
||||
|
||||
std::string mod_folder{};
|
||||
|
||||
namespace environment
|
||||
{
|
||||
launcher::mode mode = launcher::mode::none;
|
||||
@ -81,8 +71,3 @@ namespace game
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t operator"" _b(const uintptr_t ptr)
|
||||
{
|
||||
return game::base_address + ptr;
|
||||
}
|
@ -5,11 +5,6 @@
|
||||
|
||||
namespace game
|
||||
{
|
||||
extern uint64_t base_address;
|
||||
void load_base_address();
|
||||
|
||||
extern std::string mod_folder;
|
||||
|
||||
namespace environment
|
||||
{
|
||||
launcher::mode get_mode();
|
||||
@ -35,7 +30,7 @@ namespace game
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return reinterpret_cast<T*>((uint64_t)address_ + base_address);
|
||||
return reinterpret_cast<T*>(address_);
|
||||
}
|
||||
|
||||
operator T* () const
|
||||
@ -53,6 +48,4 @@ namespace game
|
||||
};
|
||||
}
|
||||
|
||||
uintptr_t operator"" _b(const uintptr_t ptr);
|
||||
|
||||
#include "symbols.hpp"
|
@ -59,15 +59,15 @@ namespace scripting
|
||||
|
||||
script_function get_function_by_index(const unsigned index)
|
||||
{
|
||||
static const auto function_table = 0xB153F90;
|
||||
static const auto method_table = 0xB155890;
|
||||
static const auto function_table = 0x14B153F90;
|
||||
static const auto method_table = 0x14B155890;
|
||||
|
||||
if (index < 0x320)
|
||||
{
|
||||
return reinterpret_cast<script_function*>(game::base_address + function_table)[index - 1];
|
||||
return reinterpret_cast<script_function*>(function_table)[index - 1];
|
||||
}
|
||||
|
||||
return reinterpret_cast<script_function*>(game::base_address + method_table)[index - 0x8000];
|
||||
return reinterpret_cast<script_function*>(method_table)[index - 0x8000];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "../../../component/notifies.hpp"
|
||||
#include "../../../component/scripting.hpp"
|
||||
#include "../../../component/command.hpp"
|
||||
#include "../../../component/chat.hpp"
|
||||
#include "../../../component/fastfiles.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
@ -48,16 +47,6 @@ namespace scripting::lua
|
||||
state["level"] = entity{*::game::levelEntityId};
|
||||
state["player"] = call("getentbynum", {0}).as<entity>();
|
||||
|
||||
state["io"]["fileexists"] = utils::io::file_exists;
|
||||
state["io"]["writefile"] = utils::io::write_file;
|
||||
state["io"]["filesize"] = utils::io::file_size;
|
||||
state["io"]["createdirectory"] = utils::io::create_directory;
|
||||
state["io"]["directoryexists"] = utils::io::directory_exists;
|
||||
state["io"]["directoryisempty"] = utils::io::directory_is_empty;
|
||||
state["io"]["listfiles"] = utils::io::list_files;
|
||||
state["io"]["copyfolder"] = utils::io::copy_folder;
|
||||
state["io"]["readfile"] = static_cast<std::string(*)(const std::string&)>(utils::io::read_file);
|
||||
|
||||
auto vector_type = state.new_usertype<vector>("vector", sol::constructors<vector(float, float, float)>());
|
||||
vector_type["x"] = sol::property(&vector::get_x, &vector::set_x);
|
||||
vector_type["y"] = sol::property(&vector::get_y, &vector::set_y);
|
||||
@ -198,8 +187,8 @@ namespace scripting::lua
|
||||
|
||||
void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler)
|
||||
{
|
||||
state["level"] = entity{ *::game::levelEntityId };
|
||||
state["player"] = call("getentbynum", { 0 }).as<entity>();
|
||||
state["level"] = entity{*::game::levelEntityId};
|
||||
state["player"] = call("getentbynum", {0}).as<entity>();
|
||||
|
||||
auto entity_type = state.new_usertype<entity>("entity");
|
||||
|
||||
@ -387,9 +376,8 @@ namespace scripting::lua
|
||||
command::execute(utils::string::va("setdiscordstate %s", state.data()), false);
|
||||
};
|
||||
|
||||
game_type["say"] = [](const game&, const std::string& msg)
|
||||
game_type["say"] = [](const game&)
|
||||
{
|
||||
chat::print(msg);
|
||||
};
|
||||
|
||||
game_type["detour"] = [](const game&, const sol::this_state s, const std::string& filename,
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "context.hpp"
|
||||
|
||||
#include "../../../component/notifies.hpp"
|
||||
#include "../../../component/filesystem.hpp"
|
||||
#include "../execution.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
@ -49,13 +50,9 @@ namespace scripting::lua::engine
|
||||
|
||||
load_generic_script();
|
||||
|
||||
load_scripts("scripts/");
|
||||
load_scripts("h2-mod/scripts/");
|
||||
load_scripts("data/scripts/");
|
||||
|
||||
if (!game::mod_folder.empty())
|
||||
for (const auto& path : filesystem::get_search_paths())
|
||||
{
|
||||
load_scripts(utils::string::va("%s/scripts/", game::mod_folder.data()));
|
||||
load_scripts(path + "/scripts/");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,14 +35,18 @@ namespace scripting::lua
|
||||
|
||||
for (auto i = tasks.begin(); i != tasks.end();)
|
||||
{
|
||||
if (i->is_deleted)
|
||||
{
|
||||
i = tasks.erase(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i->event != event.name || i->entity != event.entity)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!i->is_deleted)
|
||||
{
|
||||
if (!has_built_arguments)
|
||||
{
|
||||
has_built_arguments = true;
|
||||
@ -50,7 +54,6 @@ namespace scripting::lua
|
||||
}
|
||||
|
||||
handle_error(i->callback(sol::as_args(arguments)));
|
||||
}
|
||||
|
||||
if (i->is_volatile || i->is_deleted)
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ namespace scripting::lua
|
||||
sol::state& state_;
|
||||
std::atomic_int64_t current_listener_id_ = 0;
|
||||
|
||||
using task_list = std::vector<event_listener>;
|
||||
using task_list = std::list<event_listener>;
|
||||
utils::concurrency::container<task_list> new_callbacks_;
|
||||
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
|
||||
|
||||
|
@ -126,11 +126,90 @@ namespace game
|
||||
// ...
|
||||
};
|
||||
|
||||
struct GfxImage;
|
||||
|
||||
union MaterialTextureDefInfo
|
||||
{
|
||||
GfxImage* image;
|
||||
void* water;
|
||||
};
|
||||
|
||||
struct MaterialTextureDef
|
||||
{
|
||||
unsigned int nameHash;
|
||||
char nameStart;
|
||||
char nameEnd;
|
||||
char samplerState;
|
||||
char semantic;
|
||||
MaterialTextureDefInfo u;
|
||||
};
|
||||
|
||||
struct MaterialPass
|
||||
{
|
||||
void* vertexShader;
|
||||
void* vertexDecl;
|
||||
void* hullShader;
|
||||
void* domainShader;
|
||||
void* pixelShader;
|
||||
char pixelOutputMask;
|
||||
char perPrimArgCount;
|
||||
char perObjArgCount;
|
||||
char stableArgCount;
|
||||
unsigned __int16 perPrimArgSize;
|
||||
unsigned __int16 perObjArgSize;
|
||||
unsigned __int16 stableArgSize;
|
||||
char zone;
|
||||
char perPrimConstantBuffer;
|
||||
char perObjConstantBuffer;
|
||||
char stableConstantBuffer;
|
||||
unsigned int customBufferFlags;
|
||||
char customSamplerFlags;
|
||||
char precompiledIndex;
|
||||
char stageConfig;
|
||||
void* args;
|
||||
};
|
||||
|
||||
struct MaterialTechnique
|
||||
{
|
||||
const char* name;
|
||||
unsigned __int16 flags;
|
||||
unsigned __int16 passCount;
|
||||
MaterialPass passArray[1];
|
||||
};
|
||||
|
||||
struct MaterialTechniqueSet
|
||||
{
|
||||
const char* name;
|
||||
unsigned __int16 flags;
|
||||
char worldVertFormat;
|
||||
char preDisplacementOnlyCount;
|
||||
MaterialTechnique* techniques[309];
|
||||
};
|
||||
|
||||
struct GfxStateBits
|
||||
{
|
||||
unsigned int loadBits[3];
|
||||
char zone;
|
||||
char depthStencilState[11];
|
||||
char blendState;
|
||||
char rasterizerState;
|
||||
};
|
||||
|
||||
struct Material
|
||||
{
|
||||
const char* name;
|
||||
char __pad0[0x124];
|
||||
char textureCount;
|
||||
char __pad1[0xB];
|
||||
MaterialTechniqueSet* techniqueSet;
|
||||
MaterialTextureDef* textureTable;
|
||||
void* constantTable;
|
||||
GfxStateBits* stateBitsTable;
|
||||
char __pad2[0x118];
|
||||
};
|
||||
|
||||
static_assert(sizeof(Material) == 0x270);
|
||||
|
||||
struct point
|
||||
{
|
||||
float x;
|
||||
@ -678,6 +757,14 @@ namespace game
|
||||
const char* buffer;
|
||||
};
|
||||
|
||||
struct TTF
|
||||
{
|
||||
const char* name;
|
||||
int len;
|
||||
const char* buffer;
|
||||
int fontFace;
|
||||
};
|
||||
|
||||
union XAssetHeader
|
||||
{
|
||||
void* data;
|
||||
@ -687,6 +774,7 @@ namespace game
|
||||
ScriptFile* scriptfile;
|
||||
StringTable* stringTable;
|
||||
LuaFile* luaFile;
|
||||
TTF* ttf;
|
||||
};
|
||||
|
||||
struct XAsset
|
||||
|
@ -6,198 +6,210 @@ namespace game
|
||||
{
|
||||
// Functions
|
||||
|
||||
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x5C0EB0};
|
||||
WEAK symbol<void(unsigned int id)> AddRefToObject{0x5C0EA0};
|
||||
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0x5C1200};
|
||||
WEAK symbol<ObjectVariableValue*(unsigned int* id)> AllocVariable{0x5C1260};
|
||||
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x5C29B0};
|
||||
WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x5C28A0};
|
||||
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x1405C0EB0};
|
||||
WEAK symbol<void(unsigned int id)> AddRefToObject{0x1405C0EA0};
|
||||
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0x1405C1200};
|
||||
WEAK symbol<ObjectVariableValue*(unsigned int* id)> AllocVariable{0x1405C1260};
|
||||
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x1405C29B0};
|
||||
WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x1405C28A0};
|
||||
|
||||
WEAK symbol<void(unsigned int weapon, bool isAlternate,
|
||||
char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x6A0800};
|
||||
char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x1406A0800};
|
||||
|
||||
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x59A050};
|
||||
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x14059A050};
|
||||
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x37F450};
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessageBold{0x37F1B0};
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x14037F450};
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessageBold{0x14037F1B0};
|
||||
WEAK symbol<char*(const unsigned int weapon,
|
||||
bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x3B9210};
|
||||
bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x1403B9210};
|
||||
|
||||
WEAK symbol<void(const char* cmdName, void(), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x59A5F0};
|
||||
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x59ABA0};
|
||||
WEAK symbol<void(const char* cmdName, void(), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x14059A5F0};
|
||||
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x14059ABA0};
|
||||
|
||||
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{0x5A2D80};
|
||||
WEAK symbol<void()> Com_Quit_f{0x5A50D0};
|
||||
WEAK symbol<void()> Quit{0x5A52A0};
|
||||
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{0x1405A2D80};
|
||||
WEAK symbol<void(char const* finalMessage)> Com_Shutdown{0x1405A62C0};
|
||||
WEAK symbol<void()> Com_Quit_f{0x1405A50D0};
|
||||
WEAK symbol<bool()> Com_InFrontend{0x140328BD0};
|
||||
WEAK symbol<void()> Quit{0x1405A52A0};
|
||||
|
||||
WEAK symbol<void(XAssetType type, void(__cdecl* func)(game::XAssetHeader, void*), const void* inData, bool includeOverride)>
|
||||
DB_EnumXAssets_Internal{0x4129F0};
|
||||
WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x3E4090};
|
||||
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{0x414FF0};
|
||||
WEAK symbol<XAssetHeader(XAssetType type, const char* name, int allowCreateDefault)> DB_FindXAssetHeader{0x412F60};
|
||||
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x413D80};
|
||||
WEAK symbol<int(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x413C40};
|
||||
DB_EnumXAssets_Internal{0x1404129F0};
|
||||
WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x1403E4090};
|
||||
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{0x140414FF0};
|
||||
WEAK symbol<XAssetHeader(XAssetType type, const char* name, int allowCreateDefault)> DB_FindXAssetHeader{0x140412F60};
|
||||
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x140413D80};
|
||||
WEAK symbol<int(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x140413C40};
|
||||
|
||||
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x618F90};
|
||||
WEAK symbol<void(char* buffer, int index)> Dvar_GetCombinedString{0x5A75D0};
|
||||
WEAK symbol<dvar_t*(int hash, const char* name, bool value, unsigned int flags)> Dvar_RegisterBool{0x617BB0};
|
||||
WEAK symbol<dvar_t*(int hash, const char* name, int value, int min, int max, unsigned int flags)> Dvar_RegisterInt{0x618090};
|
||||
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140618F90};
|
||||
WEAK symbol<void(char* buffer, int index)> Dvar_GetCombinedString{0x1405A75D0};
|
||||
WEAK symbol<dvar_t*(int hash, const char* name, bool value, unsigned int flags)> Dvar_RegisterBool{0x140617BB0};
|
||||
WEAK symbol<dvar_t*(int hash, const char* name, int value, int min, int max, unsigned int flags)> Dvar_RegisterInt{0x140618090};
|
||||
WEAK symbol<dvar_t*(int hash, const char* dvarName, float value, float min, float max, unsigned int flags)>
|
||||
Dvar_RegisterFloat{0x617F80};
|
||||
Dvar_RegisterFloat{0x140617F80};
|
||||
WEAK symbol<dvar_t*(int hash, const char* dvarName, const char* value, unsigned int flags)>
|
||||
Dvar_RegisterString{0x618170};
|
||||
Dvar_RegisterString{0x140618170};
|
||||
WEAK symbol<dvar_t*(int dvarName, const char* a2, float x, float y, float z, float w, float min, float max,
|
||||
unsigned int flags)> Dvar_RegisterVec4{0x6185F0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x618EA0};
|
||||
WEAK symbol<const char*(dvar_t* dvar, void* a2, void* value)> Dvar_ValueToString{0x61B8F0};
|
||||
WEAK symbol<void(int hash, const char* name, const char* buffer)> Dvar_SetCommand{0x61A5C0};
|
||||
WEAK symbol<void(const char* dvarName, const char* string, DvarSetSource source)> Dvar_SetFromStringFromSource{0x61A910};
|
||||
unsigned int flags)> Dvar_RegisterVec4{0x1406185F0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x140618EA0};
|
||||
WEAK symbol<const char*(dvar_t* dvar, void* a2, void* value)> Dvar_ValueToString{0x14061B8F0};
|
||||
WEAK symbol<void(int hash, const char* name, const char* buffer)> Dvar_SetCommand{0x14061A5C0};
|
||||
WEAK symbol<void(const char* dvarName, const char* string, DvarSetSource source)> Dvar_SetFromStringFromSource{0x14061A910};
|
||||
|
||||
WEAK symbol<int(const char* fname)> generateHashValue{0x343D20};
|
||||
WEAK symbol<int(const char* fname)> generateHashValue{0x140343D20};
|
||||
|
||||
WEAK symbol<bool()> CL_IsCgameInitialized{0x3CA0C0};
|
||||
WEAK symbol<bool()> CL_IsCgameInitialized{0x1403CA0C0};
|
||||
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y, float xScale, float yScale,
|
||||
const float* color, int style, const float* glowColor, Material* fxMaterial, Material* fxMaterialGlow,
|
||||
int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, int a17)> CL_DrawTextPhysicalWithEffects{0x3D4990};
|
||||
int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, int a17)> CL_DrawTextPhysicalWithEffects{0x1403D4990};
|
||||
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x5C1D50};
|
||||
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0x5C1C50};
|
||||
WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x5C6100};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetVariable{0x5C2690};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewVariable{0x5C22B0};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewArrayVariable{0x5C2130};
|
||||
WEAK symbol<void(unsigned int parentId, unsigned int id, VariableValue* value)> SetNewVariableValue{0x5C5EA0};
|
||||
WEAK symbol<void(unsigned int parentId, unsigned int index)> RemoveVariableValue{0x5C2A50};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x1405C1D50};
|
||||
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0x1405C1C50};
|
||||
WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x1405C6100};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetVariable{0x1405C2690};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewVariable{0x1405C22B0};
|
||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewArrayVariable{0x1405C2130};
|
||||
WEAK symbol<void(unsigned int parentId, unsigned int id, VariableValue* value)> SetNewVariableValue{0x1405C5EA0};
|
||||
WEAK symbol<void(unsigned int parentId, unsigned int index)> RemoveVariableValue{0x1405C2A50};
|
||||
|
||||
WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x51B260};
|
||||
WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x14051B260};
|
||||
WEAK symbol<int(void* ps, unsigned int weapon, int a3, int a4, __int64 a5, int a6)>
|
||||
G_GivePlayerWeapon{0x51B660};
|
||||
WEAK symbol<void(void* ps, const unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x4C4110};
|
||||
WEAK symbol<void(int clientNum, const unsigned int weapon)> G_SelectWeapon{0x51C0D0};
|
||||
WEAK symbol<bool(int localClientNum, ScreenPlacement* screenPlacement, const float* worldDir, float* outScreenPos)> WorldPosToScreenPos{0x36F310};
|
||||
G_GivePlayerWeapon{0x14051B660};
|
||||
WEAK symbol<void(void* ps, const unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x1404C4110};
|
||||
WEAK symbol<void(int clientNum, const unsigned int weapon)> G_SelectWeapon{0x14051C0D0};
|
||||
WEAK symbol<bool(int localClientNum, ScreenPlacement* screenPlacement, const float* worldDir, float* outScreenPos)> WorldPosToScreenPos{0x14036F310};
|
||||
|
||||
WEAK symbol<char*(char* string)> I_CleanStr{0x620660};
|
||||
WEAK symbol<char*(char* string)> I_CleanStr{0x140620660};
|
||||
|
||||
WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, int a8, const char* name, const void* initData)> Image_Setup{0x74B2A0};
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, int a8, const char* name, const void* initData)> Image_Setup{0x14074B2A0};
|
||||
|
||||
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x3D32D0};
|
||||
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x1403D32D0};
|
||||
|
||||
WEAK symbol<void(int clientNum, const char* menu, int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x5F0EE0};
|
||||
WEAK symbol<bool(int clientNum, const char* menu)> Menu_IsMenuOpenAndVisible{0x5EE1A0};
|
||||
WEAK symbol<void(int clientNum, const char* menu, int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x1405F0EE0};
|
||||
WEAK symbol<bool(int clientNum, const char* name, hks::lua_State* s)> LUI_BeginEvent{0x1403155E0};
|
||||
WEAK symbol<void(hks::lua_State* s)> LUI_EndEvent{0x140316890};
|
||||
WEAK symbol<void()> LUI_EnterCriticalSection{0x140316980};
|
||||
WEAK symbol<void()> LUI_LeaveCriticalSection{0x14031BC20};
|
||||
WEAK symbol<bool(int clientNum, const char* menu)> Menu_IsMenuOpenAndVisible{0x1405EE1A0};
|
||||
|
||||
WEAK symbol<Material*(const char* material)> Material_RegisterHandle{0x759BA0};
|
||||
WEAK symbol<Material*(const char* material)> Material_RegisterHandle{0x140759BA0};
|
||||
|
||||
WEAK symbol<void(pathnode_t*, float* out)> PathNode_WorldifyPosFromParent{0x525830};
|
||||
WEAK symbol<void(pathnode_t*, float* out)> PathNode_WorldifyPosFromParent{0x140525830};
|
||||
|
||||
WEAK symbol<const float*(const float* v)> Scr_AllocVector{0x5C3220};
|
||||
WEAK symbol<void()> Scr_ClearOutParams{0x5C6E50};
|
||||
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x5C56C0};
|
||||
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> Scr_GetEntityId{0x5C5610};
|
||||
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x512190};
|
||||
WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x5C8240};
|
||||
WEAK symbol<unsigned int(unsigned int threadId)> Scr_GetSelf{0x5C57C0};
|
||||
WEAK symbol<void()> Scr_ErrorInternal{0x5C6EC0};
|
||||
WEAK symbol<const float*(const float* v)> Scr_AllocVector{0x1405C3220};
|
||||
WEAK symbol<void()> Scr_ClearOutParams{0x1405C6E50};
|
||||
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x1405C56C0};
|
||||
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> Scr_GetEntityId{0x1405C5610};
|
||||
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x140512190};
|
||||
WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x1405C8240};
|
||||
WEAK symbol<unsigned int(unsigned int threadId)> Scr_GetSelf{0x1405C57C0};
|
||||
WEAK symbol<void()> Scr_ErrorInternal{0x1405C6EC0};
|
||||
|
||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x5C8DB0};
|
||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x1405C8DB0};
|
||||
|
||||
WEAK symbol<void(float x, float y, float width, float height, float s0, float t0, float s1, float t1,
|
||||
float* color, Material* material)> R_AddCmdDrawStretchPic{0x3C9710};
|
||||
float* color, Material* material)> R_AddCmdDrawStretchPic{0x1403C9710};
|
||||
WEAK symbol<void(float x, float y, float width, float height, float s0, float t0, float s1, float t1,
|
||||
float angle, float* color, Material* material)> R_AddCmdDrawStretchPicRotateXY{0x3C99B0};
|
||||
float angle, float* color, Material* material)> R_AddCmdDrawStretchPicRotateXY{0x1403C99B0};
|
||||
WEAK symbol<void*(const char* text, int maxChars, Font_s* font, float x, float y, float xScale, float yScale,
|
||||
float rotation, float* color, int style)> R_AddCmdDrawText{0x76C660};
|
||||
float rotation, float* color, int style)> R_AddCmdDrawText{0x14076C660};
|
||||
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y, float xScale, float yScale,
|
||||
float rotation, float* color1, float* color2, int style)> R_AddCmdDrawText2{0x76C860};
|
||||
WEAK symbol<void(rectangle* rect, float a2, float a3, float a4, float a5, float* color, Material* material)> R_DrawRectangle{0x76A280};
|
||||
float rotation, float* color1, float* color2, int style)> R_AddCmdDrawText2{0x14076C860};
|
||||
WEAK symbol<void(rectangle* rect, float a2, float a3, float a4, float a5, float* color, Material* material)> R_DrawRectangle{0x14076A280};
|
||||
WEAK symbol<void(const char* text, int maxChars, Font_s* font, int fontSize, float x, float y, float xScale, float yScale, float rotation,
|
||||
const float* color, int style, int cursorPos, char cursor)> R_AddCmdDrawTextWithCursor{0x76CAF0};
|
||||
const float* color, int style, int cursorPos, char cursor)> R_AddCmdDrawTextWithCursor{0x14076CAF0};
|
||||
WEAK symbol<void*(const char* text, int maxChars, Font_s* font, float x, float y, float xScale, float yScale,
|
||||
int a8, float* color1, unsigned int style, rgba color2)> R_AddCmdDrawTextGradient{0x76C570};
|
||||
WEAK symbol<Font_s*(const char* font, int size)> R_RegisterFont{0x746FE0};
|
||||
WEAK symbol<int(const char* text, int maxChars, Font_s* font)> R_TextWidth{0x7472A0};
|
||||
WEAK symbol<void()> R_SyncRenderThread{0x76E7D0};
|
||||
int a8, float* color1, unsigned int style, rgba color2)> R_AddCmdDrawTextGradient{0x14076C570};
|
||||
WEAK symbol<Font_s*(const char* font, int size)> R_RegisterFont{0x140746FE0};
|
||||
WEAK symbol<int(const char* text, int maxChars, Font_s* font)> R_TextWidth{0x1407472A0};
|
||||
WEAK symbol<void()> R_SyncRenderThread{0x14076E7D0};
|
||||
WEAK symbol<void()> R_WaitWorkerCmds{0x140794330};
|
||||
WEAK symbol<void(const void* obj, void* pose, unsigned int entnum, unsigned int renderFxFlags, float* lightingOrigin,
|
||||
float materialTime, __int64 a7, __int64 a8)> R_AddDObjToScene{0x775C40};
|
||||
float materialTime, __int64 a7, __int64 a8)> R_AddDObjToScene{0x140775C40};
|
||||
|
||||
WEAK symbol<ScreenPlacement*()> ScrPlace_GetViewPlacement{0x3E16A0};
|
||||
WEAK symbol<ScreenPlacement*()> ScrPlace_GetView{0x3E1660};
|
||||
WEAK symbol<ScreenPlacement*()> ScrPlace_GetViewPlacement{0x1403E16A0};
|
||||
WEAK symbol<ScreenPlacement*()> ScrPlace_GetView{0x1403E1660};
|
||||
|
||||
WEAK symbol<const char*(scr_string_t stringValue)> SL_ConvertToString{0x5BFBB0};
|
||||
WEAK symbol<scr_string_t(const char* str, unsigned int user)> SL_GetString{0x5C0170};
|
||||
WEAK symbol<const char*(scr_string_t stringValue)> SL_ConvertToString{0x1405BFBB0};
|
||||
WEAK symbol<scr_string_t(const char* str, unsigned int user)> SL_GetString{0x1405C0170};
|
||||
|
||||
WEAK symbol<bool()> SV_Loaded{0x6B3860};
|
||||
WEAK symbol<bool()> SV_Loaded{0x1406B3860};
|
||||
|
||||
WEAK symbol<void()> Sys_ShowConsole{0x633080};
|
||||
WEAK symbol<bool()> Sys_IsDatabaseReady2{0x5A9FE0};
|
||||
WEAK symbol<int()> Sys_Milliseconds{0x650720};
|
||||
WEAK symbol<bool()> Sys_IsMainThread{0x5AA020};
|
||||
WEAK symbol<void()> Sys_ShowConsole{0x140633080};
|
||||
WEAK symbol<bool()> Sys_IsDatabaseReady2{0x1405A9FE0};
|
||||
WEAK symbol<int()> Sys_Milliseconds{0x140650720};
|
||||
WEAK symbol<bool()> Sys_IsMainThread{0x1405AA020};
|
||||
WEAK symbol<void(int critSec)> Sys_EnterCriticalSection{0x140624240};
|
||||
WEAK symbol<void(int critSec)> Sys_LeaveCriticalSection{0x1406242C0};
|
||||
|
||||
WEAK symbol<const char*(const char* string)> UI_SafeTranslateString{0x5A2930};
|
||||
WEAK symbol<int(int localClientNum, const char* sound)> UI_PlayLocalSoundAlias{0x606080};
|
||||
WEAK symbol<const char*(const char* string)> UI_SafeTranslateString{0x1405A2930};
|
||||
WEAK symbol<int(int localClientNum, const char* sound)> UI_PlayLocalSoundAlias{0x140606080};
|
||||
|
||||
WEAK symbol<void(pmove_t* move, trace_t*, const float*, const float*,
|
||||
const Bounds*, int, int)> PM_playerTrace{0x68F0A0};
|
||||
const Bounds*, int, int)> PM_playerTrace{0x14068F0A0};
|
||||
WEAK symbol<void(pmove_t*, trace_t*, const float*, const float*,
|
||||
const Bounds*, int, int)> PM_trace{0x68F1D0};
|
||||
const Bounds*, int, int)> PM_trace{0x14068F1D0};
|
||||
|
||||
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x89EED0};
|
||||
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x8EC2E0};
|
||||
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14089EED0};
|
||||
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x1408EC2E0};
|
||||
|
||||
// Variables
|
||||
|
||||
WEAK symbol<cmd_function_s*> cmd_functions{0xAD17BB8};
|
||||
WEAK symbol<CmdArgs> cmd_args{0xAD17A60};
|
||||
WEAK symbol<const char*> command_whitelist{0xBF84E0};
|
||||
WEAK symbol<cmd_function_s*> cmd_functions{0x14AD17BB8};
|
||||
WEAK symbol<CmdArgs> cmd_args{0x14AD17A60};
|
||||
WEAK symbol<const char*> command_whitelist{0x140BF84E0};
|
||||
|
||||
WEAK symbol<HWND> hWnd{0xCCF81C0};
|
||||
WEAK symbol<HWND> hWnd{0x14CCF81C0};
|
||||
|
||||
WEAK symbol<const char*> g_assetNames{0xBEF280};
|
||||
WEAK symbol<int> g_poolSize{0xBF2E40};
|
||||
WEAK symbol<const char*> g_assetNames{0x140BEF280};
|
||||
WEAK symbol<int> g_poolSize{0x140BF2E40};
|
||||
|
||||
WEAK symbol<gentity_s> g_entities{0x52DDDA0};
|
||||
WEAK symbol<int> num_entities{0x55CC738};
|
||||
WEAK symbol<PathData> pathData{0x52CCDA0};
|
||||
WEAK symbol<int> vehicle_pathnode_count{0xD009A30};
|
||||
WEAK symbol<gentity_s> g_entities{0x1452DDDA0};
|
||||
WEAK symbol<int> num_entities{0x1455CC738};
|
||||
WEAK symbol<PathData> pathData{0x1452CCDA0};
|
||||
WEAK symbol<int> vehicle_pathnode_count{0x14D009A30};
|
||||
|
||||
WEAK symbol<DWORD> threadIds{0xB11DC80};
|
||||
WEAK symbol<DWORD> threadIds{0x14B11DC80};
|
||||
|
||||
WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0xEDF9E00};
|
||||
WEAK symbol<refdef_t> refdef{0x1BC2500};
|
||||
WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0x14EDF9E00};
|
||||
WEAK symbol<refdef_t> refdef{0x141BC2500};
|
||||
|
||||
WEAK symbol<int> keyCatchers{0x203F3C0};
|
||||
WEAK symbol<int> keyCatchers{0x14203F3C0};
|
||||
|
||||
WEAK symbol<PlayerKeyState> playerKeys{0x1E8767C};
|
||||
WEAK symbol<PlayerKeyState> playerKeys{0x141E8767C};
|
||||
|
||||
WEAK symbol<int> dvarCount{0xBFBB310};
|
||||
WEAK symbol<dvar_t> dvarPool{0xBFBB320};
|
||||
WEAK symbol<int> dvarCount{0x14BFBB310};
|
||||
WEAK symbol<dvar_t> dvarPool{0x14BFBB320};
|
||||
|
||||
WEAK symbol<unsigned int> levelEntityId{0xB5E0B30};
|
||||
WEAK symbol<int> g_script_error_level{0xBA9CC24};
|
||||
WEAK symbol<jmp_buf> g_script_error{0xBA9CD40};
|
||||
WEAK symbol<scr_classStruct_t> g_classMap{0xBF95C0};
|
||||
WEAK symbol<unsigned int> levelEntityId{0x14B5E0B30};
|
||||
WEAK symbol<int> g_script_error_level{0x14BA9CC24};
|
||||
WEAK symbol<jmp_buf> g_script_error{0x14BA9CD40};
|
||||
WEAK symbol<scr_classStruct_t> g_classMap{0x140BF95C0};
|
||||
|
||||
WEAK symbol<scrVarGlob_t> scr_VarGlob{0xB617C00};
|
||||
WEAK symbol<scrVmPub_t> scr_VmPub{0xBA9EE40};
|
||||
WEAK symbol<function_stack_t> scr_function_stack{0xBAA93C0};
|
||||
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x14B617C00};
|
||||
WEAK symbol<scrVmPub_t> scr_VmPub{0x14BA9EE40};
|
||||
WEAK symbol<function_stack_t> scr_function_stack{0x14BAA93C0};
|
||||
|
||||
namespace hks
|
||||
{
|
||||
WEAK symbol<lua_State*> lua_state{0x19D83E8};
|
||||
WEAK symbol<void(lua_State* s, const char* str, unsigned int l)> hksi_lua_pushlstring{0x287410};
|
||||
WEAK symbol<const char*(lua_State* s, const HksObject* obj, unsigned int* len)> hks_obj_tolstring{0x287410};
|
||||
WEAK symbol<int(lua_State* s, const HksObject* obj, HksObject* ret)> hks_obj_getmetatable{0x2DA210};
|
||||
WEAK symbol<HksObject*(HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_getfield{0x2D9E20};
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)> hks_obj_settable{0x2DB040};
|
||||
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{0x2DA300};
|
||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{0x30AB60};
|
||||
WEAK symbol<void(lua_State* s, int index)> hksi_lua_pushvalue{0x2DE040};
|
||||
WEAK symbol<HashTable*(lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{0x2C8290};
|
||||
WEAK symbol<HksObject*(HashTable* t, HksObject* result, HksObject* key)> Hashtable_getNextHash{0x2D5150};
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, HksObject* key, HksObject* retval)> hks_obj_next{0x2DA850};
|
||||
WEAK symbol<lua_State*> lua_state{0x1419D83E8};
|
||||
WEAK symbol<void(lua_State* s, const char* str, unsigned int l)> hksi_lua_pushlstring{0x140287410};
|
||||
WEAK symbol<const char*(lua_State* s, const HksObject* obj, unsigned int* len)> hks_obj_tolstring{0x140287410};
|
||||
WEAK symbol<int(lua_State* s, const HksObject* obj, HksObject* ret)> hks_obj_getmetatable{0x1402DA210};
|
||||
WEAK symbol<HksObject*(HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_getfield{0x1402D9E20};
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)> hks_obj_settable{0x1402DB040};
|
||||
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{0x1402DA300};
|
||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{0x14030AB60};
|
||||
WEAK symbol<void(lua_State* s, int index)> hksi_lua_pushvalue{0x1402DE040};
|
||||
WEAK symbol<HashTable*(lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{0x1402C8290};
|
||||
WEAK symbol<HksObject*(HashTable* t, HksObject* result, HksObject* key)> Hashtable_getNextHash{0x1402D5150};
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, HksObject* key, HksObject* retval)> hks_obj_next{0x1402DA850};
|
||||
WEAK symbol<cclosure*(lua_State* s, lua_function function, int num_upvalues,
|
||||
int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0x2C84B0};
|
||||
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{0x2E4520};
|
||||
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{0x2DCE50};
|
||||
int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0x1402C84B0};
|
||||
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{0x1402E4520};
|
||||
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{0x1402DCE50};
|
||||
WEAK symbol<void(lua_State* s, int index, const char* k)> hksi_lua_setfield{0x1402DEA30};
|
||||
WEAK symbol<int(lua_State* s, int nargs, int nresults, int errfunc)> hksi_lua_pcall{0x1402DDE50};
|
||||
WEAK symbol<void(lua_State* s, HksObject* lfp)> closePendingUpvalues{0x1402CBAD0};
|
||||
}
|
||||
}
|
@ -37,38 +37,79 @@ namespace ui_scripting
|
||||
return values;
|
||||
}
|
||||
|
||||
bool notify(const std::string& name, const event_arguments& arguments)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
if (!state)
|
||||
{
|
||||
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").as<function>().call({})[0].as<userdata>();
|
||||
const auto process_event = root.get("processEvent").as<function>();
|
||||
|
||||
table event{};
|
||||
event.set("name", name);
|
||||
|
||||
for (const auto& arg : arguments)
|
||||
{
|
||||
event.set(arg.first, arg.second);
|
||||
}
|
||||
|
||||
process_event.call({root, event});
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
printf("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;
|
||||
|
||||
stack stack;
|
||||
push_value(function);
|
||||
for (auto i = arguments.begin(); i != arguments.end(); ++i)
|
||||
{
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
const auto num_args = static_cast<int>(arguments.size());
|
||||
stack.save(num_args + 1);
|
||||
|
||||
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);
|
||||
game::hks::vm_call_internal(state, num_args, -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());
|
||||
stack.fix();
|
||||
throw std::runtime_error("Error executing script function: "s + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
stack stack;
|
||||
push_value(key);
|
||||
stack.save(1);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
@ -85,16 +126,18 @@ namespace ui_scripting
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error getting userdata field: ") + e.what());
|
||||
stack.fix();
|
||||
throw std::runtime_error("Error getting userdata field: "s + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
stack stack;
|
||||
push_value(key);
|
||||
stack.save(1);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
@ -111,14 +154,17 @@ namespace ui_scripting
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error getting table field: ") + e.what());
|
||||
stack.fix();
|
||||
throw std::runtime_error("Error getting table field: "s + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
stack stack;
|
||||
stack.save(0);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
@ -133,14 +179,17 @@ namespace ui_scripting
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error setting userdata field: ") + e.what());
|
||||
stack.fix();
|
||||
throw std::runtime_error("Error setting userdata field: "s + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
stack stack;
|
||||
stack.save(0);
|
||||
|
||||
const auto _1 = gsl::finally(&disable_error_hook);
|
||||
enable_error_hook();
|
||||
@ -155,7 +204,8 @@ namespace ui_scripting
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Error setting table field: ") + e.what());
|
||||
stack.fix();
|
||||
throw std::runtime_error("Error setting table field: "s + e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ namespace ui_scripting
|
||||
script_value get_return_value(int offset);
|
||||
arguments get_return_values(int count);
|
||||
|
||||
bool notify(const std::string& name, const event_arguments& arguments);
|
||||
|
||||
arguments call_script_function(const function& function, const arguments& arguments);
|
||||
|
||||
script_value get_field(const userdata& self, const script_value& key);
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "../../../component/scripting.hpp"
|
||||
#include "../../../component/command.hpp"
|
||||
#include "../../../component/fastfiles.hpp"
|
||||
#include "../../../component/updater.hpp"
|
||||
#include "../../../component/localized_strings.hpp"
|
||||
#include "../../../component/mods.hpp"
|
||||
|
||||
#include "component/game_console.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
@ -25,7 +28,7 @@ namespace ui_scripting::lua
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const auto json_script = utils::nt::load_resource(LUA_JSON_SCRIPT);
|
||||
const auto json_script = utils::nt::load_resource(LUA_JSON);
|
||||
|
||||
scripting::script_value script_convert(const sol::lua_value& value)
|
||||
{
|
||||
@ -207,7 +210,7 @@ namespace ui_scripting::lua
|
||||
};
|
||||
}
|
||||
|
||||
void setup_game_type(sol::state& state, event_handler& handler, scheduler& scheduler)
|
||||
void setup_game_type(sol::state& state, scheduler& scheduler)
|
||||
{
|
||||
struct game
|
||||
{
|
||||
@ -243,28 +246,6 @@ namespace ui_scripting::lua
|
||||
return scheduler.add(callback, milliseconds, false);
|
||||
};
|
||||
|
||||
game_type["onnotify"] = [&handler](const game&, const std::string& event,
|
||||
const event_callback& callback)
|
||||
{
|
||||
event_listener listener{};
|
||||
listener.callback = callback;
|
||||
listener.event = event;
|
||||
listener.is_volatile = false;
|
||||
|
||||
return handler.add_event_listener(std::move(listener));
|
||||
};
|
||||
|
||||
game_type["onnotifyonce"] = [&handler](const game&, const std::string& event,
|
||||
const event_callback& callback)
|
||||
{
|
||||
event_listener listener{};
|
||||
listener.callback = callback;
|
||||
listener.event = event;
|
||||
listener.is_volatile = true;
|
||||
|
||||
return handler.add_event_listener(std::move(listener));
|
||||
};
|
||||
|
||||
game_type["isingame"] = []()
|
||||
{
|
||||
return ::game::CL_IsCgameInitialized() && ::game::g_entities[0].client;
|
||||
@ -360,7 +341,7 @@ namespace ui_scripting::lua
|
||||
game_type["playmenuvideo"] = [](const game&, const std::string& video)
|
||||
{
|
||||
reinterpret_cast<void (*)(const char* a1, int a2, int a3)>
|
||||
(0x71B970_b)(video.data(), 64, 0);
|
||||
(0x14071B970)(video.data(), 64, 0);
|
||||
};
|
||||
|
||||
game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value)
|
||||
@ -432,124 +413,13 @@ namespace ui_scripting::lua
|
||||
|
||||
game_type["getloadedmod"] = [](const game&)
|
||||
{
|
||||
return ::game::mod_folder;
|
||||
return mods::mod_path;
|
||||
};
|
||||
|
||||
static int request_id{};
|
||||
game_type["httpget"] = [](const game&, const std::string& url)
|
||||
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
||||
const std::string& value)
|
||||
{
|
||||
const auto id = request_id++;
|
||||
::scheduler::once([url, id]()
|
||||
{
|
||||
const auto result = utils::http::get_data(url);
|
||||
::scheduler::once([result, id]
|
||||
{
|
||||
event event;
|
||||
event.name = "http_request_done";
|
||||
|
||||
if (result.has_value())
|
||||
{
|
||||
event.arguments = {id, true, result.value()};
|
||||
}
|
||||
else
|
||||
{
|
||||
event.arguments = {id, false};
|
||||
}
|
||||
|
||||
notify(event);
|
||||
}, ::scheduler::pipeline::lui);
|
||||
}, ::scheduler::pipeline::async);
|
||||
return id;
|
||||
};
|
||||
|
||||
game_type["httpgettofile"] = [](const game&, const std::string& url,
|
||||
const std::string& dest)
|
||||
{
|
||||
const auto id = request_id++;
|
||||
::scheduler::once([url, id, dest]()
|
||||
{
|
||||
auto last_report = std::chrono::high_resolution_clock::now();
|
||||
const auto result = utils::http::get_data(url, {}, [&last_report, id](size_t progress, size_t total, size_t speed)
|
||||
{
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
if (now - last_report < 100ms && progress < total)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
last_report = now;
|
||||
|
||||
::scheduler::once([id, progress, total, speed]
|
||||
{
|
||||
event event;
|
||||
event.name = "http_request_progress";
|
||||
event.arguments = {
|
||||
id,
|
||||
static_cast<int>(progress),
|
||||
static_cast<int>(total),
|
||||
static_cast<int>(speed)
|
||||
};
|
||||
|
||||
notify(event);
|
||||
}, ::scheduler::pipeline::lui);
|
||||
});
|
||||
|
||||
if (result.has_value())
|
||||
{
|
||||
const auto write = utils::io::write_file(dest, result.value(), false);
|
||||
::scheduler::once([result, id, write]()
|
||||
{
|
||||
event event;
|
||||
event.name = "http_request_done";
|
||||
event.arguments = {id, true, write};
|
||||
|
||||
notify(event);
|
||||
}, ::scheduler::pipeline::lui);
|
||||
}
|
||||
else
|
||||
{
|
||||
::scheduler::once([result, id]()
|
||||
{
|
||||
event event;
|
||||
event.name = "http_request_done";
|
||||
event.arguments = {id, false};
|
||||
|
||||
notify(event);
|
||||
}, ::scheduler::pipeline::lui);
|
||||
}
|
||||
}, ::scheduler::pipeline::async);
|
||||
return id;
|
||||
};
|
||||
|
||||
game_type["sha"] = [](const game&, const std::string& data)
|
||||
{
|
||||
return utils::string::to_upper(utils::cryptography::sha1::compute(data, true));
|
||||
};
|
||||
|
||||
game_type["environment"] = [](const game&)
|
||||
{
|
||||
return GIT_BRANCH;
|
||||
};
|
||||
|
||||
game_type["binaryname"] = [](const game&)
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
};
|
||||
|
||||
game_type["relaunch"] = [](const game&)
|
||||
{
|
||||
utils::nt::relaunch_self("-singleplayer");
|
||||
utils::nt::terminate();
|
||||
};
|
||||
|
||||
game_type["isdebugbuild"] = [](const game&)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
localized_strings::override(string, value);
|
||||
};
|
||||
|
||||
struct player
|
||||
@ -586,7 +456,7 @@ namespace ui_scripting::lua
|
||||
};
|
||||
}
|
||||
|
||||
void setup_lui_types(sol::state& state, event_handler& handler, scheduler& scheduler)
|
||||
void setup_lui_types(sol::state& state)
|
||||
{
|
||||
auto userdata_type = state.new_usertype<userdata>("userdata_");
|
||||
|
||||
@ -602,15 +472,15 @@ namespace ui_scripting::lua
|
||||
);
|
||||
|
||||
userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s,
|
||||
const std::string& name)
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, userdata.get(name));
|
||||
return convert(s, userdata.get(convert({s, key})));
|
||||
};
|
||||
|
||||
userdata_type[sol::meta_function::new_index] = [](const userdata& userdata, const sol::this_state s,
|
||||
const std::string& name, const sol::lua_value& value)
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
userdata.set(name, convert({s, value}));
|
||||
userdata.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
auto table_type = state.new_usertype<table>("table_");
|
||||
@ -627,27 +497,27 @@ namespace ui_scripting::lua
|
||||
);
|
||||
|
||||
table_type["get"] = [](const table& table, const sol::this_state s,
|
||||
const std::string& name)
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, table.get(name));
|
||||
return convert(s, table.get(convert({s, key})));
|
||||
};
|
||||
|
||||
table_type["set"] = [](const table& table, const sol::this_state s,
|
||||
const std::string& name, const sol::lua_value& value)
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
table.set(name, convert({s, value}));
|
||||
table.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
table_type[sol::meta_function::index] = [](const table& table, const sol::this_state s,
|
||||
const std::string& name)
|
||||
const sol::lua_value& key)
|
||||
{
|
||||
return convert(s, table.get(name));
|
||||
return convert(s, table.get(convert({s, key})));
|
||||
};
|
||||
|
||||
table_type[sol::meta_function::new_index] = [](const table& table, const sol::this_state s,
|
||||
const std::string& name, const sol::lua_value& value)
|
||||
const sol::lua_value& key, const sol::lua_value& value)
|
||||
{
|
||||
table.set(name, convert({s, value}));
|
||||
table.set(convert({s, key}), convert({s, value}));
|
||||
};
|
||||
|
||||
auto function_type = state.new_usertype<function>("function_");
|
||||
@ -677,13 +547,35 @@ namespace ui_scripting::lua
|
||||
state["LUI"] = state["luiglobals"]["LUI"];
|
||||
state["Engine"] = state["luiglobals"]["Engine"];
|
||||
state["Game"] = state["luiglobals"]["Game"];
|
||||
|
||||
auto updater_table = sol::table::create(state.lua_state());
|
||||
|
||||
updater_table["relaunch"] = updater::relaunch;
|
||||
|
||||
updater_table["sethastriedupdate"] = updater::set_has_tried_update;
|
||||
updater_table["gethastriedupdate"] = updater::get_has_tried_update;
|
||||
updater_table["autoupdatesenabled"] = updater::auto_updates_enabled;
|
||||
|
||||
updater_table["startupdatecheck"] = updater::start_update_check;
|
||||
updater_table["isupdatecheckdone"] = updater::is_update_check_done;
|
||||
updater_table["getupdatecheckstatus"] = updater::get_update_check_status;
|
||||
updater_table["isupdateavailable"] = updater::is_update_available;
|
||||
|
||||
updater_table["startupdatedownload"] = updater::start_update_download;
|
||||
updater_table["isupdatedownloaddone"] = updater::is_update_download_done;
|
||||
updater_table["getupdatedownloadstatus"] = updater::get_update_download_status;
|
||||
updater_table["cancelupdate"] = updater::cancel_update;
|
||||
updater_table["isrestartrequired"] = updater::is_restart_required;
|
||||
|
||||
updater_table["getlasterror"] = updater::get_last_error;
|
||||
updater_table["getcurrentfile"] = updater::get_current_file;
|
||||
|
||||
state["updater"] = updater_table;
|
||||
}
|
||||
}
|
||||
|
||||
context::context(std::string data, script_type type)
|
||||
: scheduler_(state_)
|
||||
, event_handler_(state_)
|
||||
|
||||
{
|
||||
this->state_.open_libraries(sol::lib::base,
|
||||
sol::lib::package,
|
||||
@ -696,8 +588,8 @@ namespace ui_scripting::lua
|
||||
setup_io(this->state_);
|
||||
setup_json(this->state_);
|
||||
setup_vector_type(this->state_);
|
||||
setup_game_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
setup_lui_types(this->state_, this->event_handler_, this->scheduler_);
|
||||
setup_game_type(this->state_, this->scheduler_);
|
||||
setup_lui_types(this->state_);
|
||||
|
||||
if (type == script_type::file)
|
||||
{
|
||||
@ -734,7 +626,6 @@ namespace ui_scripting::lua
|
||||
{
|
||||
this->state_.collect_garbage();
|
||||
this->scheduler_.clear();
|
||||
this->event_handler_.clear();
|
||||
this->state_ = {};
|
||||
}
|
||||
|
||||
@ -744,12 +635,6 @@ namespace ui_scripting::lua
|
||||
this->state_.collect_garbage();
|
||||
}
|
||||
|
||||
void context::notify(const event& e)
|
||||
{
|
||||
this->scheduler_.dispatch(e);
|
||||
this->event_handler_.dispatch(e);
|
||||
}
|
||||
|
||||
void context::load_script(const std::string& script)
|
||||
{
|
||||
if (!this->loaded_scripts_.emplace(script).second)
|
||||
|
@ -41,7 +41,6 @@ namespace ui_scripting::lua
|
||||
std::unordered_set<std::string> loaded_scripts_;
|
||||
|
||||
scheduler scheduler_;
|
||||
event_handler event_handler_;
|
||||
|
||||
void load_script(const std::string& script);
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "../../../component/scheduler.hpp"
|
||||
#include "../../../component/ui_scripting.hpp"
|
||||
#include "../../../component/filesystem.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
@ -13,28 +14,8 @@ namespace ui_scripting::lua::engine
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const auto updater_script = utils::nt::load_resource(LUI_UPDATER_MENU);
|
||||
|
||||
void handle_key_event(const int key, const int down)
|
||||
{
|
||||
event event;
|
||||
event.name = down
|
||||
? "keydown"
|
||||
: "keyup";
|
||||
event.arguments = {key};
|
||||
|
||||
engine::notify(event);
|
||||
}
|
||||
|
||||
void handle_char_event(const int key)
|
||||
{
|
||||
std::string key_str = {(char)key};
|
||||
event event;
|
||||
event.name = "keypress";
|
||||
event.arguments = {key_str};
|
||||
|
||||
engine::notify(event);
|
||||
}
|
||||
const auto lui_common = utils::nt::load_resource(LUI_COMMON);
|
||||
const auto lui_updater = utils::nt::load_resource(LUI_UPDATER);
|
||||
|
||||
auto& get_scripts()
|
||||
{
|
||||
@ -71,15 +52,12 @@ namespace ui_scripting::lua::engine
|
||||
clear_converted_functions();
|
||||
get_scripts().clear();
|
||||
|
||||
load_code(updater_script);
|
||||
load_code(lui_common);
|
||||
load_code(lui_updater);
|
||||
|
||||
load_scripts("ui_scripts/");
|
||||
load_scripts("h2-mod/ui_scripts/");
|
||||
load_scripts("data/ui_scripts/");
|
||||
|
||||
if (!game::mod_folder.empty())
|
||||
for (const auto& path : filesystem::get_search_paths())
|
||||
{
|
||||
load_scripts(utils::string::va("%s/ui_scripts/", game::mod_folder.data()));
|
||||
load_scripts(path + "/ui_scripts/");
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,27 +67,6 @@ namespace ui_scripting::lua::engine
|
||||
get_scripts().clear();
|
||||
}
|
||||
|
||||
void ui_event(const std::string& type, const std::vector<int>& arguments)
|
||||
{
|
||||
if (type == "key")
|
||||
{
|
||||
handle_key_event(arguments[0], arguments[1]);
|
||||
}
|
||||
|
||||
if (type == "char")
|
||||
{
|
||||
handle_char_event(arguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void notify(const event& e)
|
||||
{
|
||||
for (auto& script : get_scripts())
|
||||
{
|
||||
script->notify(e);
|
||||
}
|
||||
}
|
||||
|
||||
void run_frame()
|
||||
{
|
||||
for (auto& script : get_scripts())
|
||||
|
@ -6,8 +6,5 @@ namespace ui_scripting::lua::engine
|
||||
{
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void ui_event(const std::string&, const std::vector<int>&);
|
||||
void notify(const event& e);
|
||||
void run_frame();
|
||||
}
|
||||
|
@ -56,4 +56,5 @@ namespace ui_scripting
|
||||
};
|
||||
|
||||
using arguments = std::vector<script_value>;
|
||||
using event_arguments = std::unordered_map<std::string, script_value>;
|
||||
}
|
||||
|
@ -273,4 +273,38 @@ namespace ui_scripting
|
||||
{
|
||||
return call_script_function(*this, arguments);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Stack
|
||||
**************************************************************/
|
||||
|
||||
stack::stack()
|
||||
{
|
||||
this->state = *game::hks::lua_state;
|
||||
this->state->m_apistack.top = this->state->m_apistack.base;
|
||||
}
|
||||
|
||||
void stack::save(int num_args)
|
||||
{
|
||||
this->num_args_ = num_args;
|
||||
this->num_calls_ = state->m_numberOfCCalls;
|
||||
this->base_bottom_ = state->m_apistack.base - state->m_apistack.bottom;
|
||||
this->top_bottom_ = state->m_apistack.top - state->m_apistack.bottom;
|
||||
this->callstack_ = state->m_callStack.m_current - state->m_callStack.m_records;
|
||||
}
|
||||
|
||||
void stack::fix()
|
||||
{
|
||||
this->state->m_numberOfCCalls = this->num_calls_;
|
||||
|
||||
game::hks::closePendingUpvalues(this->state, &this->state->m_apistack.bottom[this->top_bottom_ - this->num_args_]);
|
||||
this->state->m_callStack.m_current = &this->state->m_callStack.m_records[this->callstack_];
|
||||
|
||||
this->state->m_apistack.base = &this->state->m_apistack.bottom[this->base_bottom_];
|
||||
this->state->m_apistack.top = &this->state->m_apistack.bottom[this->top_bottom_ - static_cast<uint64_t>(this->num_args_ + 1)];
|
||||
|
||||
this->state->m_apistack.bottom[this->top_bottom_].t = this->state->m_apistack.top[-1].t;
|
||||
this->state->m_apistack.bottom[this->top_bottom_].v.ptr = this->state->m_apistack.top[-1].v.ptr;
|
||||
this->state->m_apistack.top = &this->state->m_apistack.bottom[this->top_bottom_ + 1];
|
||||
}
|
||||
}
|
@ -86,4 +86,28 @@ namespace ui_scripting
|
||||
|
||||
int ref{};
|
||||
};
|
||||
|
||||
class stack final
|
||||
{
|
||||
public:
|
||||
stack();
|
||||
|
||||
void save(int num_args);
|
||||
void fix();
|
||||
|
||||
stack(stack&&) = delete;
|
||||
stack(const stack&) = delete;
|
||||
stack& operator=(stack&&) = delete;
|
||||
stack& operator=(const stack&) = delete;
|
||||
|
||||
private:
|
||||
game::hks::lua_State* state;
|
||||
|
||||
int num_args_;
|
||||
int num_calls_;
|
||||
|
||||
uint64_t base_bottom_;
|
||||
uint64_t top_bottom_;
|
||||
uint64_t callstack_;
|
||||
};
|
||||
}
|
@ -31,7 +31,7 @@ FARPROC loader::load(const utils::nt::library& library, const std::string& buffe
|
||||
return FARPROC(library.get_ptr() + source.get_relative_entry_point());
|
||||
}
|
||||
|
||||
FARPROC loader::load_library(const std::string& filename, uint64_t* base_address) const
|
||||
FARPROC loader::load_library(const std::string& filename) const
|
||||
{
|
||||
const auto target = utils::nt::library::load(filename);
|
||||
if (!target)
|
||||
@ -39,9 +39,6 @@ FARPROC loader::load_library(const std::string& filename, uint64_t* base_address
|
||||
throw std::runtime_error{"Failed to map binary!"};
|
||||
}
|
||||
|
||||
const auto base = size_t(target.get_ptr());
|
||||
*base_address = base;
|
||||
|
||||
this->load_imports(target, target);
|
||||
this->load_tls(target, target);
|
||||
|
||||
|
@ -5,7 +5,7 @@ class loader final
|
||||
{
|
||||
public:
|
||||
FARPROC load(const utils::nt::library& library, const std::string& buffer) const;
|
||||
FARPROC load_library(const std::string& filename, uint64_t* base_address) const;
|
||||
FARPROC load_library(const std::string& filename) const;
|
||||
|
||||
void set_import_resolver(const std::function<void*(const std::string&, const std::string&)>& resolver);
|
||||
|
||||
|
@ -39,7 +39,7 @@ launcher::mode detect_mode_from_arguments()
|
||||
return launcher::mode::none;
|
||||
}
|
||||
|
||||
FARPROC load_binary(const launcher::mode mode, uint64_t* base_address)
|
||||
FARPROC load_binary(const launcher::mode mode)
|
||||
{
|
||||
loader loader;
|
||||
utils::nt::library self;
|
||||
@ -87,7 +87,7 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address)
|
||||
binary.data()));
|
||||
}
|
||||
|
||||
return loader.load_library(binary, base_address);
|
||||
return loader.load(self, data);
|
||||
}
|
||||
|
||||
void remove_crash_file()
|
||||
@ -97,7 +97,7 @@ void remove_crash_file()
|
||||
|
||||
void verify_version()
|
||||
{
|
||||
const auto value = *reinterpret_cast<DWORD*>(0x123456_b);
|
||||
const auto value = *reinterpret_cast<DWORD*>(0x140123456);
|
||||
if (value != 0xE465E151)
|
||||
{
|
||||
throw std::runtime_error("Unsupported Call of Duty: Modern Warfare 2 Campaign Remastered version");
|
||||
@ -184,14 +184,12 @@ int main()
|
||||
|
||||
game::environment::set_mode(mode);
|
||||
|
||||
uint64_t base_address{};
|
||||
entry_point = load_binary(mode, &base_address);
|
||||
entry_point = load_binary(mode);
|
||||
if (!entry_point)
|
||||
{
|
||||
throw std::runtime_error("Unable to load binary into memory");
|
||||
}
|
||||
|
||||
game::base_address = base_address;
|
||||
verify_version();
|
||||
|
||||
if (!component_loader::post_load())
|
||||
|
@ -2,23 +2,13 @@
|
||||
|
||||
#define ID_ICON 102
|
||||
|
||||
#define IMAGE_SPLASH 300
|
||||
#define IMAGE_LOGO 301
|
||||
#define MENU_MAIN 300
|
||||
|
||||
#define DW_ENTITLEMENT_CONFIG 302
|
||||
#define DW_SOCIAL_CONFIG 303
|
||||
#define DW_MM_CONFIG 304
|
||||
#define DW_LOOT_CONFIG 305
|
||||
#define DW_STORE_CONFIG 306
|
||||
#define DW_MOTD 307
|
||||
#define DW_FASTFILE 308
|
||||
#define DW_PLAYLISTS 309
|
||||
#define TLS_DLL 301
|
||||
|
||||
#define MENU_MAIN 310
|
||||
#define ICON_IMAGE 302
|
||||
|
||||
#define TLS_DLL 311
|
||||
#define LUI_COMMON 303
|
||||
#define LUI_UPDATER 304
|
||||
|
||||
#define ICON_IMAGE 312
|
||||
|
||||
#define LUA_JSON_SCRIPT 313
|
||||
#define LUI_UPDATER_MENU 314
|
||||
#define LUA_JSON 305
|
||||
|
@ -97,8 +97,10 @@ ID_ICON ICON "resources/icon.ico"
|
||||
|
||||
MENU_MAIN RCDATA "resources/main.html"
|
||||
|
||||
LUA_JSON_SCRIPT RCDATA "resources/json.lua"
|
||||
LUI_UPDATER_MENU RCDATA "resources/updater.lua"
|
||||
LUI_COMMON RCDATA "resources/ui_scripts/common.lua"
|
||||
LUI_UPDATER RCDATA "resources/ui_scripts/updater.lua"
|
||||
|
||||
LUA_JSON RCDATA "resources/json.lua"
|
||||
|
||||
#ifdef _DEBUG
|
||||
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
|
||||
|
162
src/client/resources/ui_scripts/common.lua
Normal file
162
src/client/resources/ui_scripts/common.lua
Normal file
@ -0,0 +1,162 @@
|
||||
menucallbacks = {}
|
||||
originalmenus = {}
|
||||
stack = {}
|
||||
|
||||
LUI.MenuBuilder.m_types_build["generic_waiting_popup_"] = function (menu, event)
|
||||
local oncancel = stack.oncancel
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType("waiting_popup", {
|
||||
message_text = stack.text,
|
||||
isLiveWithCancel = true,
|
||||
cancel_func = function(...)
|
||||
local args = {...}
|
||||
oncancel()
|
||||
LUI.FlowManager.RequestLeaveMenu(args[1])
|
||||
end
|
||||
})
|
||||
|
||||
popup.text = popup:getchildren()[7]
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return popup
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["generic_yes_no_popup_"] = function()
|
||||
local callback = stack.callback
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType("generic_yesno_popup", {
|
||||
popup_title = stack.title,
|
||||
message_text = stack.text,
|
||||
yes_action = function()
|
||||
callback(true)
|
||||
end,
|
||||
no_action = function()
|
||||
callback(false)
|
||||
end
|
||||
})
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return popup
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["generic_confirmation_popup_"] = function()
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType( "generic_confirmation_popup", {
|
||||
cancel_will_close = false,
|
||||
popup_title = stack.title,
|
||||
message_text = stack.text,
|
||||
button_text = stack.buttontext,
|
||||
confirmation_action = stack.callback
|
||||
})
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.onmenuopen = function(name, callback)
|
||||
if (not LUI.MenuBuilder.m_types_build[name]) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not menucallbacks[name]) then
|
||||
menucallbacks[name] = {}
|
||||
end
|
||||
|
||||
table.insert(menucallbacks[name], callback)
|
||||
|
||||
if (not originalmenus[name]) then
|
||||
originalmenus[name] = LUI.MenuBuilder.m_types_build[name]
|
||||
LUI.MenuBuilder.m_types_build[name] = function(...)
|
||||
local args = {...}
|
||||
local menu = originalmenus[name](table.unpack(args))
|
||||
|
||||
for k, v in luiglobals.next, menucallbacks[name] do
|
||||
v(menu, table.unpack(args))
|
||||
end
|
||||
|
||||
return menu
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local addoptionstextinfo = LUI.Options.AddOptionTextInfo
|
||||
LUI.Options.AddOptionTextInfo = function(menu)
|
||||
local result = addoptionstextinfo(menu)
|
||||
menu.optionTextInfo = result
|
||||
return result
|
||||
end
|
||||
|
||||
LUI.addmenubutton = function(name, data)
|
||||
LUI.onmenuopen(name, function(menu)
|
||||
if (not menu.list) then
|
||||
return
|
||||
end
|
||||
|
||||
local button = menu:AddButton(data.text, data.callback, nil, true, nil, {
|
||||
desc_text = data.description
|
||||
})
|
||||
|
||||
local buttonlist = menu:getChildById(menu.type .. "_list")
|
||||
|
||||
if (data.id) then
|
||||
button.id = data.id
|
||||
end
|
||||
|
||||
if (data.index) then
|
||||
buttonlist:removeElement(button)
|
||||
buttonlist:insertElement(button, data.index)
|
||||
end
|
||||
|
||||
local hintbox = menu.optionTextInfo
|
||||
menu:removeElement(hintbox)
|
||||
|
||||
LUI.Options.InitScrollingList(menu.list, nil)
|
||||
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
||||
end)
|
||||
end
|
||||
|
||||
LUI.openmenu = function(menu, args)
|
||||
stack = args
|
||||
LUI.FlowManager.RequestAddMenu(nil, menu)
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.openpopupmenu = function(menu, args)
|
||||
stack = args
|
||||
LUI.FlowManager.RequestPopupMenu(nil, menu)
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.yesnopopup = function(data)
|
||||
for k, v in luiglobals.next, data do
|
||||
stack[k] = v
|
||||
end
|
||||
LUI.FlowManager.RequestPopupMenu(nil, "generic_yes_no_popup_")
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.confirmationpopup = function(data)
|
||||
for k, v in luiglobals.next, data do
|
||||
stack[k] = v
|
||||
end
|
||||
LUI.FlowManager.RequestPopupMenu(nil, "generic_confirmation_popup_")
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
function userdata_:getchildren()
|
||||
local children = {}
|
||||
local first = self:getFirstChild()
|
||||
|
||||
while (first) do
|
||||
table.insert(children, first)
|
||||
first = first:getNextSibling()
|
||||
end
|
||||
|
||||
return children
|
||||
end
|
160
src/client/resources/ui_scripts/updater.lua
Normal file
160
src/client/resources/ui_scripts/updater.lua
Normal file
@ -0,0 +1,160 @@
|
||||
updatecancelled = false
|
||||
taskinterval = 100
|
||||
|
||||
updater.cancelupdate()
|
||||
|
||||
function startupdatecheck(popup, autoclose)
|
||||
updatecancelled = false
|
||||
|
||||
local callback = function()
|
||||
if (not updater.getupdatecheckstatus()) then
|
||||
if (autoclose) then
|
||||
LUI.FlowManager.RequestLeaveMenu(popup)
|
||||
return
|
||||
end
|
||||
|
||||
popup.text:setText("Error: " .. updater.getlasterror())
|
||||
return
|
||||
end
|
||||
|
||||
if (not updater.isupdateavailable()) then
|
||||
if (autoclose) then
|
||||
LUI.FlowManager.RequestLeaveMenu(popup)
|
||||
return
|
||||
end
|
||||
|
||||
popup.text:setText("No updates available")
|
||||
return
|
||||
end
|
||||
|
||||
LUI.yesnopopup({
|
||||
title = "NOTICE",
|
||||
text = "An update is available, proceed with installation?",
|
||||
callback = function(result)
|
||||
if (result) then
|
||||
startupdatedownload(popup, autoclose)
|
||||
else
|
||||
LUI.FlowManager.RequestLeaveMenu(popup)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
updater.startupdatecheck()
|
||||
createtask({
|
||||
done = updater.isupdatecheckdone,
|
||||
cancelled = isupdatecancelled,
|
||||
callback = callback,
|
||||
interval = taskinterval
|
||||
})
|
||||
end
|
||||
|
||||
function startupdatedownload(popup, autoclose)
|
||||
updater.startupdatedownload()
|
||||
|
||||
local textupdate = nil
|
||||
local previousfile = nil
|
||||
textupdate = game:oninterval(function()
|
||||
local file = updater.getcurrentfile()
|
||||
if (file == previousfile) then
|
||||
return
|
||||
end
|
||||
|
||||
file = previousfile
|
||||
popup.text:setText("Downloading file " .. updater.getcurrentfile() .. "...")
|
||||
end, 10)
|
||||
|
||||
local callback = function()
|
||||
textupdate:clear()
|
||||
|
||||
if (not updater.getupdatedownloadstatus()) then
|
||||
if (autoclose) then
|
||||
LUI.FlowManager.RequestLeaveMenu(popup)
|
||||
return
|
||||
end
|
||||
|
||||
popup.text:setText("Error: " .. updater.getlasterror())
|
||||
return
|
||||
end
|
||||
|
||||
popup.text:setText("Update successful")
|
||||
|
||||
if (updater.isrestartrequired()) then
|
||||
LUI.confirmationpopup({
|
||||
title = "RESTART REQUIRED",
|
||||
text = "Update requires restart",
|
||||
buttontext = "RESTART",
|
||||
callback = function()
|
||||
updater.relaunch()
|
||||
end
|
||||
})
|
||||
else
|
||||
Engine.Exec("lui_restart")
|
||||
end
|
||||
|
||||
if (autoclose) then
|
||||
LUI.FlowManager.RequestLeaveMenu(popup)
|
||||
end
|
||||
end
|
||||
|
||||
createtask({
|
||||
done = updater.isupdatedownloaddone,
|
||||
cancelled = isupdatecancelled,
|
||||
callback = callback,
|
||||
interval = taskinterval
|
||||
})
|
||||
end
|
||||
|
||||
function updaterpopup(oncancel)
|
||||
return LUI.openpopupmenu("generic_waiting_popup_", {
|
||||
oncancel = oncancel,
|
||||
withcancel = true,
|
||||
text = "Checking for updates..."
|
||||
})
|
||||
end
|
||||
|
||||
function createtask(data)
|
||||
local interval = nil
|
||||
interval = game:oninterval(function()
|
||||
if (data.cancelled()) then
|
||||
interval:clear()
|
||||
return
|
||||
end
|
||||
|
||||
if (data.done()) then
|
||||
interval:clear()
|
||||
data.callback()
|
||||
end
|
||||
end, data.interval)
|
||||
return interval
|
||||
end
|
||||
|
||||
function isupdatecancelled()
|
||||
return updatecancelled
|
||||
end
|
||||
|
||||
function tryupdate(autoclose)
|
||||
updatecancelled = false
|
||||
local popup = updaterpopup(function()
|
||||
updater.cancelupdate()
|
||||
updatecancelled = true
|
||||
end)
|
||||
|
||||
startupdatecheck(popup, autoclose)
|
||||
end
|
||||
|
||||
function tryautoupdate()
|
||||
if (not updater.autoupdatesenabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not updater.gethastriedupdate()) then
|
||||
game:ontimeout(function()
|
||||
updater.sethastriedupdate(true)
|
||||
tryupdate(true)
|
||||
end, 100)
|
||||
end
|
||||
end
|
||||
|
||||
LUI.tryupdating = tryupdate
|
||||
LUI.onmenuopen("main_lockout", tryautoupdate)
|
@ -1,411 +0,0 @@
|
||||
menucallbacks = {}
|
||||
originalmenus = {}
|
||||
|
||||
LUI.onmenuopen = function(name, callback)
|
||||
if (not LUI.MenuBuilder.m_types_build[name]) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not menucallbacks[name]) then
|
||||
menucallbacks[name] = {}
|
||||
end
|
||||
|
||||
table.insert(menucallbacks[name], callback)
|
||||
|
||||
if (not originalmenus[name]) then
|
||||
originalmenus[name] = LUI.MenuBuilder.m_types_build[name]
|
||||
LUI.MenuBuilder.m_types_build[name] = function(...)
|
||||
local args = {...}
|
||||
local menu = originalmenus[name](table.unpack(args))
|
||||
|
||||
for k, v in luiglobals.next, menucallbacks[name] do
|
||||
v(menu, table.unpack(args))
|
||||
end
|
||||
|
||||
return menu
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local addoptionstextinfo = LUI.Options.AddOptionTextInfo
|
||||
LUI.Options.AddOptionTextInfo = function(menu)
|
||||
local result = addoptionstextinfo(menu)
|
||||
menu.optionTextInfo = result
|
||||
return result
|
||||
end
|
||||
|
||||
LUI.addmenubutton = function(name, data)
|
||||
LUI.onmenuopen(name, function(menu)
|
||||
if (not menu.list) then
|
||||
return
|
||||
end
|
||||
|
||||
local button = menu:AddButton(data.text, data.callback, nil, true, nil, {
|
||||
desc_text = data.description
|
||||
})
|
||||
|
||||
local buttonlist = menu:getChildById(menu.type .. "_list")
|
||||
|
||||
if (data.id) then
|
||||
button.id = data.id
|
||||
end
|
||||
|
||||
if (data.index) then
|
||||
buttonlist:removeElement(button)
|
||||
buttonlist:insertElement(button, data.index)
|
||||
end
|
||||
|
||||
local hintbox = menu.optionTextInfo
|
||||
menu:removeElement(hintbox)
|
||||
|
||||
LUI.Options.InitScrollingList(menu.list, nil)
|
||||
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
||||
end)
|
||||
end
|
||||
|
||||
stack = {}
|
||||
LUI.openmenu = function(menu, args)
|
||||
stack = args
|
||||
LUI.FlowManager.RequestAddMenu(nil, menu)
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.openpopupmenu = function(menu, args)
|
||||
stack = args
|
||||
LUI.FlowManager.RequestPopupMenu(nil, menu)
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.onmenuopen("main_lockout", function()
|
||||
if (game:isdebugbuild() or not Engine.GetDvarBool("cg_autoUpdate")) then
|
||||
return
|
||||
end
|
||||
|
||||
if (game:sharedget("has_tried_updating") == "") then
|
||||
game:ontimeout(function()
|
||||
game:sharedset("has_tried_updating", "1")
|
||||
tryupdate(true)
|
||||
end, 0)
|
||||
end
|
||||
end)
|
||||
|
||||
stack = {}
|
||||
LUI.MenuBuilder.m_types_build["generic_waiting_popup_"] = function (menu, event)
|
||||
local oncancel = stack.oncancel
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType("waiting_popup", {
|
||||
message_text = stack.text,
|
||||
isLiveWithCancel = true,
|
||||
cancel_func = function(...)
|
||||
local args = {...}
|
||||
oncancel()
|
||||
LUI.common_menus.CommonPopups.CancelCSSDownload(table.unpack(args))
|
||||
end
|
||||
})
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return popup
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["generic_yes_no_popup_"] = function()
|
||||
local callback = stack.callback
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType("generic_yesno_popup", {
|
||||
popup_title = stack.title,
|
||||
message_text = stack.text,
|
||||
yes_action = function()
|
||||
callback(true)
|
||||
end,
|
||||
no_action = function()
|
||||
callback(false)
|
||||
end
|
||||
})
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return popup
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["generic_confirmation_popup_"] = function()
|
||||
local popup = LUI.MenuBuilder.BuildRegisteredType( "generic_confirmation_popup", {
|
||||
cancel_will_close = false,
|
||||
popup_title = stack.title,
|
||||
message_text = stack.text,
|
||||
button_text = stack.buttontext,
|
||||
confirmation_action = stack.callback
|
||||
})
|
||||
|
||||
stack = {
|
||||
ret = popup
|
||||
}
|
||||
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.yesnopopup = function(data)
|
||||
for k, v in luiglobals.next, data do
|
||||
stack[k] = v
|
||||
end
|
||||
LUI.FlowManager.RequestPopupMenu(nil, "generic_yes_no_popup_")
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
LUI.confirmationpopup = function(data)
|
||||
for k, v in luiglobals.next, data do
|
||||
stack[k] = v
|
||||
end
|
||||
LUI.FlowManager.RequestPopupMenu(nil, "generic_confirmation_popup_")
|
||||
return stack.ret
|
||||
end
|
||||
|
||||
function updaterpopup(oncancel)
|
||||
return LUI.openpopupmenu("generic_waiting_popup_", {
|
||||
oncancel = oncancel,
|
||||
withcancel = true,
|
||||
text = "Checking for updates..."
|
||||
})
|
||||
end
|
||||
|
||||
function deleteoldfile()
|
||||
io.removefile(game:binaryname() .. ".old")
|
||||
end
|
||||
|
||||
deleteoldfile()
|
||||
|
||||
function verifyfiles(files)
|
||||
local needed = {}
|
||||
local updatebinary = false
|
||||
|
||||
if (game:isdebugbuild()) then
|
||||
return needed, updatebinary
|
||||
end
|
||||
|
||||
local binaryname = game:binaryname()
|
||||
|
||||
for i = 1, #files do
|
||||
local name = files[i][1]
|
||||
|
||||
if (io.fileexists(name) and game:sha(io.readfile(name)) == files[i][3]) then
|
||||
goto continue
|
||||
end
|
||||
|
||||
if (name == binaryname) then
|
||||
updatebinary = true
|
||||
end
|
||||
|
||||
table.insert(needed, files[i])
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
return needed, updatebinary
|
||||
end
|
||||
|
||||
local canceled = false
|
||||
|
||||
function downloadfiles(popup, files, callback)
|
||||
deleteoldfile()
|
||||
|
||||
local text = popup:getchildren()[7]
|
||||
local folder = game:environment() == "develop" and "data-dev" or "data"
|
||||
|
||||
if (#files == 0) then
|
||||
callback(true)
|
||||
return
|
||||
end
|
||||
|
||||
local total = 0
|
||||
local filedownloaded = function()
|
||||
total = total + 1
|
||||
if (total == #files) then
|
||||
callback(true)
|
||||
end
|
||||
end
|
||||
|
||||
local download = nil
|
||||
local stop = false
|
||||
download = function(index)
|
||||
if (canceled or stop) then
|
||||
return
|
||||
end
|
||||
|
||||
local filename = files[index][1]
|
||||
|
||||
local url = "https://master.fed0001.xyz/" .. folder .. "/" .. filename .. "?" .. os.time()
|
||||
text:setText(string.format("Downloading file [%i/%i]\n%s", index, #files, filename))
|
||||
|
||||
if (filename == game:binaryname()) then
|
||||
io.movefile(filename, filename .. ".old")
|
||||
end
|
||||
|
||||
httprequesttofile(url, filename, function(valid, success)
|
||||
if (not valid) then
|
||||
callback(false, "Invalid server response")
|
||||
stop = true
|
||||
return
|
||||
end
|
||||
|
||||
if (not success) then
|
||||
callback(false, "Failed to write file " .. filename)
|
||||
stop = true
|
||||
return
|
||||
end
|
||||
|
||||
filedownloaded()
|
||||
|
||||
if (files[index + 1]) then
|
||||
download(index + 1)
|
||||
else
|
||||
callback(true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
download(1)
|
||||
end
|
||||
|
||||
function userdata_:getchildren()
|
||||
local children = {}
|
||||
local first = self:getFirstChild()
|
||||
|
||||
while (first) do
|
||||
table.insert(children, first)
|
||||
first = first:getNextSibling()
|
||||
end
|
||||
|
||||
return children
|
||||
end
|
||||
|
||||
function tryupdate(autoclose)
|
||||
canceled = false
|
||||
local popup = updaterpopup(function()
|
||||
canceled = true
|
||||
end)
|
||||
|
||||
local text = popup:getchildren()[7]
|
||||
local file = game:environment() == "develop" and "files-dev.json" or "files.json"
|
||||
local url = "https://master.fed0001.xyz/" .. file .. "?" .. os.time()
|
||||
|
||||
httprequest(url, function(valid, data)
|
||||
if (not valid) then
|
||||
text:setText("Update check failed: Invalid server response")
|
||||
return
|
||||
end
|
||||
|
||||
local valid = pcall(function()
|
||||
local files = json.decode(data)
|
||||
local needed, updatebinary = verifyfiles(files)
|
||||
|
||||
if (#needed == 0) then
|
||||
text:setText("No updates available")
|
||||
if (autoclose) then
|
||||
LUI.common_menus.CommonPopups.CancelCSSDownload(popup, {})
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local download = function()
|
||||
local gotresult = false
|
||||
downloadfiles(popup, needed, function(result, error)
|
||||
if (gotresult or canceled) then
|
||||
return
|
||||
end
|
||||
|
||||
gotresult = true
|
||||
|
||||
if (not result) then
|
||||
text:setText("Update failed: " .. error)
|
||||
return
|
||||
end
|
||||
|
||||
if (updatebinary) then
|
||||
LUI.confirmationpopup({
|
||||
title = "RESTART REQUIRED",
|
||||
text = "Update requires restart",
|
||||
buttontext = "RESTART",
|
||||
callback = function()
|
||||
game:relaunch()
|
||||
end
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
if (result and #needed > 0) then
|
||||
game:executecommand("lui_restart")
|
||||
return
|
||||
end
|
||||
|
||||
text:setText("Update successful!")
|
||||
|
||||
if (autoclose) then
|
||||
LUI.common_menus.CommonPopups.CancelCSSDownload(popup, {})
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if (autoclose) then
|
||||
download()
|
||||
else
|
||||
LUI.yesnopopup({
|
||||
title = "NOTICE",
|
||||
text = "An update is available, proceed with installation?",
|
||||
callback = function(result)
|
||||
if (not result) then
|
||||
LUI.common_menus.CommonPopups.CancelCSSDownload(popup, {})
|
||||
else
|
||||
download()
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
if (not valid) then
|
||||
text:setText("Update failed: unknown error")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
LUI.tryupdating = function(autoclose)
|
||||
tryupdate(autoclose)
|
||||
end
|
||||
|
||||
function httprequest(url, callback)
|
||||
local request = game:httpget(url)
|
||||
local listener = nil
|
||||
listener = game:onnotify("http_request_done", function(id, valid, data)
|
||||
if (id ~= request) then
|
||||
return
|
||||
end
|
||||
|
||||
listener:clear()
|
||||
callback(valid, data)
|
||||
end)
|
||||
end
|
||||
|
||||
function httprequesttofile(url, dest, callback)
|
||||
local request = game:httpgettofile(url, dest)
|
||||
local listener = nil
|
||||
listener = game:onnotify("http_request_done", function(id, valid, success)
|
||||
if (id ~= request) then
|
||||
return
|
||||
end
|
||||
|
||||
listener:clear()
|
||||
callback(valid, success)
|
||||
end)
|
||||
end
|
||||
|
||||
local localize = Engine.Localize
|
||||
Engine.Localize = function(...)
|
||||
local args = {...}
|
||||
|
||||
if (type(args[1]) == "string" and args[1]:sub(1, 2) == "$_") then
|
||||
return args[1]:sub(3, -1)
|
||||
end
|
||||
|
||||
return localize(table.unpack(args))
|
||||
end
|
@ -1,6 +1,13 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#pragma comment(linker, "/base:0x7FFF00000000")
|
||||
#pragma comment(linker, "/merge:.data=.cld")
|
||||
#pragma comment(linker, "/merge:.rdata=.clr")
|
||||
#pragma comment(linker, "/merge:.cl=.main")
|
||||
#pragma comment(linker, "/merge:.text=.main")
|
||||
#pragma comment(linker, "/stack:0x1000000")
|
||||
#pragma comment(linker, "/base:0x140000000")
|
||||
#pragma bss_seg(".payload")
|
||||
char payload_data[BINARY_PAYLOAD_SIZE];
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@ -10,6 +17,12 @@ extern "C"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// workaround for release build removing 'payload_data'
|
||||
char* dont_remove_this()
|
||||
{
|
||||
return payload_data;
|
||||
}
|
||||
|
||||
int s_read_arc4random(void*, size_t)
|
||||
{
|
||||
return -1;
|
||||
|
@ -86,8 +86,6 @@
|
||||
#include <asmjit/core/jitruntime.h>
|
||||
#include <asmjit/x86/x86assembler.h>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
Loading…
Reference in New Issue
Block a user