diff --git a/data/scripts/logging/__init__.lua b/data/scripts/logging/__init__.lua new file mode 100644 index 00000000..33db4cfc --- /dev/null +++ b/data/scripts/logging/__init__.lua @@ -0,0 +1,117 @@ +-- modified version of https://github.com/Joelrau/S1x-IW6x-g_log-script (permission to use by author) + +if (game:getdvar("gamemode") ~= "mp") then + return +end + +-- setup dvars +game:setdvarifuninitialized("logfile", 1) +if (tonumber(game:getdvar("logfile")) < 1) then + return +end +game:setdvarifuninitialized("g_log", "logs/games_mp.log") + +start_time = 0 + +function get_time() + local seconds = math.floor((game:gettime() - start_time) / 1000) + local minutes = math.floor(seconds / 60) + time = string.format("%d:%02d", minutes, seconds - minutes * 60) + while (string.len(time) < 6) do + time = " " .. time + end + time = time .. " " + return time +end + +function create_path(path) + local dir = path:gsub("%/", "\\"):match("(.*[\\])") + os.execute("if not exist " .. dir .. " mkdir " .. dir) +end + +function log_print(message) + local path = game:getdvar("g_log") + local file = io.open(path, "a") + if (file == nil) then + create_path(path) + file = assert(io.open(path, "a")) + end + file:write(get_time() .. message .. "\n") + file:close() +end + +function init() + start_time = game:gettime() + + log_print("------------------------------------------------------------") + log_print("InitGame") + + -- player callbacks + level:onnotify("connected", function(player) + player:player_connected() + end) + level:onnotify("say", function(player, message, hidden) + player:say(message) + end) + level:onnotify("say_team", function(player, message, hidden) + player:say(message, "say_team") + end) + + -- damage/killed hooks + game:onplayerdamage(player_damage) + game:onplayerkilled(player_killed) + + -- other level notifies for log + level:onnotify("exitLevel_called", function() + log_print("ExitLevel: executed") + end) + level:onnotify("shutdownGame_called", function() + log_print("ShutdownGame:") + log_print("------------------------------------------------------------") + end) +end + +function entity:player_connected() + log_print(string.format("J;%s;%i;%s", self:getguid(), self:getentitynumber(), self.name)) + + self:onnotifyonce("disconnect", function() + self:disconnect() + end) +end + +function entity:disconnect() + log_print(string.format("Q;%s;%i;%s", self:getguid(), self:getentitynumber(), self.name)) +end + +function player_damage(self_, inflictor, attacker, damage, dflags, mod, weapon, vPoint, vDir, hitLoc) + if (game:isplayer(attacker) == 1) then + log_print(string.format("D;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(), + self_.team, self_.name, attacker:getguid(), attacker:getentitynumber(), attacker.team, attacker.name, + weapon, damage, mod, hitLoc)) + else + log_print(string.format("D;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(), + self_.team, self_.name, "", "-1", "world", "", weapon, damage, mod, hitLoc)) + end +end + +function player_killed(self_, inflictor, attacker, damage, mod, weapon, vDir, hitLoc, psTimeOffset, deathAnimDuration) + if (game:isplayer(attacker) == 1) then + log_print(string.format("K;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(), + self_.team, self_.name, attacker:getguid(), attacker:getentitynumber(), attacker.team, attacker.name, + weapon, damage, mod, hitLoc)) + else + log_print(string.format("K;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(), + self_.team, self_.name, "", "-1", "world", "", weapon, damage, mod, hitLoc)) + end +end + +-- this function handles 'say' and 'say_team' +function entity:say(message, mode) + if (not mode) then + mode = "say" + end + + log_print(string.format("%s;%s;%i;%s;%s", mode, self:getguid(), self:getentitynumber(), self.name, message)) +end + +init() diff --git a/data/ui_scripts/extra_gamemodes/__init__.lua b/data/ui_scripts/extra_gamemodes/__init__.lua index 6bdadc82..5608b759 100644 --- a/data/ui_scripts/extra_gamemodes/__init__.lua +++ b/data/ui_scripts/extra_gamemodes/__init__.lua @@ -1,3 +1,7 @@ +if (game:issingleplayer() or not Engine.InFrontend()) then + return +end + Cac.GameModes.Data = { Standard = { Label = Engine.Localize("@MPUI_STANDARD_CAPS"), diff --git a/data/ui_scripts/server_list/lobby.lua b/data/ui_scripts/server_list/lobby.lua index 93e01a90..20027026 100644 --- a/data/ui_scripts/server_list/lobby.lua +++ b/data/ui_scripts/server_list/lobby.lua @@ -63,6 +63,20 @@ function menu_xboxlive(f16_arg0, f16_arg1) Engine.ExecNow("eliteclan_refresh", Engine.GetFirstActiveController()) end + local root = Engine.GetLuiRoot() + if (root.vltimer) then + root.vltimer:close() + end + + root.vltimer = LUI.UITimer.new(4000, "vl") + root:addElement(root.vltimer) + root:registerEventHandler("vl", function() + if (Engine.GetDvarBool("virtualLobbyReady")) then + root.vltimer:close() + game:virtuallobbypresentable() + end + end) + return menu end diff --git a/data/ui_scripts/server_list/serverlist.lua b/data/ui_scripts/server_list/serverlist.lua index 568670ed..daed0300 100644 --- a/data/ui_scripts/server_list/serverlist.lua +++ b/data/ui_scripts/server_list/serverlist.lua @@ -10,7 +10,7 @@ game:addlocalizedstring("MENU_PING", "Ping") local columns = { { - offset = 10, + offset = 40, text = "@MENU_HOST_NAME", dataindex = 0 }, @@ -33,6 +33,28 @@ local columns = { offset = 1100, text = "@MENU_PING", dataindex = 4 + }, + { + offset = 10, + image = "s1_icon_locked", + customelement = function(value, offset) + return LUI.UIImage.new({ + leftAnchor = true, + topAnchor = true, + height = 20, + width = 20, + left = offset, + top = 2, + material = RegisterMaterial(CoD.Material.RestrictedIcon), + alpha = value == "1" and 1 or 0, + color = { + r = 1, + b = 1, + g = 1 + } + }) + end, + dataindex = 5 } } @@ -68,7 +90,20 @@ SystemLinkJoinMenu.AddHeaderButton = function(menu, f12_arg1, width) button.m_eventHandlers = {} for i = 1, #columns do - SystemLinkJoinMenu.MakeText(button.textHolder, columns[i].offset, Engine.Localize(columns[i].text), nil) + if (columns[i].text) then + SystemLinkJoinMenu.MakeText(button.textHolder, columns[i].offset, Engine.Localize(columns[i].text), nil) + elseif (columns[i].image) then + local image = LUI.UIImage.new({ + leftAnchor = true, + topAnchor = true, + height = 20, + width = 20, + top = 2, + left = columns[i].offset, + material = RegisterMaterial(columns[i].image) + }) + button.textHolder:addElement(image) + end end element:addElement(button) @@ -83,6 +118,9 @@ SystemLinkJoinMenu.AddServerButton = function(menu, controller, index) local gettext = function(i) local text = Lobby.GetServerData(controller, index, columns[i].dataindex) + if (columns[i].customelement) then + text = columns[i].customelement(text) + end local islast = not columns[i + 1] local end_ = islast and 1130 or columns[i + 1].offset @@ -100,7 +138,13 @@ SystemLinkJoinMenu.AddServerButton = function(menu, controller, index) end for i = 1, #columns do - SystemLinkJoinMenu.MakeText(button.textHolder, columns[i].offset, gettext(i), luiglobals.Colors.h1.medium_grey) + if (columns[i].customelement) then + local value = Lobby.GetServerData(controller, index, columns[i].dataindex) + local element = columns[i].customelement(value, columns[i].offset) + button.textHolder:addElement(element) + else + SystemLinkJoinMenu.MakeText(button.textHolder, columns[i].offset, gettext(i), luiglobals.Colors.h1.medium_grey) + end end menu.list:addElement(button) @@ -131,6 +175,8 @@ SystemLinkJoinMenu.MakeText = function(menu, f5_arg1, text, color) el:setText(text) menu:addElement(el) + + return el end function menu_systemlink_join(f19_arg0, f19_arg1) diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 46843e64..2031788a 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -40,6 +40,7 @@ namespace dedicated game::netadr_s target{}; if (server_list::get_master_server(target)) { + console::info("Sending heartbeat"); network::send(target, "heartbeat", "H1"); } } diff --git a/src/client/component/images.cpp b/src/client/component/images.cpp index 7b88c223..cad0cd1e 100644 --- a/src/client/component/images.cpp +++ b/src/client/component/images.cpp @@ -119,8 +119,8 @@ namespace images return; } - setup_texture_hook.create(SELECT_VALUE(0x55F870_b, 0x6829C0_b), setup_texture_stub); - load_texture_hook.create(SELECT_VALUE(0x83300_b, 0xA4AA0_b), load_texture_stub); + setup_texture_hook.create(SELECT_VALUE(0x83300_b, 0xA4AA0_b), setup_texture_stub); + load_texture_hook.create(SELECT_VALUE(0x82050_b, 0xA37A0_b), load_texture_stub); } }; } diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 0c8fd8ae..a5cae4f8 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -250,6 +250,17 @@ namespace patches "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."); utils::hook::call(SELECT_VALUE(0x457BC9_b, 0x1D8E09_b), out_of_memory_text_stub); // "Out of memory. You are probably low on disk space." + // "fix" for rare 'Out of memory error' error + // this will *at least* generate the configs for mp/sp, which is the #1 issue + if (utils::flags::has_flag("memoryfix")) + { + utils::hook::jump(SELECT_VALUE(0x5110D0_b, 0x6200C0_b), malloc); + utils::hook::jump(SELECT_VALUE(0x510FF0_b, 0x61FFE0_b), _aligned_malloc); + utils::hook::jump(SELECT_VALUE(0x511130_b, 0x620120_b), free); + utils::hook::jump(SELECT_VALUE(0x511220_b, 0x620210_b), realloc); + utils::hook::jump(SELECT_VALUE(0x511050_b, 0x620040_b), _aligned_realloc); + } + if (!game::environment::is_sp()) { patch_mp(); @@ -333,16 +344,6 @@ namespace patches // Prevent clients from sending invalid reliableAcknowledge utils::hook::call(0x1CBD06_b, sv_execute_client_message_stub); - // "fix" for rare 'Out of memory error' error - if (utils::flags::has_flag("memoryfix")) - { - utils::hook::jump(0x6200C0_b, malloc); - utils::hook::jump(0x61FFE0_b, _aligned_malloc); - utils::hook::jump(0x620120_b, free); - utils::hook::jump(0x620210_b, realloc); - utils::hook::jump(0x620040_b, _aligned_realloc); - } - // Change default hostname and make it replicated dvars::override::register_string("sv_hostname", "^2H1-Mod^7 Default Server", game::DVAR_FLAG_REPLICATED); diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp index 25db1248..f5059e35 100644 --- a/src/client/component/server_list.cpp +++ b/src/client/component/server_list.cpp @@ -36,6 +36,7 @@ namespace server_list game::CodPlayMode play_mode; char in_game; game::netadr_s address; + bool is_private; }; struct @@ -156,6 +157,11 @@ namespace server_list return servers[i].game_type.empty() ? "" : utils::string::va("%i", servers[i].ping); } + if (column == 5) + { + return servers[i].is_private ? "1" : "0"; + } + return ""; } @@ -362,6 +368,7 @@ namespace server_list server.max_clients = atoi(info.get("sv_maxclients").data()); server.bots = atoi(info.get("bots").data()); server.ping = std::min(now - start_time, 999); + server.is_private = atoi(info.get("isPrivate").data()) == 1; server.in_game = 1; @@ -373,16 +380,22 @@ namespace server_list public: void post_unpack() override { - if (!game::environment::is_mp()) return; - - scheduler::once([]() + if (!game::environment::is_sp()) { - // add dvars to change destination master server ip/port - master_server_ip = dvars::register_string("masterServerIP", "master.h1.gg", game::DVAR_FLAG_NONE, - "IP of the destination master server to connect to"); - master_server_port = dvars::register_string("masterServerPort", "20810", game::DVAR_FLAG_NONE, - "Port of the destination master server to connect to"); - }, scheduler::pipeline::main); + scheduler::once([]() + { + // add dvars to change destination master server ip/port + master_server_ip = dvars::register_string("masterServerIP", "master.h1.gg", game::DVAR_FLAG_NONE, + "IP of the destination master server to connect to"); + master_server_port = dvars::register_string("masterServerPort", "20810", game::DVAR_FLAG_NONE, + "Port of the destination master server to connect to"); + }, scheduler::pipeline::main); + } + + if (!game::environment::is_mp()) + { + return; + } localized_strings::override("PLATFORM_SYSTEM_LINK_TITLE", "SERVER LIST"); diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index 0c03036f..ec6418c3 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -337,6 +337,11 @@ namespace ui_scripting }; } + game_type["virtuallobbypresentable"] = [](const game&) + { + ::game::Dvar_SetFromStringByNameFromSource("virtualLobbyPresentable", "1", ::game::DvarSetSource::DVAR_SOURCE_INTERNAL); + }; + auto updater_table = table(); lua["updater"] = updater_table; diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp index 44d2b611..ab2c748a 100644 --- a/src/client/component/updater.cpp +++ b/src/client/component/updater.cpp @@ -27,6 +27,7 @@ #define DATA_PATH_DEV "data-dev/" #define ERR_UPDATE_CHECK_FAIL "Failed to check for updates" +#define ERR_UPDATE_CHECK_FAIL_BAD_RESPONSE "Bad response" #define ERR_DOWNLOAD_FAIL "Failed to download file " #define ERR_WRITE_FAIL "Failed to write file " @@ -345,7 +346,7 @@ namespace updater if (!j.IsArray()) { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); + set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL_BAD_RESPONSE); return; } diff --git a/src/client/game/scripting/lua/context.cpp b/src/client/game/scripting/lua/context.cpp index 396b3837..42140a86 100644 --- a/src/client/game/scripting/lua/context.cpp +++ b/src/client/game/scripting/lua/context.cpp @@ -156,11 +156,6 @@ namespace scripting::lua return normalize_vector(a); }; - vector_type["normalize"] = [](const vector& a) - { - return normalize_vector(a); - }; - vector_type["toangles"] = [](const vector& a) { return call("vectortoangles", {a}).as(); diff --git a/src/client/resources/ui_scripts/updater.lua b/src/client/resources/ui_scripts/updater.lua index 90008700..fbb19d8b 100644 --- a/src/client/resources/ui_scripts/updater.lua +++ b/src/client/resources/ui_scripts/updater.lua @@ -12,11 +12,6 @@ function startupdatecheck(popup, autoclose) end if (not updater.getupdatecheckstatus()) then - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - return - end - popup.text:setText("Error: " .. updater.getlasterror()) return end @@ -71,11 +66,6 @@ function startupdatedownload(popup, autoclose) end if (not updater.getupdatedownloadstatus()) then - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - return - end - popup.text:setText("Error: " .. updater.getlasterror()) return end diff --git a/src/common/utils/vector.cpp b/src/common/utils/vector.cpp index aa0357ef..81f4eff2 100644 --- a/src/common/utils/vector.cpp +++ b/src/common/utils/vector.cpp @@ -46,6 +46,13 @@ namespace utils::vector out[1] = veca[1] - vecb[1]; out[2] = veca[2] - vecb[2]; } + + void add(const float* veca, const float* vecb, float* out) + { + out[0] = veca[0] + vecb[0]; + out[1] = veca[1] + vecb[1]; + out[2] = veca[2] + vecb[2]; + } float length(float* v) { diff --git a/src/common/utils/vector.hpp b/src/common/utils/vector.hpp index 6bf74ae1..5700c5a3 100644 --- a/src/common/utils/vector.hpp +++ b/src/common/utils/vector.hpp @@ -7,6 +7,7 @@ namespace utils::vector void scale(const float* in, float scale, float* out); void ma(const float* v1, float scale, const float* v2, float* out); void subtract(const float* veca, const float* vecb, float* out); + void add(const float* veca, const float* vecb, float* out); float length(float* v); float product(const float* v1, const float* v2); }