Use new format library and sort utils
This commit is contained in:
59
.gitmodules
vendored
59
.gitmodules
vendored
@ -1,28 +1,31 @@
|
|||||||
[submodule "deps/zlib"]
|
[submodule "deps/zlib"]
|
||||||
path = deps/zlib
|
path = deps/zlib
|
||||||
url = https://github.com/madler/zlib.git
|
url = https://github.com/madler/zlib.git
|
||||||
branch = master
|
branch = master
|
||||||
[submodule "deps/json11"]
|
[submodule "deps/json11"]
|
||||||
path = deps/json11
|
path = deps/json11
|
||||||
url = https://github.com/dropbox/json11.git
|
url = https://github.com/dropbox/json11.git
|
||||||
[submodule "deps/libtommath"]
|
[submodule "deps/libtommath"]
|
||||||
path = deps/libtommath
|
path = deps/libtommath
|
||||||
url = https://github.com/libtom/libtommath.git
|
url = https://github.com/libtom/libtommath.git
|
||||||
branch = develop
|
branch = develop
|
||||||
[submodule "deps/protobuf"]
|
[submodule "deps/protobuf"]
|
||||||
path = deps/protobuf
|
path = deps/protobuf
|
||||||
url = https://github.com/google/protobuf.git
|
url = https://github.com/google/protobuf.git
|
||||||
[submodule "deps/Wink-Signals"]
|
[submodule "deps/Wink-Signals"]
|
||||||
path = deps/Wink-Signals
|
path = deps/Wink-Signals
|
||||||
url = https://github.com/momo5502/Wink-Signals.git
|
url = https://github.com/momo5502/Wink-Signals.git
|
||||||
[submodule "deps/libtomcrypt"]
|
[submodule "deps/libtomcrypt"]
|
||||||
path = deps/libtomcrypt
|
path = deps/libtomcrypt
|
||||||
url = https://github.com/libtom/libtomcrypt.git
|
url = https://github.com/libtom/libtomcrypt.git
|
||||||
branch = develop
|
branch = develop
|
||||||
[submodule "deps/pdcurses"]
|
[submodule "deps/pdcurses"]
|
||||||
path = deps/pdcurses
|
path = deps/pdcurses
|
||||||
url = https://github.com/wmcbrine/PDCurses.git
|
url = https://github.com/wmcbrine/PDCurses.git
|
||||||
[submodule "deps/mongoose"]
|
[submodule "deps/mongoose"]
|
||||||
path = deps/mongoose
|
path = deps/mongoose
|
||||||
url = https://github.com/cesanta/mongoose.git
|
url = https://github.com/cesanta/mongoose.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
|
[submodule "deps/fmt"]
|
||||||
|
path = deps/fmt
|
||||||
|
url = https://github.com/fmtlib/fmt.git
|
||||||
|
1
deps/fmt
vendored
Submodule
1
deps/fmt
vendored
Submodule
Submodule deps/fmt added at 4133e501f3
2
deps/protobuf
vendored
2
deps/protobuf
vendored
Submodule deps/protobuf updated: 8779cba302...790e6afb72
802
premake5.lua
802
premake5.lua
@ -1,390 +1,412 @@
|
|||||||
-- Option to allow copying the DLL file to a custom folder after build
|
-- Option to allow copying the DLL file to a custom folder after build
|
||||||
newoption {
|
newoption {
|
||||||
trigger = "copy-to",
|
trigger = "copy-to",
|
||||||
description = "Optional, copy the DLL to a custom folder after build, define the path here if wanted.",
|
description = "Optional, copy the DLL to a custom folder after build, define the path here if wanted.",
|
||||||
value = "PATH"
|
value = "PATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
newoption {
|
newoption {
|
||||||
trigger = "no-new-structure",
|
trigger = "no-new-structure",
|
||||||
description = "Do not use new virtual path structure (separating headers and source files)."
|
description = "Do not use new virtual path structure (separating headers and source files)."
|
||||||
}
|
}
|
||||||
|
|
||||||
newaction {
|
newaction {
|
||||||
trigger = "version",
|
trigger = "version",
|
||||||
description = "Returns the version string for the current commit of the source code.",
|
description = "Returns the version string for the current commit of the source code.",
|
||||||
onWorkspace = function(wks)
|
onWorkspace = function(wks)
|
||||||
-- get revision number via git
|
-- get revision number via git
|
||||||
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
||||||
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
proc:close()
|
proc:close()
|
||||||
|
|
||||||
print(revNumber)
|
print(revNumber)
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
newaction {
|
newaction {
|
||||||
trigger = "generate-buildinfo",
|
trigger = "generate-buildinfo",
|
||||||
description = "Sets up build information file like version.h.",
|
description = "Sets up build information file like version.h.",
|
||||||
onWorkspace = function(wks)
|
onWorkspace = function(wks)
|
||||||
-- get revision number via git
|
-- get revision number via git
|
||||||
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
||||||
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
proc:close()
|
proc:close()
|
||||||
|
|
||||||
-- get whether this is a clean revision (no uncommitted changes)
|
-- get whether this is a clean revision (no uncommitted changes)
|
||||||
local proc = assert(io.popen("git status --porcelain", "r"))
|
local proc = assert(io.popen("git status --porcelain", "r"))
|
||||||
local revClean = 1
|
local revClean = 1
|
||||||
local revCleanSuffix = ""
|
local revCleanSuffix = ""
|
||||||
if assert(proc:read('*a')) ~= "" then
|
if assert(proc:read('*a')) ~= "" then
|
||||||
revClean = 0
|
revClean = 0
|
||||||
revCleanSuffix = " (unclean)"
|
revCleanSuffix = " (unclean)"
|
||||||
end
|
end
|
||||||
proc:close()
|
proc:close()
|
||||||
|
|
||||||
-- get old version number from version.hpp if any
|
-- get old version number from version.hpp if any
|
||||||
local oldRevNumber = "(none)"
|
local oldRevNumber = "(none)"
|
||||||
local oldRevClean = 1
|
local oldRevClean = 1
|
||||||
local oldRevCleanSuffix = ""
|
local oldRevCleanSuffix = ""
|
||||||
local oldVersionHeader = io.open(wks.location .. "/src/version.hpp", "r")
|
local oldVersionHeader = io.open(wks.location .. "/src/version.hpp", "r")
|
||||||
if oldVersionHeader ~=nil then
|
if oldVersionHeader ~=nil then
|
||||||
local oldVersionHeaderContent = assert(oldVersionHeader:read('*a'))
|
local oldVersionHeaderContent = assert(oldVersionHeader:read('*a'))
|
||||||
oldRevNumber = string.match(oldVersionHeaderContent, "#define REVISION (%d+)")
|
oldRevNumber = string.match(oldVersionHeaderContent, "#define REVISION (%d+)")
|
||||||
if oldRevNumber == nil then
|
if oldRevNumber == nil then
|
||||||
-- old version.hpp format?
|
-- old version.hpp format?
|
||||||
oldRevNumber = "(none)"
|
oldRevNumber = "(none)"
|
||||||
end
|
end
|
||||||
oldRevClean = string.match(oldVersionHeaderContent, "#define REVISION_CLEAN (%d+)")
|
oldRevClean = string.match(oldVersionHeaderContent, "#define REVISION_CLEAN (%d+)")
|
||||||
if oldRevClean == nil then
|
if oldRevClean == nil then
|
||||||
-- old version.hpp format?
|
-- old version.hpp format?
|
||||||
oldRevClean = 1
|
oldRevClean = 1
|
||||||
elseif oldRevClean ~= "1" then
|
elseif oldRevClean ~= "1" then
|
||||||
oldRevClean = 0
|
oldRevClean = 0
|
||||||
else
|
else
|
||||||
oldRevClean = 1
|
oldRevClean = 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if oldRevClean == 0 then
|
if oldRevClean == 0 then
|
||||||
oldRevCleanSuffix = " (unclean)"
|
oldRevCleanSuffix = " (unclean)"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate version.hpp with a revision number if not equal
|
-- generate version.hpp with a revision number if not equal
|
||||||
if oldRevNumber ~= revNumber or oldRevClean ~= revClean then
|
if oldRevNumber ~= revNumber or oldRevClean ~= revClean then
|
||||||
print ("Update " .. oldRevNumber .. oldRevCleanSuffix .. " -> " .. revNumber .. revCleanSuffix)
|
print ("Update " .. oldRevNumber .. oldRevCleanSuffix .. " -> " .. revNumber .. revCleanSuffix)
|
||||||
local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
|
local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
|
||||||
versionHeader:write("/*\n")
|
versionHeader:write("/*\n")
|
||||||
versionHeader:write(" * Automatically generated by premake5.\n")
|
versionHeader:write(" * Automatically generated by premake5.\n")
|
||||||
versionHeader:write(" * Do not touch, you fucking moron!\n")
|
versionHeader:write(" * Do not touch, you fucking moron!\n")
|
||||||
versionHeader:write(" */\n")
|
versionHeader:write(" */\n")
|
||||||
versionHeader:write("\n")
|
versionHeader:write("\n")
|
||||||
versionHeader:write("#define REVISION " .. revNumber .. "\n")
|
versionHeader:write("#define REVISION " .. revNumber .. "\n")
|
||||||
versionHeader:write("#define REVISION_CLEAN " .. revClean .. "\n")
|
versionHeader:write("#define REVISION_CLEAN " .. revClean .. "\n")
|
||||||
versionHeader:close()
|
versionHeader:close()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace "iw4x"
|
workspace "iw4x"
|
||||||
location "./build"
|
location "./build"
|
||||||
objdir "%{wks.location}/obj"
|
objdir "%{wks.location}/obj"
|
||||||
targetdir "%{wks.location}/bin/%{cfg.buildcfg}"
|
targetdir "%{wks.location}/bin/%{cfg.buildcfg}"
|
||||||
configurations { "Debug", "DebugStatic", "Release", "ReleaseStatic" }
|
configurations { "Debug", "DebugStatic", "Release", "ReleaseStatic" }
|
||||||
architecture "x32"
|
architecture "x32"
|
||||||
platforms "x86"
|
platforms "x86"
|
||||||
|
|
||||||
-- VS 2015 toolset only
|
-- VS 2015 toolset only
|
||||||
toolset "msc-140"
|
toolset "msc-140"
|
||||||
|
|
||||||
configuration "windows"
|
configuration "windows"
|
||||||
defines { "_WINDOWS", "WIN32" }
|
defines { "_WINDOWS", "WIN32" }
|
||||||
|
|
||||||
configuration "Release*"
|
configuration "Release*"
|
||||||
defines { "NDEBUG" }
|
defines { "NDEBUG" }
|
||||||
flags { "MultiProcessorCompile", "Symbols", "LinkTimeOptimization", "No64BitChecks" }
|
flags { "MultiProcessorCompile", "Symbols", "LinkTimeOptimization", "No64BitChecks" }
|
||||||
optimize "Full"
|
optimize "Full"
|
||||||
|
|
||||||
configuration "Debug*"
|
configuration "Debug*"
|
||||||
defines { "DEBUG", "_DEBUG" }
|
defines { "DEBUG", "_DEBUG" }
|
||||||
flags { "MultiProcessorCompile", "Symbols", "No64BitChecks" }
|
flags { "MultiProcessorCompile", "Symbols", "No64BitChecks" }
|
||||||
optimize "Debug"
|
optimize "Debug"
|
||||||
|
|
||||||
configuration "*Static"
|
configuration "*Static"
|
||||||
flags { "StaticRuntime" }
|
flags { "StaticRuntime" }
|
||||||
|
|
||||||
project "iw4x"
|
project "iw4x"
|
||||||
kind "SharedLib"
|
kind "SharedLib"
|
||||||
language "C++"
|
language "C++"
|
||||||
files {
|
files {
|
||||||
"./src/**.rc",
|
"./src/**.rc",
|
||||||
"./src/**.hpp",
|
"./src/**.hpp",
|
||||||
"./src/**.cpp",
|
"./src/**.cpp",
|
||||||
"./src/**.proto",
|
"./src/**.proto",
|
||||||
}
|
}
|
||||||
includedirs {
|
includedirs {
|
||||||
"%{prj.location}/src",
|
"%{prj.location}/src",
|
||||||
"./src"
|
"./src"
|
||||||
}
|
}
|
||||||
resincludedirs {
|
resincludedirs {
|
||||||
"$(ProjectDir)src" -- fix for VS IDE
|
"$(ProjectDir)src" -- fix for VS IDE
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Pre-compiled header
|
-- Pre-compiled header
|
||||||
pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives
|
pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives
|
||||||
pchsource "src/STDInclude.cpp" -- real path
|
pchsource "src/STDInclude.cpp" -- real path
|
||||||
buildoptions { "/Zm200" }
|
buildoptions { "/Zm200" }
|
||||||
filter "files:**.pb.*"
|
filter "files:**.pb.*"
|
||||||
flags {
|
flags {
|
||||||
"NoPCH",
|
"NoPCH",
|
||||||
}
|
}
|
||||||
buildoptions {
|
buildoptions {
|
||||||
"/wd4100", -- "Unused formal parameter"
|
"/wd4100", -- "Unused formal parameter"
|
||||||
"/wd4389", -- "Signed/Unsigned mismatch"
|
"/wd4389", -- "Signed/Unsigned mismatch"
|
||||||
"/wd6011", -- "Dereferencing NULL pointer"
|
"/wd6011", -- "Dereferencing NULL pointer"
|
||||||
"/wd4125", -- "Decimal digit terminates octal escape sequence"
|
"/wd4125", -- "Decimal digit terminates octal escape sequence"
|
||||||
}
|
}
|
||||||
defines {
|
defines {
|
||||||
"_SCL_SECURE_NO_WARNINGS",
|
"_SCL_SECURE_NO_WARNINGS",
|
||||||
}
|
}
|
||||||
filter {}
|
filter {}
|
||||||
|
|
||||||
-- Dependency libraries
|
-- Dependency libraries
|
||||||
links { "zlib", "json11", "pdcurses", "libtomcrypt", "libtommath", "protobuf", "mongoose" }
|
links { "zlib", "fmt", "json11", "pdcurses", "libtomcrypt", "libtommath", "protobuf", "mongoose" }
|
||||||
includedirs
|
includedirs
|
||||||
{
|
{
|
||||||
"./deps/zlib",
|
"./deps/fmt",
|
||||||
"./deps/json11",
|
"./deps/zlib",
|
||||||
"./deps/pdcurses",
|
"./deps/json11",
|
||||||
"./deps/mongoose",
|
"./deps/pdcurses",
|
||||||
"./deps/libtomcrypt/src/headers",
|
"./deps/mongoose",
|
||||||
"./deps/libtommath",
|
"./deps/libtomcrypt/src/headers",
|
||||||
"./deps/protobuf/src",
|
"./deps/libtommath",
|
||||||
"./deps/Wink-Signals",
|
"./deps/protobuf/src",
|
||||||
}
|
"./deps/Wink-Signals",
|
||||||
|
}
|
||||||
-- fix vpaths for protobuf sources
|
|
||||||
vpaths {
|
-- fix vpaths for protobuf sources
|
||||||
["*"] = { "./src/**" },
|
vpaths
|
||||||
["Proto/Generated"] = { "**.pb.*" }, -- meh.
|
{
|
||||||
}
|
["*"] = { "./src/**" },
|
||||||
|
["Proto/Generated"] = { "**.pb.*" }, -- meh.
|
||||||
-- Virtual paths
|
}
|
||||||
if not _OPTIONS["no-new-structure"] then
|
|
||||||
vpaths {
|
-- Virtual paths
|
||||||
["Headers/*"] = { "./src/**.hpp" },
|
if not _OPTIONS["no-new-structure"] then
|
||||||
["Sources/*"] = { "./src/**.cpp" },
|
vpaths
|
||||||
["Resource/*"] = { "./src/**.rc" },
|
{
|
||||||
["Proto/Definitions/*"] = { "./src/Proto/**.proto" },
|
["Headers/*"] = { "./src/**.hpp" },
|
||||||
["Proto/Generated/*"] = { "**.pb.*" }, -- meh.
|
["Sources/*"] = { "./src/**.cpp" },
|
||||||
}
|
["Resource/*"] = { "./src/**.rc" },
|
||||||
end
|
["Proto/Definitions/*"] = { "./src/Proto/**.proto" },
|
||||||
|
["Proto/Generated/*"] = { "**.pb.*" }, -- meh.
|
||||||
vpaths {
|
}
|
||||||
["Docs/*"] = { "**.txt","**.md" },
|
end
|
||||||
}
|
|
||||||
|
vpaths {
|
||||||
-- Pre-build
|
["Docs/*"] = { "**.txt","**.md" },
|
||||||
prebuildcommands {
|
}
|
||||||
"cd %{_MAIN_SCRIPT_DIR}",
|
|
||||||
"tools\\premake5 generate-buildinfo"
|
-- Pre-build
|
||||||
}
|
prebuildcommands
|
||||||
|
{
|
||||||
-- Post-build
|
"cd %{_MAIN_SCRIPT_DIR}",
|
||||||
if _OPTIONS["copy-to"] then
|
"tools\\premake5 generate-buildinfo"
|
||||||
saneCopyToPath = string.gsub(_OPTIONS["copy-to"] .. "\\", "\\\\", "\\")
|
}
|
||||||
postbuildcommands {
|
|
||||||
"copy /y \"$(TargetDir)*.dll\" \"" .. saneCopyToPath .. "\""
|
-- Post-build
|
||||||
}
|
if _OPTIONS["copy-to"] then
|
||||||
end
|
saneCopyToPath = string.gsub(_OPTIONS["copy-to"] .. "\\", "\\\\", "\\")
|
||||||
|
postbuildcommands {
|
||||||
-- Specific configurations
|
"copy /y \"$(TargetDir)*.dll\" \"" .. saneCopyToPath .. "\""
|
||||||
flags { "UndefinedIdentifiers", "ExtraWarnings" }
|
}
|
||||||
|
end
|
||||||
configuration "Release*"
|
|
||||||
flags { "FatalCompileWarnings" }
|
-- Specific configurations
|
||||||
configuration {}
|
flags { "UndefinedIdentifiers", "ExtraWarnings" }
|
||||||
|
|
||||||
-- Generate source code from protobuf definitions
|
configuration "Release*"
|
||||||
rules { "ProtobufCompiler" }
|
flags { "FatalCompileWarnings" }
|
||||||
|
configuration {}
|
||||||
-- Workaround: Consume protobuf generated source files
|
|
||||||
matches = os.matchfiles(path.join("src/Proto/**.proto"))
|
-- Generate source code from protobuf definitions
|
||||||
for i, srcPath in ipairs(matches) do
|
rules { "ProtobufCompiler" }
|
||||||
basename = path.getbasename(srcPath)
|
|
||||||
files {
|
-- Workaround: Consume protobuf generated source files
|
||||||
string.format("%%{prj.location}/src/proto/%s.pb.h", basename),
|
matches = os.matchfiles(path.join("src/Proto/**.proto"))
|
||||||
string.format("%%{prj.location}/src/proto/%s.pb.cc", basename),
|
for i, srcPath in ipairs(matches) do
|
||||||
}
|
basename = path.getbasename(srcPath)
|
||||||
end
|
files
|
||||||
includedirs {
|
{
|
||||||
"%{prj.location}/src/proto"
|
string.format("%%{prj.location}/src/proto/%s.pb.h", basename),
|
||||||
}
|
string.format("%%{prj.location}/src/proto/%s.pb.cc", basename),
|
||||||
|
}
|
||||||
group "External dependencies"
|
end
|
||||||
|
includedirs {
|
||||||
-- zlib
|
"%{prj.location}/src/proto"
|
||||||
project "zlib"
|
}
|
||||||
language "C"
|
|
||||||
defines { "ZLIB_DLL", "_CRT_SECURE_NO_DEPRECATE" }
|
group "External dependencies"
|
||||||
|
|
||||||
files
|
-- zlib
|
||||||
{
|
project "zlib"
|
||||||
"./deps/zlib/*.h",
|
language "C"
|
||||||
"./deps/zlib/*.c"
|
defines { "ZLIB_DLL", "_CRT_SECURE_NO_DEPRECATE" }
|
||||||
}
|
|
||||||
|
files
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
{
|
||||||
warnings "Off"
|
"./deps/zlib/*.h",
|
||||||
|
"./deps/zlib/*.c"
|
||||||
kind "SharedLib"
|
}
|
||||||
configuration "*Static"
|
|
||||||
kind "StaticLib"
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
removedefines { "ZLIB_DLL" }
|
warnings "Off"
|
||||||
|
|
||||||
-- json11
|
kind "SharedLib"
|
||||||
project "json11"
|
configuration "*Static"
|
||||||
language "C++"
|
kind "StaticLib"
|
||||||
|
removedefines { "ZLIB_DLL" }
|
||||||
files
|
|
||||||
{
|
-- json11
|
||||||
"./deps/json11/*.cpp",
|
project "json11"
|
||||||
"./deps/json11/*.hpp"
|
language "C++"
|
||||||
}
|
|
||||||
|
files
|
||||||
-- remove dropbox's testing code
|
{
|
||||||
removefiles { "./deps/json11/test.cpp" }
|
"./deps/json11/*.cpp",
|
||||||
|
"./deps/json11/*.hpp"
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
}
|
||||||
warnings "Off"
|
|
||||||
|
-- remove dropbox's testing code
|
||||||
-- always build as static lib, as json11 doesn't export anything
|
removefiles { "./deps/json11/test.cpp" }
|
||||||
kind "StaticLib"
|
|
||||||
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
-- mongoose
|
warnings "Off"
|
||||||
project "mongoose"
|
|
||||||
language "C"
|
-- always build as static lib, as json11 doesn't export anything
|
||||||
|
kind "StaticLib"
|
||||||
files
|
|
||||||
{
|
-- fmt
|
||||||
"./deps/mongoose/*.c",
|
project "fmt"
|
||||||
"./deps/mongoose/*.h"
|
language "C++"
|
||||||
}
|
|
||||||
|
includedirs { "./deps/fmt" }
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
files
|
||||||
warnings "Off"
|
{
|
||||||
|
"./deps/fmt/fmt/*.cc",
|
||||||
-- always build as static lib, as json11 doesn't export anything
|
"./deps/fmt/fmt/*.h"
|
||||||
kind "StaticLib"
|
}
|
||||||
|
|
||||||
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
-- pdcurses
|
warnings "Off"
|
||||||
project "pdcurses"
|
|
||||||
language "C"
|
-- always build as static lib, as fmt doesn't export anything
|
||||||
includedirs { "./deps/pdcurses/" }
|
kind "StaticLib"
|
||||||
|
|
||||||
files
|
-- mongoose
|
||||||
{
|
project "mongoose"
|
||||||
"./deps/pdcurses/pdcurses/*.c",
|
language "C"
|
||||||
"./deps/pdcurses/win32/*.c"
|
|
||||||
}
|
files
|
||||||
|
{
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
"./deps/mongoose/*.c",
|
||||||
warnings "Off"
|
"./deps/mongoose/*.h"
|
||||||
|
}
|
||||||
-- always build as static lib, as pdcurses doesn't export anything
|
|
||||||
kind "StaticLib"
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
|
warnings "Off"
|
||||||
-- libtomcrypt
|
|
||||||
project "libtomcrypt"
|
-- always build as static lib, as mongoose doesn't export anything
|
||||||
language "C"
|
kind "StaticLib"
|
||||||
defines { "_LIB", "LTC_SOURCE", "LTC_NO_FAST", "LTC_NO_RSA_BLINDING", "LTM_DESC", "USE_LTM", "WIN32" }
|
|
||||||
|
|
||||||
links { "libtommath" }
|
-- pdcurses
|
||||||
includedirs { "./deps/libtomcrypt/src/headers" }
|
project "pdcurses"
|
||||||
includedirs { "./deps/libtommath" }
|
language "C"
|
||||||
|
includedirs { "./deps/pdcurses/" }
|
||||||
files { "./deps/libtomcrypt/src/**.c" }
|
|
||||||
|
files
|
||||||
-- seems like tab stuff can be omitted
|
{
|
||||||
removefiles { "./deps/libtomcrypt/src/**/*tab.c" }
|
"./deps/pdcurses/pdcurses/*.c",
|
||||||
|
"./deps/pdcurses/win32/*.c"
|
||||||
-- remove incorrect files
|
}
|
||||||
-- for some reason, they lack the necessary header files
|
|
||||||
-- i might have to open a pull request which includes them
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
removefiles
|
warnings "Off"
|
||||||
{
|
|
||||||
"./deps/libtomcrypt/src/pk/dh/dh_sys.c",
|
-- always build as static lib, as pdcurses doesn't export anything
|
||||||
"./deps/libtomcrypt/src/hashes/sha2/sha224.c",
|
kind "StaticLib"
|
||||||
"./deps/libtomcrypt/src/hashes/sha2/sha384.c",
|
|
||||||
"./deps/libtomcrypt/src/encauth/ocb3/**.c",
|
-- libtomcrypt
|
||||||
}
|
project "libtomcrypt"
|
||||||
|
language "C"
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
defines { "_LIB", "LTC_SOURCE", "LTC_NO_FAST", "LTC_NO_RSA_BLINDING", "LTM_DESC", "USE_LTM", "WIN32" }
|
||||||
warnings "Off"
|
|
||||||
|
links { "libtommath" }
|
||||||
-- always build as static lib, as libtomcrypt doesn't export anything
|
includedirs { "./deps/libtomcrypt/src/headers" }
|
||||||
kind "StaticLib"
|
includedirs { "./deps/libtommath" }
|
||||||
|
|
||||||
-- libtommath
|
files { "./deps/libtomcrypt/src/**.c" }
|
||||||
project "libtommath"
|
|
||||||
language "C"
|
-- seems like tab stuff can be omitted
|
||||||
defines { "_LIB" }
|
removefiles { "./deps/libtomcrypt/src/**/*tab.c" }
|
||||||
includedirs { "./deps/libtommath" }
|
|
||||||
|
-- remove incorrect files
|
||||||
files { "./deps/libtommath/*.c" }
|
-- for some reason, they lack the necessary header files
|
||||||
|
-- i might have to open a pull request which includes them
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
removefiles
|
||||||
warnings "Off"
|
{
|
||||||
|
"./deps/libtomcrypt/src/pk/dh/dh_sys.c",
|
||||||
-- always build as static lib, as libtommath doesn't export anything
|
"./deps/libtomcrypt/src/hashes/sha2/sha224.c",
|
||||||
kind "StaticLib"
|
"./deps/libtomcrypt/src/hashes/sha2/sha384.c",
|
||||||
|
"./deps/libtomcrypt/src/encauth/ocb3/**.c",
|
||||||
-- protobuf
|
}
|
||||||
project "protobuf"
|
|
||||||
language "C++"
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
links { "zlib" }
|
warnings "Off"
|
||||||
defines { "_SCL_SECURE_NO_WARNINGS" }
|
|
||||||
includedirs
|
-- always build as static lib, as libtomcrypt doesn't export anything
|
||||||
{
|
kind "StaticLib"
|
||||||
"./deps/zlib",
|
|
||||||
"./deps/protobuf/src",
|
-- libtommath
|
||||||
}
|
project "libtommath"
|
||||||
|
language "C"
|
||||||
-- default protobuf sources
|
defines { "_LIB" }
|
||||||
files { "./deps/protobuf/src/**.cc" }
|
includedirs { "./deps/libtommath" }
|
||||||
|
|
||||||
-- remove unnecessary sources
|
files { "./deps/libtommath/*.c" }
|
||||||
removefiles
|
|
||||||
{
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
"./deps/protobuf/src/**/*test.cc",
|
warnings "Off"
|
||||||
"./deps/protobuf/src/google/protobuf/*test*.cc",
|
|
||||||
|
-- always build as static lib, as libtommath doesn't export anything
|
||||||
"./deps/protobuf/src/google/protobuf/testing/**.cc",
|
kind "StaticLib"
|
||||||
"./deps/protobuf/src/google/protobuf/compiler/**.cc",
|
|
||||||
|
-- protobuf
|
||||||
"./deps/protobuf/src/google/protobuf/arena_nc.cc",
|
project "protobuf"
|
||||||
"./deps/protobuf/src/google/protobuf/util/internal/error_listener.cc",
|
language "C++"
|
||||||
"./deps/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
|
links { "zlib" }
|
||||||
}
|
defines { "_SCL_SECURE_NO_WARNINGS" }
|
||||||
|
includedirs
|
||||||
-- not our code, ignore POSIX usage warnings for now
|
{
|
||||||
warnings "Off"
|
"./deps/zlib",
|
||||||
|
"./deps/protobuf/src",
|
||||||
-- always build as static lib, as we include our custom classes and therefore can't perform shared linking
|
}
|
||||||
kind "StaticLib"
|
|
||||||
|
-- default protobuf sources
|
||||||
rule "ProtobufCompiler"
|
files { "./deps/protobuf/src/**.cc" }
|
||||||
display "Protobuf compiler"
|
|
||||||
location "./build"
|
-- remove unnecessary sources
|
||||||
fileExtension ".proto"
|
removefiles
|
||||||
buildmessage "Compiling %(Identity) with protoc..."
|
{
|
||||||
buildcommands {
|
"./deps/protobuf/src/**/*test.cc",
|
||||||
'@echo off',
|
"./deps/protobuf/src/google/protobuf/*test*.cc",
|
||||||
'path "$(SolutionDir)\\..\\tools"',
|
|
||||||
'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"',
|
"./deps/protobuf/src/google/protobuf/testing/**.cc",
|
||||||
'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)',
|
"./deps/protobuf/src/google/protobuf/compiler/**.cc",
|
||||||
}
|
|
||||||
buildoutputs {
|
"./deps/protobuf/src/google/protobuf/arena_nc.cc",
|
||||||
'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc',
|
"./deps/protobuf/src/google/protobuf/util/internal/error_listener.cc",
|
||||||
'$(ProjectDir)\\src\\proto\\%(Filename).pb.h',
|
"./deps/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- not our code, ignore POSIX usage warnings for now
|
||||||
|
warnings "Off"
|
||||||
|
|
||||||
|
-- always build as static lib, as we include our custom classes and therefore can't perform shared linking
|
||||||
|
kind "StaticLib"
|
||||||
|
|
||||||
|
rule "ProtobufCompiler"
|
||||||
|
display "Protobuf compiler"
|
||||||
|
location "./build"
|
||||||
|
fileExtension ".proto"
|
||||||
|
buildmessage "Compiling %(Identity) with protoc..."
|
||||||
|
buildcommands {
|
||||||
|
'@echo off',
|
||||||
|
'path "$(SolutionDir)\\..\\tools"',
|
||||||
|
'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"',
|
||||||
|
'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)',
|
||||||
|
}
|
||||||
|
buildoutputs {
|
||||||
|
'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc',
|
||||||
|
'$(ProjectDir)\\src\\proto\\%(Filename).pb.h',
|
||||||
|
}
|
||||||
|
@ -1,233 +1,233 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
int AntiCheat::LastCheck;
|
int AntiCheat::LastCheck;
|
||||||
std::string AntiCheat::Hash;
|
std::string AntiCheat::Hash;
|
||||||
Utils::Hook AntiCheat::LoadLibHook[4];
|
Utils::Hook AntiCheat::LoadLibHook[4];
|
||||||
Utils::Hook AntiCheat::VirtualProtectHook;
|
Utils::Hook AntiCheat::VirtualProtectHook;
|
||||||
|
|
||||||
// This function does nothing, it only adds the two passed variables and returns the value
|
// This function does nothing, it only adds the two passed variables and returns the value
|
||||||
// The only important thing it does is to clean the first parameter, and then return
|
// The only important thing it does is to clean the first parameter, and then return
|
||||||
// By returning, the crash procedure will be called, as it hasn't been cleaned from the stack
|
// By returning, the crash procedure will be called, as it hasn't been cleaned from the stack
|
||||||
void __declspec(naked) AntiCheat::NullSub()
|
void __declspec(naked) AntiCheat::NullSub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push ebp
|
push ebp
|
||||||
push ecx
|
push ecx
|
||||||
mov ebp, esp
|
mov ebp, esp
|
||||||
|
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov eax, [ebp + 8h]
|
mov eax, [ebp + 8h]
|
||||||
mov ecx, [ebp + 0Ch]
|
mov ecx, [ebp + 0Ch]
|
||||||
add eax, ecx
|
add eax, ecx
|
||||||
|
|
||||||
pop ecx
|
pop ecx
|
||||||
pop ebp
|
pop ebp
|
||||||
retn 4
|
retn 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) AntiCheat::CrashClient()
|
void __declspec(naked) AntiCheat::CrashClient()
|
||||||
{
|
{
|
||||||
static uint8_t crashProcedure[] =
|
static uint8_t crashProcedure[] =
|
||||||
{
|
{
|
||||||
// Variable space
|
// Variable space
|
||||||
0xDC, 0xC1, 0xDC, 0x05,
|
0xDC, 0xC1, 0xDC, 0x05,
|
||||||
|
|
||||||
// Uninstall minidump handler
|
// Uninstall minidump handler
|
||||||
// This doesn't work anymore, due to the SetUnhandledExceptionFilter hook, but that's not important
|
// This doesn't work anymore, due to the SetUnhandledExceptionFilter hook, but that's not important
|
||||||
//0xB8, 0x63, 0xE7, 0x2F, 0x00, // mov eax, 2FE763h
|
//0xB8, 0x63, 0xE7, 0x2F, 0x00, // mov eax, 2FE763h
|
||||||
//0x05, 0xAD, 0xAD, 0x3C, 0x00, // add eax, 3CADADh
|
//0x05, 0xAD, 0xAD, 0x3C, 0x00, // add eax, 3CADADh
|
||||||
//0x6A, 0x58, // push 88
|
//0x6A, 0x58, // push 88
|
||||||
//0x8B, 0x80, 0xEA, 0x01, 0x00, 0x00, // mov eax, [eax + 1EAh]
|
//0x8B, 0x80, 0xEA, 0x01, 0x00, 0x00, // mov eax, [eax + 1EAh]
|
||||||
//0xFF, 0x10, // call dword ptr [eax]
|
//0xFF, 0x10, // call dword ptr [eax]
|
||||||
|
|
||||||
// Crash me.
|
// Crash me.
|
||||||
0xB8, 0x4F, 0x91, 0x27, 0x00, // mov eax, 27914Fh
|
0xB8, 0x4F, 0x91, 0x27, 0x00, // mov eax, 27914Fh
|
||||||
0x05, 0xDD, 0x28, 0x1A, 0x00, // add eax, 1A28DDh
|
0x05, 0xDD, 0x28, 0x1A, 0x00, // add eax, 1A28DDh
|
||||||
0x80, 0x00, 0x68, // add byte ptr [eax], 68h
|
0x80, 0x00, 0x68, // add byte ptr [eax], 68h
|
||||||
0xC3, // retn
|
0xC3, // retn
|
||||||
|
|
||||||
// Random stuff
|
// Random stuff
|
||||||
0xBE, 0xFF, 0xC2, 0xF4, 0x3A,
|
0xBE, 0xFF, 0xC2, 0xF4, 0x3A,
|
||||||
};
|
};
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
// This does absolutely nothing :P
|
// This does absolutely nothing :P
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov ebx, [esp + 4h]
|
mov ebx, [esp + 4h]
|
||||||
shl ebx, 4h
|
shl ebx, 4h
|
||||||
setz bl
|
setz bl
|
||||||
|
|
||||||
// Push the fake var onto the stack
|
// Push the fake var onto the stack
|
||||||
push ebx
|
push ebx
|
||||||
|
|
||||||
// Save the address to our crash procedure
|
// Save the address to our crash procedure
|
||||||
mov eax, offset crashProcedure
|
mov eax, offset crashProcedure
|
||||||
push eax
|
push eax
|
||||||
|
|
||||||
// Unprotect the .text segment
|
// Unprotect the .text segment
|
||||||
push eax
|
push eax
|
||||||
push 40h
|
push 40h
|
||||||
push 2D5FFFh
|
push 2D5FFFh
|
||||||
push 401001h
|
push 401001h
|
||||||
call VirtualProtect
|
call VirtualProtect
|
||||||
|
|
||||||
// Increment to our crash procedure
|
// Increment to our crash procedure
|
||||||
// Skip variable space
|
// Skip variable space
|
||||||
add dword ptr [esp], 4h
|
add dword ptr [esp], 4h
|
||||||
|
|
||||||
// This basically removes the pushed ebx value from the stack, so returning results in a call to the procedure
|
// This basically removes the pushed ebx value from the stack, so returning results in a call to the procedure
|
||||||
jmp AntiCheat::NullSub
|
jmp AntiCheat::NullSub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This has to be called when doing .text changes during runtime
|
// This has to be called when doing .text changes during runtime
|
||||||
void AntiCheat::EmptyHash()
|
void AntiCheat::EmptyHash()
|
||||||
{
|
{
|
||||||
AntiCheat::LastCheck = 0;
|
AntiCheat::LastCheck = 0;
|
||||||
AntiCheat::Hash.clear();
|
AntiCheat::Hash.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::InitLoadLibHook()
|
void AntiCheat::InitLoadLibHook()
|
||||||
{
|
{
|
||||||
static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h
|
static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h
|
||||||
static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch
|
static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch
|
||||||
|
|
||||||
static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll
|
static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll
|
||||||
static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA
|
static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA
|
||||||
static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW
|
static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW
|
||||||
|
|
||||||
HMODULE kernel32 = GetModuleHandleA(Utils::XORString(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data());
|
HMODULE kernel32 = GetModuleHandleA(Utils::String::XORString(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data());
|
||||||
FARPROC loadLibA = GetProcAddress(kernel32, Utils::XORString(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1).data());
|
FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XORString(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1).data());
|
||||||
FARPROC loadLibW = GetProcAddress(kernel32, Utils::XORString(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1).data());
|
FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XORString(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1).data());
|
||||||
|
|
||||||
AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP);
|
AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP);
|
||||||
AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP);
|
AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP);
|
||||||
//AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP);
|
//AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP);
|
||||||
//AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP);
|
//AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::PerformCheck()
|
void AntiCheat::PerformCheck()
|
||||||
{
|
{
|
||||||
// Hash .text segment
|
// Hash .text segment
|
||||||
// Add 1 to each value, so searching in memory doesn't reveal anything
|
// Add 1 to each value, so searching in memory doesn't reveal anything
|
||||||
size_t textSize = 0x2D6001;
|
size_t textSize = 0x2D6001;
|
||||||
uint8_t* textBase = reinterpret_cast<uint8_t*>(0x401001);
|
uint8_t* textBase = reinterpret_cast<uint8_t*>(0x401001);
|
||||||
std::string hash = Utils::Cryptography::SHA512::Compute(textBase - 1, textSize - 1, false);
|
std::string hash = Utils::Cryptography::SHA512::Compute(textBase - 1, textSize - 1, false);
|
||||||
|
|
||||||
// Set the hash, if none is set
|
// Set the hash, if none is set
|
||||||
if (AntiCheat::Hash.empty())
|
if (AntiCheat::Hash.empty())
|
||||||
{
|
{
|
||||||
AntiCheat::Hash = hash;
|
AntiCheat::Hash = hash;
|
||||||
}
|
}
|
||||||
// Crash if the hashes don't match
|
// Crash if the hashes don't match
|
||||||
else if (AntiCheat::Hash != hash)
|
else if (AntiCheat::Hash != hash)
|
||||||
{
|
{
|
||||||
AntiCheat::CrashClient();
|
AntiCheat::CrashClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::Frame()
|
void AntiCheat::Frame()
|
||||||
{
|
{
|
||||||
// Perform check only every 30 seconds
|
// Perform check only every 30 seconds
|
||||||
if (AntiCheat::LastCheck && (Game::Sys_Milliseconds() - AntiCheat::LastCheck) < 1000 * 30) return;
|
if (AntiCheat::LastCheck && (Game::Sys_Milliseconds() - AntiCheat::LastCheck) < 1000 * 30) return;
|
||||||
AntiCheat::LastCheck = Game::Sys_Milliseconds();
|
AntiCheat::LastCheck = Game::Sys_Milliseconds();
|
||||||
|
|
||||||
AntiCheat::PerformCheck();
|
AntiCheat::PerformCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::UninstallLibHook()
|
void AntiCheat::UninstallLibHook()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
||||||
{
|
{
|
||||||
AntiCheat::LoadLibHook[i].Uninstall();
|
AntiCheat::LoadLibHook[i].Uninstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::InstallLibHook()
|
void AntiCheat::InstallLibHook()
|
||||||
{
|
{
|
||||||
AntiCheat::LoadLibHook[0].Install();
|
AntiCheat::LoadLibHook[0].Install();
|
||||||
AntiCheat::LoadLibHook[1].Install();
|
AntiCheat::LoadLibHook[1].Install();
|
||||||
//AntiCheat::LoadLibHook[2].Install();
|
//AntiCheat::LoadLibHook[2].Install();
|
||||||
//AntiCheat::LoadLibHook[3].Install();
|
//AntiCheat::LoadLibHook[3].Install();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::PatchWinAPI()
|
void AntiCheat::PatchWinAPI()
|
||||||
{
|
{
|
||||||
AntiCheat::UninstallLibHook();
|
AntiCheat::UninstallLibHook();
|
||||||
|
|
||||||
// Initialize directx :P
|
// Initialize directx :P
|
||||||
Utils::Hook::Call<void()>(0x5078C0)();
|
Utils::Hook::Call<void()>(0x5078C0)();
|
||||||
|
|
||||||
AntiCheat::InstallLibHook();
|
AntiCheat::InstallLibHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiCheat::SoundInitStub()
|
void AntiCheat::SoundInitStub()
|
||||||
{
|
{
|
||||||
AntiCheat::UninstallLibHook();
|
AntiCheat::UninstallLibHook();
|
||||||
|
|
||||||
Game::SND_InitDriver();
|
Game::SND_InitDriver();
|
||||||
|
|
||||||
AntiCheat::InstallLibHook();
|
AntiCheat::InstallLibHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOOL WINAPI AntiCheat::VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
|
// BOOL WINAPI AntiCheat::VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
|
||||||
// {
|
// {
|
||||||
// AntiCheat::VirtualProtectHook.Uninstall(false);
|
// AntiCheat::VirtualProtectHook.Uninstall(false);
|
||||||
//
|
//
|
||||||
// if (flNewProtect == PAGE_WRITECOPY || flNewProtect == PAGE_READWRITE || flNewProtect == PAGE_EXECUTE_READWRITE || flNewProtect == PAGE_WRITECOMBINE)
|
// if (flNewProtect == PAGE_WRITECOPY || flNewProtect == PAGE_READWRITE || flNewProtect == PAGE_EXECUTE_READWRITE || flNewProtect == PAGE_WRITECOMBINE)
|
||||||
// {
|
// {
|
||||||
// DWORD addr = (DWORD)lpAddress;
|
// DWORD addr = (DWORD)lpAddress;
|
||||||
// DWORD start = 0x401000;
|
// DWORD start = 0x401000;
|
||||||
// DWORD end = start + 0x2D6000;
|
// DWORD end = start + 0x2D6000;
|
||||||
//
|
//
|
||||||
// if (addr > start && addr < end)
|
// if (addr > start && addr < end)
|
||||||
// {
|
// {
|
||||||
// OutputDebugStringA(Utils::VA("Write access to address %X", lpAddress));
|
// OutputDebugStringA(Utils::VA("Write access to address %X", lpAddress));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// BOOL retVal = VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
|
// BOOL retVal = VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
|
||||||
// AntiCheat::VirtualProtectHook.Install(false);
|
// AntiCheat::VirtualProtectHook.Install(false);
|
||||||
// return retVal;
|
// return retVal;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
AntiCheat::AntiCheat()
|
AntiCheat::AntiCheat()
|
||||||
{
|
{
|
||||||
// This is required for debugging...in release mode :P
|
// This is required for debugging...in release mode :P
|
||||||
//AntiCheat::VirtualProtectHook.Initialize(VirtualProtect, VirtualProtectStub, HOOK_JUMP);
|
//AntiCheat::VirtualProtectHook.Initialize(VirtualProtect, VirtualProtectStub, HOOK_JUMP);
|
||||||
//AntiCheat::VirtualProtectHook.Install(true, true);
|
//AntiCheat::VirtualProtectHook.Install(true, true);
|
||||||
|
|
||||||
AntiCheat::EmptyHash();
|
AntiCheat::EmptyHash();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Command::Add("penis", [] (Command::Params)
|
Command::Add("penis", [] (Command::Params)
|
||||||
{
|
{
|
||||||
AntiCheat::CrashClient();
|
AntiCheat::CrashClient();
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
Utils::Hook(0x60BE8E, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x60BE8E, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x418204, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x418204, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).Install()->Quick();
|
||||||
QuickPatch::OnFrame(AntiCheat::Frame);
|
QuickPatch::OnFrame(AntiCheat::Frame);
|
||||||
|
|
||||||
// TODO: Probably move that :P
|
// TODO: Probably move that :P
|
||||||
AntiCheat::InitLoadLibHook();
|
AntiCheat::InitLoadLibHook();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AntiCheat::~AntiCheat()
|
AntiCheat::~AntiCheat()
|
||||||
{
|
{
|
||||||
AntiCheat::EmptyHash();
|
AntiCheat::EmptyHash();
|
||||||
|
|
||||||
AntiCheat::VirtualProtectHook.Uninstall(false);
|
AntiCheat::VirtualProtectHook.Uninstall(false);
|
||||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
||||||
{
|
{
|
||||||
AntiCheat::LoadLibHook[i].Uninstall();
|
AntiCheat::LoadLibHook[i].Uninstall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,124 +1,124 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IGfxImage::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
void IGfxImage::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image;
|
Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image;
|
||||||
if (image) return; // TODO: Check for default?
|
if (image) return; // TODO: Check for default?
|
||||||
|
|
||||||
image = builder->GetAllocator()->AllocateArray<Game::GfxImage>();
|
image = builder->GetAllocator()->AllocateArray<Game::GfxImage>();
|
||||||
if (!image)
|
if (!image)
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Failed to allocate GfxImage structure!");
|
Components::Logger::Error("Failed to allocate GfxImage structure!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
image->name = builder->GetAllocator()->DuplicateString(name);
|
image->name = builder->GetAllocator()->DuplicateString(name);
|
||||||
image->semantic = 2;
|
image->semantic = 2;
|
||||||
image->category = 0;
|
image->category = 0;
|
||||||
image->cardMemory = 0;
|
image->cardMemory = 0;
|
||||||
|
|
||||||
image->texture = builder->GetAllocator()->AllocateArray<Game::GfxImageLoadDef>();
|
image->texture = builder->GetAllocator()->AllocateArray<Game::GfxImageLoadDef>();
|
||||||
if (!image->texture)
|
if (!image->texture)
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!");
|
Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Components::FileSystem::File iwi(Utils::VA("images/%s.iwi", name.data()));
|
Components::FileSystem::File iwi(fmt::sprintf("images/%s.iwi", name.data()));
|
||||||
|
|
||||||
if (!iwi.Exists())
|
if (!iwi.Exists())
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Loading image '%s' failed!", iwi.GetName().data());
|
Components::Logger::Error("Loading image '%s' failed!", iwi.GetName().data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Game::GfxImageFileHeader* iwiHeader = reinterpret_cast<const Game::GfxImageFileHeader*>(iwi.GetBuffer().data());
|
const Game::GfxImageFileHeader* iwiHeader = reinterpret_cast<const Game::GfxImageFileHeader*>(iwi.GetBuffer().data());
|
||||||
|
|
||||||
image->mapType = 3;
|
image->mapType = 3;
|
||||||
image->dataLen1 = iwiHeader->fileSizeForPicmip[0] - 32;
|
image->dataLen1 = iwiHeader->fileSizeForPicmip[0] - 32;
|
||||||
image->dataLen2 = iwiHeader->fileSizeForPicmip[0] - 32;
|
image->dataLen2 = iwiHeader->fileSizeForPicmip[0] - 32;
|
||||||
|
|
||||||
if (std::memcmp(iwiHeader->tag, "IWi", 3))
|
if (std::memcmp(iwiHeader->tag, "IWi", 3))
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Image is not a valid IWi!");
|
Components::Logger::Error("Image is not a valid IWi!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(image->texture->dimensions, iwiHeader->dimensions, 6);
|
std::memcpy(image->texture->dimensions, iwiHeader->dimensions, 6);
|
||||||
image->texture->flags = 0;
|
image->texture->flags = 0;
|
||||||
image->texture->mipLevels = 0;
|
image->texture->mipLevels = 0;
|
||||||
|
|
||||||
switch (iwiHeader->format)
|
switch (iwiHeader->format)
|
||||||
{
|
{
|
||||||
case Game::IWI_COMPRESSION::IWI_ARGB:
|
case Game::IWI_COMPRESSION::IWI_ARGB:
|
||||||
{
|
{
|
||||||
image->texture->format = 21;
|
image->texture->format = 21;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Game::IWI_COMPRESSION::IWI_RGB8:
|
case Game::IWI_COMPRESSION::IWI_RGB8:
|
||||||
{
|
{
|
||||||
image->texture->format = 20;
|
image->texture->format = 20;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Game::IWI_COMPRESSION::IWI_DXT1:
|
case Game::IWI_COMPRESSION::IWI_DXT1:
|
||||||
{
|
{
|
||||||
image->texture->format = 0x31545844;
|
image->texture->format = 0x31545844;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Game::IWI_COMPRESSION::IWI_DXT3:
|
case Game::IWI_COMPRESSION::IWI_DXT3:
|
||||||
{
|
{
|
||||||
image->texture->format = 0x33545844;
|
image->texture->format = 0x33545844;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Game::IWI_COMPRESSION::IWI_DXT5:
|
case Game::IWI_COMPRESSION::IWI_DXT5:
|
||||||
{
|
{
|
||||||
image->texture->format = 0x35545844;
|
image->texture->format = 0x35545844;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header->image = image;
|
header->image = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGfxImage::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IGfxImage::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::GfxImage, 32);
|
Assert_Size(Game::GfxImage, 32);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->GetBuffer();
|
Utils::Stream* buffer = builder->GetBuffer();
|
||||||
Game::GfxImage* asset = header.image;
|
Game::GfxImage* asset = header.image;
|
||||||
Game::GfxImage* dest = buffer->Dest<Game::GfxImage>();
|
Game::GfxImage* dest = buffer->Dest<Game::GfxImage>();
|
||||||
buffer->Save(asset);
|
buffer->Save(asset);
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
|
|
||||||
if (asset->name)
|
if (asset->name)
|
||||||
{
|
{
|
||||||
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
||||||
Utils::Stream::ClearPointer(&dest->name);
|
Utils::Stream::ClearPointer(&dest->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_TEMP);
|
buffer->PushBlock(Game::XFILE_BLOCK_TEMP);
|
||||||
|
|
||||||
if (asset->texture)
|
if (asset->texture)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::GfxImageLoadDef* destTexture = buffer->Dest<Game::GfxImageLoadDef>();
|
Game::GfxImageLoadDef* destTexture = buffer->Dest<Game::GfxImageLoadDef>();
|
||||||
buffer->Save(asset->texture, 16);
|
buffer->Save(asset->texture, 16);
|
||||||
|
|
||||||
// Zero the size!
|
// Zero the size!
|
||||||
destTexture->dataSize = 0;
|
destTexture->dataSize = 0;
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->texture);
|
Utils::Stream::ClearPointer(&dest->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,320 +1,320 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IMaterial::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
void IMaterial::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Components::FileSystem::File materialInfo(Utils::VA("materials/%s.json", name.data()));
|
Components::FileSystem::File materialInfo(fmt::sprintf("materials/%s.json", name.data()));
|
||||||
|
|
||||||
if (!materialInfo.Exists()) return;
|
if (!materialInfo.Exists()) return;
|
||||||
|
|
||||||
std::string errors;
|
std::string errors;
|
||||||
json11::Json infoData = json11::Json::parse(materialInfo.GetBuffer(), errors);
|
json11::Json infoData = json11::Json::parse(materialInfo.GetBuffer(), errors);
|
||||||
|
|
||||||
if (!infoData.is_object())
|
if (!infoData.is_object())
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Failed to load material information for %s!", name.data());
|
Components::Logger::Error("Failed to load material information for %s!", name.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base = infoData["base"];
|
auto base = infoData["base"];
|
||||||
|
|
||||||
if (!base.is_string())
|
if (!base.is_string())
|
||||||
{
|
{
|
||||||
Components::Logger::Error("No valid material base provided for %s!", name.data());
|
Components::Logger::Error("No valid material base provided for %s!", name.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material;
|
Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material;
|
||||||
|
|
||||||
if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
|
if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data());
|
Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::Material* material = builder->GetAllocator()->AllocateArray<Game::Material>();
|
Game::Material* material = builder->GetAllocator()->AllocateArray<Game::Material>();
|
||||||
|
|
||||||
if (!material)
|
if (!material)
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Failed to allocate material structure!");
|
Components::Logger::Error("Failed to allocate material structure!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy base material to our structure
|
// Copy base material to our structure
|
||||||
std::memcpy(material, baseMaterial, sizeof(Game::Material));
|
std::memcpy(material, baseMaterial, sizeof(Game::Material));
|
||||||
material->name = builder->GetAllocator()->DuplicateString(name);
|
material->name = builder->GetAllocator()->DuplicateString(name);
|
||||||
|
|
||||||
material->textureAtlasRowCount = 1;
|
material->textureAtlasRowCount = 1;
|
||||||
material->textureAtlasColumnCount = 1;
|
material->textureAtlasColumnCount = 1;
|
||||||
|
|
||||||
// Load animation frames
|
// Load animation frames
|
||||||
auto anims = infoData["anims"];
|
auto anims = infoData["anims"];
|
||||||
if (anims.is_array())
|
if (anims.is_array())
|
||||||
{
|
{
|
||||||
auto animCoords = anims.array_items();
|
auto animCoords = anims.array_items();
|
||||||
|
|
||||||
if (animCoords.size() >= 2)
|
if (animCoords.size() >= 2)
|
||||||
{
|
{
|
||||||
auto animCoordX = animCoords[0];
|
auto animCoordX = animCoords[0];
|
||||||
auto animCoordY = animCoords[1];
|
auto animCoordY = animCoords[1];
|
||||||
|
|
||||||
if (animCoordX.is_number())
|
if (animCoordX.is_number())
|
||||||
{
|
{
|
||||||
material->textureAtlasColumnCount = static_cast<char>(animCoordX.number_value()) & 0xFF;
|
material->textureAtlasColumnCount = static_cast<char>(animCoordX.number_value()) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animCoordY.is_number())
|
if (animCoordY.is_number())
|
||||||
{
|
{
|
||||||
material->textureAtlasRowCount = static_cast<char>(animCoordY.number_value()) & 0xFF;
|
material->textureAtlasRowCount = static_cast<char>(animCoordY.number_value()) & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Model surface textures are special, they need a special order and whatnot
|
// Model surface textures are special, they need a special order and whatnot
|
||||||
bool replaceTexture = Utils::StartsWith(name, "mc/");
|
bool replaceTexture = Utils::String::StartsWith(name, "mc/");
|
||||||
if (replaceTexture)
|
if (replaceTexture)
|
||||||
{
|
{
|
||||||
Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray<Game::MaterialTextureDef>(baseMaterial->textureCount);
|
Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray<Game::MaterialTextureDef>(baseMaterial->textureCount);
|
||||||
std::memcpy(textureTable, baseMaterial->textureTable, sizeof(Game::MaterialTextureDef) * baseMaterial->textureCount);
|
std::memcpy(textureTable, baseMaterial->textureTable, sizeof(Game::MaterialTextureDef) * baseMaterial->textureCount);
|
||||||
material->textureTable = textureTable;
|
material->textureTable = textureTable;
|
||||||
material->textureCount = baseMaterial->textureCount;
|
material->textureCount = baseMaterial->textureCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load referenced textures
|
// Load referenced textures
|
||||||
auto textures = infoData["textures"];
|
auto textures = infoData["textures"];
|
||||||
if (textures.is_array())
|
if (textures.is_array())
|
||||||
{
|
{
|
||||||
std::vector<Game::MaterialTextureDef> textureList;
|
std::vector<Game::MaterialTextureDef> textureList;
|
||||||
|
|
||||||
for (auto texture : textures.array_items())
|
for (auto texture : textures.array_items())
|
||||||
{
|
{
|
||||||
if (!texture.is_array()) continue;
|
if (!texture.is_array()) continue;
|
||||||
if (textureList.size() >= 0xFF) break;
|
if (textureList.size() >= 0xFF) break;
|
||||||
|
|
||||||
auto textureInfo = texture.array_items();
|
auto textureInfo = texture.array_items();
|
||||||
if (textureInfo.size() < 2) continue;
|
if (textureInfo.size() < 2) continue;
|
||||||
|
|
||||||
auto map = textureInfo[0];
|
auto map = textureInfo[0];
|
||||||
auto image = textureInfo[1];
|
auto image = textureInfo[1];
|
||||||
if (!map.is_string() || !image.is_string()) continue;
|
if (!map.is_string() || !image.is_string()) continue;
|
||||||
|
|
||||||
Game::MaterialTextureDef textureDef;
|
Game::MaterialTextureDef textureDef;
|
||||||
|
|
||||||
textureDef.semantic = 0; // No water image
|
textureDef.semantic = 0; // No water image
|
||||||
textureDef.sampleState = -30;
|
textureDef.sampleState = -30;
|
||||||
textureDef.nameEnd = map.string_value().back();
|
textureDef.nameEnd = map.string_value().back();
|
||||||
textureDef.nameStart = map.string_value().front();
|
textureDef.nameStart = map.string_value().front();
|
||||||
textureDef.nameHash = Game::R_HashString(map.string_value().data());
|
textureDef.nameHash = Game::R_HashString(map.string_value().data());
|
||||||
|
|
||||||
textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image;
|
textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image;
|
||||||
|
|
||||||
if (replaceTexture)
|
if (replaceTexture)
|
||||||
{
|
{
|
||||||
bool applied = false;
|
bool applied = false;
|
||||||
|
|
||||||
for (char i = 0; i < baseMaterial->textureCount; ++i)
|
for (char i = 0; i < baseMaterial->textureCount; ++i)
|
||||||
{
|
{
|
||||||
if (material->textureTable[i].nameHash == textureDef.nameHash)
|
if (material->textureTable[i].nameHash == textureDef.nameHash)
|
||||||
{
|
{
|
||||||
applied = true;
|
applied = true;
|
||||||
material->textureTable[i].info.image = textureDef.info.image;
|
material->textureTable[i].info.image = textureDef.info.image;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!applied)
|
if (!applied)
|
||||||
{
|
{
|
||||||
Components::Logger::Error(0, "Unable to find texture for map '%s' in %s!", map.string_value().data(), baseMaterial->name);
|
Components::Logger::Error(0, "Unable to find texture for map '%s' in %s!", map.string_value().data(), baseMaterial->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
textureList.push_back(textureDef);
|
textureList.push_back(textureDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!replaceTexture)
|
if(!replaceTexture)
|
||||||
{
|
{
|
||||||
if (!textureList.empty())
|
if (!textureList.empty())
|
||||||
{
|
{
|
||||||
Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray<Game::MaterialTextureDef>(textureList.size());
|
Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray<Game::MaterialTextureDef>(textureList.size());
|
||||||
|
|
||||||
if (!textureTable)
|
if (!textureTable)
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Failed to allocate texture table!");
|
Components::Logger::Error("Failed to allocate texture table!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size());
|
std::memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size());
|
||||||
|
|
||||||
material->textureTable = textureTable;
|
material->textureTable = textureTable;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
material->textureTable = 0;
|
material->textureTable = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
material->textureCount = static_cast<char>(textureList.size()) & 0xFF;
|
material->textureCount = static_cast<char>(textureList.size()) & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header->material = material;
|
header->material = material;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMaterial::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IMaterial::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::Material* asset = header.material;
|
Game::Material* asset = header.material;
|
||||||
|
|
||||||
if (asset->techniqueSet)
|
if (asset->techniqueSet)
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_TECHSET, asset->techniqueSet->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_TECHSET, asset->techniqueSet->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->textureTable)
|
if (asset->textureTable)
|
||||||
{
|
{
|
||||||
for (char i = 0; i < asset->textureCount; ++i)
|
for (char i = 0; i < asset->textureCount; ++i)
|
||||||
{
|
{
|
||||||
if (asset->textureTable[i].info.image)
|
if (asset->textureTable[i].info.image)
|
||||||
{
|
{
|
||||||
if (asset->textureTable[i].semantic == SEMANTIC_WATER_MAP)
|
if (asset->textureTable[i].semantic == SEMANTIC_WATER_MAP)
|
||||||
{
|
{
|
||||||
if (asset->textureTable[i].info.water->image)
|
if (asset->textureTable[i].info.water->image)
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.water->image->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.water->image->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.image->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.image->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMaterial::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IMaterial::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::Material, 96);
|
Assert_Size(Game::Material, 96);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->GetBuffer();
|
Utils::Stream* buffer = builder->GetBuffer();
|
||||||
Game::Material* asset = header.material;
|
Game::Material* asset = header.material;
|
||||||
Game::Material* dest = buffer->Dest<Game::Material>();
|
Game::Material* dest = buffer->Dest<Game::Material>();
|
||||||
buffer->Save(asset);
|
buffer->Save(asset);
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
|
|
||||||
if (asset->name)
|
if (asset->name)
|
||||||
{
|
{
|
||||||
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
||||||
Utils::Stream::ClearPointer(&dest->name);
|
Utils::Stream::ClearPointer(&dest->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->techniqueSet)
|
if (asset->techniqueSet)
|
||||||
{
|
{
|
||||||
dest->techniqueSet = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_TECHSET, asset->techniqueSet->name).materialTechset;
|
dest->techniqueSet = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_TECHSET, asset->techniqueSet->name).materialTechset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->textureTable)
|
if (asset->textureTable)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::MaterialTextureDef, 12);
|
Assert_Size(Game::MaterialTextureDef, 12);
|
||||||
|
|
||||||
// Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine
|
// Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine
|
||||||
if (builder->HasPointer(asset->textureTable))
|
if (builder->HasPointer(asset->textureTable))
|
||||||
{
|
{
|
||||||
dest->textureTable = builder->GetPointer(asset->textureTable);
|
dest->textureTable = builder->GetPointer(asset->textureTable);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
builder->StorePointer(asset->textureTable);
|
builder->StorePointer(asset->textureTable);
|
||||||
|
|
||||||
Game::MaterialTextureDef* destTextureTable = buffer->Dest<Game::MaterialTextureDef>();
|
Game::MaterialTextureDef* destTextureTable = buffer->Dest<Game::MaterialTextureDef>();
|
||||||
buffer->SaveArray(asset->textureTable, asset->textureCount);
|
buffer->SaveArray(asset->textureTable, asset->textureCount);
|
||||||
|
|
||||||
for (char i = 0; i < asset->textureCount; ++i)
|
for (char i = 0; i < asset->textureCount; ++i)
|
||||||
{
|
{
|
||||||
Game::MaterialTextureDef* destTextureDef = &destTextureTable[i];
|
Game::MaterialTextureDef* destTextureDef = &destTextureTable[i];
|
||||||
Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
|
Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
|
||||||
|
|
||||||
if (textureDef->semantic == SEMANTIC_WATER_MAP)
|
if (textureDef->semantic == SEMANTIC_WATER_MAP)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::water_t, 68);
|
Assert_Size(Game::water_t, 68);
|
||||||
|
|
||||||
Game::water_t* destWater = buffer->Dest<Game::water_t>();
|
Game::water_t* destWater = buffer->Dest<Game::water_t>();
|
||||||
Game::water_t* water = textureDef->info.water;
|
Game::water_t* water = textureDef->info.water;
|
||||||
|
|
||||||
if (water)
|
if (water)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(water);
|
buffer->Save(water);
|
||||||
Utils::Stream::ClearPointer(&destTextureDef->info.water);
|
Utils::Stream::ClearPointer(&destTextureDef->info.water);
|
||||||
|
|
||||||
// Save_water_t
|
// Save_water_t
|
||||||
if (water->H0X)
|
if (water->H0X)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(water->H0X, 8, water->M * water->N);
|
buffer->Save(water->H0X, 8, water->M * water->N);
|
||||||
Utils::Stream::ClearPointer(&destWater->H0X);
|
Utils::Stream::ClearPointer(&destWater->H0X);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (water->H0Y)
|
if (water->H0Y)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(water->H0Y, 4, water->M * water->N);
|
buffer->Save(water->H0Y, 4, water->M * water->N);
|
||||||
Utils::Stream::ClearPointer(&destWater->H0Y);
|
Utils::Stream::ClearPointer(&destWater->H0Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (water->image)
|
if (water->image)
|
||||||
{
|
{
|
||||||
destWater->image = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_IMAGE, water->image->name).image;
|
destWater->image = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_IMAGE, water->image->name).image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (textureDef->info.image)
|
else if (textureDef->info.image)
|
||||||
{
|
{
|
||||||
destTextureDef->info.image = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_IMAGE, textureDef->info.image->name).image;
|
destTextureDef->info.image = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_IMAGE, textureDef->info.image->name).image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->textureTable);
|
Utils::Stream::ClearPointer(&dest->textureTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->constantTable)
|
if (asset->constantTable)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::MaterialConstantDef, 32);
|
Assert_Size(Game::MaterialConstantDef, 32);
|
||||||
|
|
||||||
if (builder->HasPointer(asset->constantTable))
|
if (builder->HasPointer(asset->constantTable))
|
||||||
{
|
{
|
||||||
dest->constantTable = builder->GetPointer(asset->constantTable);
|
dest->constantTable = builder->GetPointer(asset->constantTable);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_16);
|
buffer->Align(Utils::Stream::ALIGN_16);
|
||||||
builder->StorePointer(asset->constantTable);
|
builder->StorePointer(asset->constantTable);
|
||||||
|
|
||||||
buffer->SaveArray(asset->constantTable, asset->constantCount);
|
buffer->SaveArray(asset->constantTable, asset->constantCount);
|
||||||
Utils::Stream::ClearPointer(&dest->constantTable);
|
Utils::Stream::ClearPointer(&dest->constantTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->stateBitTable)
|
if (asset->stateBitTable)
|
||||||
{
|
{
|
||||||
if (builder->HasPointer(asset->stateBitTable))
|
if (builder->HasPointer(asset->stateBitTable))
|
||||||
{
|
{
|
||||||
dest->stateBitTable = builder->GetPointer(asset->stateBitTable);
|
dest->stateBitTable = builder->GetPointer(asset->stateBitTable);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
builder->StorePointer(asset->stateBitTable);
|
builder->StorePointer(asset->stateBitTable);
|
||||||
|
|
||||||
buffer->Save(asset->stateBitTable, 8, asset->stateBitsCount);
|
buffer->Save(asset->stateBitTable, 8, asset->stateBitsCount);
|
||||||
Utils::Stream::ClearPointer(&dest->stateBitTable);
|
Utils::Stream::ClearPointer(&dest->stateBitTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,341 +1,341 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IXAnimParts::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
void IXAnimParts::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Components::FileSystem::File animFile(Utils::VA("xanim/%s.iw4xAnim", name.data()));
|
Components::FileSystem::File animFile(fmt::sprintf("xanim/%s.iw4xAnim", name.data()));
|
||||||
|
|
||||||
if (animFile.Exists())
|
if (animFile.Exists())
|
||||||
{
|
{
|
||||||
Utils::Stream::Reader reader(builder->GetAllocator(), animFile.GetBuffer());
|
Utils::Stream::Reader reader(builder->GetAllocator(), animFile.GetBuffer());
|
||||||
|
|
||||||
Game::XAnimParts* xanim = reader.ReadArray<Game::XAnimParts>();
|
Game::XAnimParts* xanim = reader.ReadArray<Game::XAnimParts>();
|
||||||
|
|
||||||
if (xanim)
|
if (xanim)
|
||||||
{
|
{
|
||||||
if (xanim->name)
|
if (xanim->name)
|
||||||
{
|
{
|
||||||
xanim->name = reader.ReadCString();
|
xanim->name = reader.ReadCString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->tagnames)
|
if (xanim->tagnames)
|
||||||
{
|
{
|
||||||
xanim->tagnames = builder->GetAllocator()->AllocateArray<short>(xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
|
xanim->tagnames = builder->GetAllocator()->AllocateArray<short>(xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
|
||||||
for (int i = 0; i < xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
for (int i = 0; i < xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
||||||
{
|
{
|
||||||
xanim->tagnames[i] = Game::SL_GetString(reader.ReadCString(), 0);
|
xanim->tagnames[i] = Game::SL_GetString(reader.ReadCString(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->notetracks)
|
if (xanim->notetracks)
|
||||||
{
|
{
|
||||||
xanim->notetracks = reader.ReadArray<Game::XAnimNotifyInfo>(xanim->notetrackCount);
|
xanim->notetracks = reader.ReadArray<Game::XAnimNotifyInfo>(xanim->notetrackCount);
|
||||||
|
|
||||||
for (int i = 0; i < xanim->notetrackCount; ++i)
|
for (int i = 0; i < xanim->notetrackCount; ++i)
|
||||||
{
|
{
|
||||||
xanim->notetracks[i].name = Game::SL_GetString(reader.ReadCString(), 0);
|
xanim->notetracks[i].name = Game::SL_GetString(reader.ReadCString(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->dataByte)
|
if (xanim->dataByte)
|
||||||
{
|
{
|
||||||
xanim->dataByte = reader.ReadArray<char>(xanim->dataByteCount);
|
xanim->dataByte = reader.ReadArray<char>(xanim->dataByteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->dataShort)
|
if (xanim->dataShort)
|
||||||
{
|
{
|
||||||
xanim->dataShort = reader.ReadArray<short>(xanim->dataShortCount);
|
xanim->dataShort = reader.ReadArray<short>(xanim->dataShortCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->dataInt)
|
if (xanim->dataInt)
|
||||||
{
|
{
|
||||||
xanim->dataInt = reader.ReadArray<int>(xanim->dataIntCount);
|
xanim->dataInt = reader.ReadArray<int>(xanim->dataIntCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->randomDataByte)
|
if (xanim->randomDataByte)
|
||||||
{
|
{
|
||||||
xanim->randomDataByte = reader.ReadArray<char>(xanim->randomDataByteCount);
|
xanim->randomDataByte = reader.ReadArray<char>(xanim->randomDataByteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->randomDataShort)
|
if (xanim->randomDataShort)
|
||||||
{
|
{
|
||||||
xanim->randomDataShort = reader.ReadArray<short>(xanim->randomDataShortCount);
|
xanim->randomDataShort = reader.ReadArray<short>(xanim->randomDataShortCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->randomDataInt)
|
if (xanim->randomDataInt)
|
||||||
{
|
{
|
||||||
xanim->randomDataInt = reader.ReadArray<int>(xanim->randomDataIntCount);
|
xanim->randomDataInt = reader.ReadArray<int>(xanim->randomDataIntCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xanim->indices.data)
|
if (xanim->indices.data)
|
||||||
{
|
{
|
||||||
if (xanim->framecount < 256)
|
if (xanim->framecount < 256)
|
||||||
{
|
{
|
||||||
xanim->indices._1 = reader.ReadArray<char>(xanim->indexcount);
|
xanim->indices._1 = reader.ReadArray<char>(xanim->indexcount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xanim->indices._2 = reader.ReadArray<unsigned short>(xanim->indexcount);
|
xanim->indices._2 = reader.ReadArray<unsigned short>(xanim->indexcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reader.End())
|
if (!reader.End())
|
||||||
{
|
{
|
||||||
Components::Logger::Error(0, "Reading animation '%s' failed, remaining raw data found!", name.data());
|
Components::Logger::Error(0, "Reading animation '%s' failed, remaining raw data found!", name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
header->xanim = xanim;
|
header->xanim = xanim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXAnimParts::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IXAnimParts::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::XAnimParts* asset = header.xanim;
|
Game::XAnimParts* asset = header.xanim;
|
||||||
|
|
||||||
if (asset->tagnames)
|
if (asset->tagnames)
|
||||||
{
|
{
|
||||||
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
||||||
{
|
{
|
||||||
builder->AddScriptString(asset->tagnames[i]);
|
builder->AddScriptString(asset->tagnames[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->notetracks)
|
if (asset->notetracks)
|
||||||
{
|
{
|
||||||
for (char i = 0; i < asset->notetrackCount; ++i)
|
for (char i = 0; i < asset->notetrackCount; ++i)
|
||||||
{
|
{
|
||||||
builder->AddScriptString(asset->notetracks[i].name);
|
builder->AddScriptString(asset->notetracks[i].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXAnimParts::Save_XAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder)
|
void IXAnimParts::Save_XAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XAnimDeltaPart, 12);
|
Assert_Size(Game::XAnimDeltaPart, 12);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->GetBuffer();
|
Utils::Stream* buffer = builder->GetBuffer();
|
||||||
Game::XAnimDeltaPart* destDelta = buffer->Dest<Game::XAnimDeltaPart>();
|
Game::XAnimDeltaPart* destDelta = buffer->Dest<Game::XAnimDeltaPart>();
|
||||||
buffer->Save(delta);
|
buffer->Save(delta);
|
||||||
|
|
||||||
if (delta->trans)
|
if (delta->trans)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->trans, 4);
|
buffer->Save(delta->trans, 4);
|
||||||
|
|
||||||
if (delta->trans->size)
|
if (delta->trans->size)
|
||||||
{
|
{
|
||||||
buffer->Save(&delta->trans->u.frames, 28);
|
buffer->Save(&delta->trans->u.frames, 28);
|
||||||
|
|
||||||
if (framecount > 0xFF)
|
if (framecount > 0xFF)
|
||||||
{
|
{
|
||||||
buffer->SaveArray(delta->trans->u.frames.indices._2, delta->trans->size + 1);
|
buffer->SaveArray(delta->trans->u.frames.indices._2, delta->trans->size + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->SaveArray(delta->trans->u.frames.indices._1, delta->trans->size + 1);
|
buffer->SaveArray(delta->trans->u.frames.indices._1, delta->trans->size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta->trans->u.frames.frames._1)
|
if (delta->trans->u.frames.frames._1)
|
||||||
{
|
{
|
||||||
if (delta->trans->smallTrans)
|
if (delta->trans->smallTrans)
|
||||||
{
|
{
|
||||||
buffer->Save(delta->trans->u.frames.frames._1, 3, delta->trans->size + 1);
|
buffer->Save(delta->trans->u.frames.frames._1, 3, delta->trans->size + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->trans->u.frames.frames._1, 6, delta->trans->size + 1);
|
buffer->Save(delta->trans->u.frames.frames._1, 6, delta->trans->size + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Save(delta->trans->u.frame0, 12);
|
buffer->Save(delta->trans->u.frame0, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&destDelta->trans);
|
Utils::Stream::ClearPointer(&destDelta->trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta->quat2)
|
if (delta->quat2)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->quat2, 4);
|
buffer->Save(delta->quat2, 4);
|
||||||
|
|
||||||
if (delta->quat2->size)
|
if (delta->quat2->size)
|
||||||
{
|
{
|
||||||
buffer->Save(&delta->quat2->u.frames, 4);
|
buffer->Save(&delta->quat2->u.frames, 4);
|
||||||
|
|
||||||
if (framecount > 0xFF)
|
if (framecount > 0xFF)
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat2->u.frames.indices, 2, delta->quat2->size + 1);
|
buffer->Save(delta->quat2->u.frames.indices, 2, delta->quat2->size + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat2->u.frames.indices, 1, delta->quat2->size + 1);
|
buffer->Save(delta->quat2->u.frames.indices, 1, delta->quat2->size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta->quat2->u.frames.frames)
|
if (delta->quat2->u.frames.frames)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->quat2->u.frames.frames, 4, delta->quat2->size + 1);
|
buffer->Save(delta->quat2->u.frames.frames, 4, delta->quat2->size + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat2->u.frame0, 4);
|
buffer->Save(delta->quat2->u.frame0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&destDelta->quat2);
|
Utils::Stream::ClearPointer(&destDelta->quat2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta->quat)
|
if (delta->quat)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->quat, 4);
|
buffer->Save(delta->quat, 4);
|
||||||
|
|
||||||
if (delta->quat->size)
|
if (delta->quat->size)
|
||||||
{
|
{
|
||||||
buffer->Save(&delta->quat->u.frames, 4);
|
buffer->Save(&delta->quat->u.frames, 4);
|
||||||
|
|
||||||
if (framecount > 0xFF)
|
if (framecount > 0xFF)
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat->u.frames.indices, 2, delta->quat->size + 1);
|
buffer->Save(delta->quat->u.frames.indices, 2, delta->quat->size + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat->u.frames.indices, 1, delta->quat->size + 1);
|
buffer->Save(delta->quat->u.frames.indices, 1, delta->quat->size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta->quat->u.frames.frames)
|
if (delta->quat->u.frames.frames)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->Save(delta->quat->u.frames.frames, 4, delta->quat->size + 1);
|
buffer->Save(delta->quat->u.frames.frames, 4, delta->quat->size + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->Save(delta->quat->u.frame0, 4);
|
buffer->Save(delta->quat->u.frame0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&destDelta->quat);
|
Utils::Stream::ClearPointer(&destDelta->quat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXAnimParts::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IXAnimParts::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XAnimParts, 88);
|
Assert_Size(Game::XAnimParts, 88);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->GetBuffer();
|
Utils::Stream* buffer = builder->GetBuffer();
|
||||||
Game::XAnimParts* asset = header.xanim;
|
Game::XAnimParts* asset = header.xanim;
|
||||||
Game::XAnimParts* dest = buffer->Dest<Game::XAnimParts>();
|
Game::XAnimParts* dest = buffer->Dest<Game::XAnimParts>();
|
||||||
buffer->Save(asset, sizeof(Game::XAnimParts));
|
buffer->Save(asset, sizeof(Game::XAnimParts));
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
|
|
||||||
if (asset->name)
|
if (asset->name)
|
||||||
{
|
{
|
||||||
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
||||||
Utils::Stream::ClearPointer(&dest->name);
|
Utils::Stream::ClearPointer(&dest->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->tagnames)
|
if (asset->tagnames)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
|
|
||||||
unsigned short* destTagnames = buffer->Dest<unsigned short>();
|
unsigned short* destTagnames = buffer->Dest<unsigned short>();
|
||||||
buffer->SaveArray(asset->tagnames, asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
|
buffer->SaveArray(asset->tagnames, asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
|
||||||
|
|
||||||
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
|
||||||
{
|
{
|
||||||
builder->MapScriptString(&destTagnames[i]);
|
builder->MapScriptString(&destTagnames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->tagnames);
|
Utils::Stream::ClearPointer(&dest->tagnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->notetracks)
|
if (asset->notetracks)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XAnimNotifyInfo, 8);
|
Assert_Size(Game::XAnimNotifyInfo, 8);
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::XAnimNotifyInfo* destNotetracks = buffer->Dest<Game::XAnimNotifyInfo>();
|
Game::XAnimNotifyInfo* destNotetracks = buffer->Dest<Game::XAnimNotifyInfo>();
|
||||||
buffer->SaveArray(asset->notetracks, asset->notetrackCount);
|
buffer->SaveArray(asset->notetracks, asset->notetrackCount);
|
||||||
|
|
||||||
for (char i = 0; i < asset->notetrackCount; ++i)
|
for (char i = 0; i < asset->notetrackCount; ++i)
|
||||||
{
|
{
|
||||||
builder->MapScriptString(&destNotetracks[i].name);
|
builder->MapScriptString(&destNotetracks[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->notetracks);
|
Utils::Stream::ClearPointer(&dest->notetracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->delta)
|
if (asset->delta)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XAnimDeltaPart, 12);
|
Assert_Size(Game::XAnimDeltaPart, 12);
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
IXAnimParts::Save_XAnimDeltaPart(asset->delta, asset->framecount, builder);
|
IXAnimParts::Save_XAnimDeltaPart(asset->delta, asset->framecount, builder);
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->delta);
|
Utils::Stream::ClearPointer(&dest->delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->dataByte)
|
if (asset->dataByte)
|
||||||
{
|
{
|
||||||
buffer->SaveArray(asset->dataByte, asset->dataByteCount);
|
buffer->SaveArray(asset->dataByte, asset->dataByteCount);
|
||||||
Utils::Stream::ClearPointer(&dest->dataByte);
|
Utils::Stream::ClearPointer(&dest->dataByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->dataShort)
|
if (asset->dataShort)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
buffer->SaveArray(asset->dataShort, asset->dataShortCount);
|
buffer->SaveArray(asset->dataShort, asset->dataShortCount);
|
||||||
Utils::Stream::ClearPointer(&dest->dataShort);
|
Utils::Stream::ClearPointer(&dest->dataShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->dataInt)
|
if (asset->dataInt)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->SaveArray(asset->dataInt, asset->dataIntCount);
|
buffer->SaveArray(asset->dataInt, asset->dataIntCount);
|
||||||
Utils::Stream::ClearPointer(&dest->dataInt);
|
Utils::Stream::ClearPointer(&dest->dataInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->randomDataShort)
|
if (asset->randomDataShort)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
buffer->SaveArray(asset->randomDataShort, asset->randomDataShortCount);
|
buffer->SaveArray(asset->randomDataShort, asset->randomDataShortCount);
|
||||||
Utils::Stream::ClearPointer(&dest->randomDataShort);
|
Utils::Stream::ClearPointer(&dest->randomDataShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->randomDataByte)
|
if (asset->randomDataByte)
|
||||||
{
|
{
|
||||||
buffer->SaveArray(asset->randomDataByte, asset->randomDataByteCount);
|
buffer->SaveArray(asset->randomDataByte, asset->randomDataByteCount);
|
||||||
Utils::Stream::ClearPointer(&dest->randomDataByte);
|
Utils::Stream::ClearPointer(&dest->randomDataByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->randomDataInt)
|
if (asset->randomDataInt)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->SaveArray(asset->randomDataInt, asset->randomDataIntCount);
|
buffer->SaveArray(asset->randomDataInt, asset->randomDataIntCount);
|
||||||
Utils::Stream::ClearPointer(&dest->randomDataInt);
|
Utils::Stream::ClearPointer(&dest->randomDataInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->indices.data)
|
if (asset->indices.data)
|
||||||
{
|
{
|
||||||
if (asset->framecount > 0xFF)
|
if (asset->framecount > 0xFF)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
buffer->SaveArray(asset->indices._2, asset->indexcount);
|
buffer->SaveArray(asset->indices._2, asset->indexcount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->SaveArray(asset->indices._1, asset->indexcount);
|
buffer->SaveArray(asset->indices._1, asset->indexcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->indices.data);
|
Utils::Stream::ClearPointer(&dest->indices.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,354 +1,354 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IXModel::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
void IXModel::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Components::FileSystem::File modelFile(Utils::VA("xmodel/%s.iw4xModel", name.data()));
|
Components::FileSystem::File modelFile(fmt::sprintf("xmodel/%s.iw4xModel", name.data()));
|
||||||
|
|
||||||
if (modelFile.Exists())
|
if (modelFile.Exists())
|
||||||
{
|
{
|
||||||
Game::XModel* baseModel = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_XMODEL, "viewmodel_mp5k").model;
|
Game::XModel* baseModel = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_XMODEL, "viewmodel_mp5k").model;
|
||||||
|
|
||||||
// Allocate new model and copy the base data to it
|
// Allocate new model and copy the base data to it
|
||||||
Game::XModel* model = builder->GetAllocator()->AllocateArray<Game::XModel>();
|
Game::XModel* model = builder->GetAllocator()->AllocateArray<Game::XModel>();
|
||||||
std::memcpy(model, baseModel, sizeof(Game::XModel));
|
std::memcpy(model, baseModel, sizeof(Game::XModel));
|
||||||
|
|
||||||
Utils::Stream::Reader reader(builder->GetAllocator(), modelFile.GetBuffer());
|
Utils::Stream::Reader reader(builder->GetAllocator(), modelFile.GetBuffer());
|
||||||
|
|
||||||
model->name = reader.ReadCString();
|
model->name = reader.ReadCString();
|
||||||
model->numBones = reader.ReadByte();
|
model->numBones = reader.ReadByte();
|
||||||
model->numRootBones = reader.ReadByte();
|
model->numRootBones = reader.ReadByte();
|
||||||
model->numSurfaces = reader.ReadByte();
|
model->numSurfaces = reader.ReadByte();
|
||||||
model->numColSurfs = reader.Read<int>();
|
model->numColSurfs = reader.Read<int>();
|
||||||
|
|
||||||
// Read bone names
|
// Read bone names
|
||||||
model->boneNames = builder->GetAllocator()->AllocateArray<short>(model->numBones);
|
model->boneNames = builder->GetAllocator()->AllocateArray<short>(model->numBones);
|
||||||
for (int i = 0; i < model->numBones; ++i)
|
for (int i = 0; i < model->numBones; ++i)
|
||||||
{
|
{
|
||||||
model->boneNames[i] = Game::SL_GetString(reader.ReadCString(), 0);
|
model->boneNames[i] = Game::SL_GetString(reader.ReadCString(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bone count
|
// Bone count
|
||||||
int boneCount = (model->numBones - model->numRootBones);
|
int boneCount = (model->numBones - model->numRootBones);
|
||||||
|
|
||||||
// Read bone data
|
// Read bone data
|
||||||
model->parentList = reader.ReadArray<char>(boneCount);
|
model->parentList = reader.ReadArray<char>(boneCount);
|
||||||
model->tagAngles = reader.ReadArray<Game::XModelAngle>(boneCount);
|
model->tagAngles = reader.ReadArray<Game::XModelAngle>(boneCount);
|
||||||
model->tagPositions = reader.ReadArray<Game::XModelTagPos>(boneCount);
|
model->tagPositions = reader.ReadArray<Game::XModelTagPos>(boneCount);
|
||||||
model->partClassification = reader.ReadArray<char>(boneCount);
|
model->partClassification = reader.ReadArray<char>(boneCount);
|
||||||
model->animMatrix = reader.ReadArray<Game::DObjAnimMat>(boneCount);
|
model->animMatrix = reader.ReadArray<Game::DObjAnimMat>(boneCount);
|
||||||
|
|
||||||
// Prepare surfaces
|
// Prepare surfaces
|
||||||
Game::XSurface* baseSurface = &baseModel->lods[0].surfaces[0].surfaces[0];
|
Game::XSurface* baseSurface = &baseModel->lods[0].surfaces[0].surfaces[0];
|
||||||
Game::XModelSurfs* surf = builder->GetAllocator()->AllocateArray<Game::XModelSurfs>();
|
Game::XModelSurfs* surf = builder->GetAllocator()->AllocateArray<Game::XModelSurfs>();
|
||||||
|
|
||||||
std::memcpy(surf, baseModel->lods[0].surfaces, sizeof(Game::XModelSurfs));
|
std::memcpy(surf, baseModel->lods[0].surfaces, sizeof(Game::XModelSurfs));
|
||||||
surf->name = builder->GetAllocator()->DuplicateString(Utils::VA("%s1", model->name));
|
surf->name = builder->GetAllocator()->DuplicateString(fmt::sprintf("%s1", model->name));
|
||||||
surf->surfaces = builder->GetAllocator()->AllocateArray<Game::XSurface>(model->numSurfaces);
|
surf->surfaces = builder->GetAllocator()->AllocateArray<Game::XSurface>(model->numSurfaces);
|
||||||
surf->numSurfaces = model->numSurfaces;
|
surf->numSurfaces = model->numSurfaces;
|
||||||
|
|
||||||
model->lods[0].numSurfs = model->numSurfaces;
|
model->lods[0].numSurfs = model->numSurfaces;
|
||||||
model->lods[0].surfaces = surf;
|
model->lods[0].surfaces = surf;
|
||||||
|
|
||||||
// Reset surfaces in remaining lods
|
// Reset surfaces in remaining lods
|
||||||
for (unsigned int i = 1; i < 4; ++i)
|
for (unsigned int i = 1; i < 4; ++i)
|
||||||
{
|
{
|
||||||
model->lods[i].numSurfs = 0;
|
model->lods[i].numSurfs = 0;
|
||||||
model->lods[i].surfaces = nullptr;
|
model->lods[i].surfaces = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read surfaces
|
// Read surfaces
|
||||||
for (int i = 0; i < surf->numSurfaces; ++i)
|
for (int i = 0; i < surf->numSurfaces; ++i)
|
||||||
{
|
{
|
||||||
Game::XSurface* surface = &surf->surfaces[i];
|
Game::XSurface* surface = &surf->surfaces[i];
|
||||||
std::memcpy(surface, baseSurface, sizeof(Game::XSurface));
|
std::memcpy(surface, baseSurface, sizeof(Game::XSurface));
|
||||||
|
|
||||||
surface->streamHandle = reader.Read<unsigned char>();
|
surface->streamHandle = reader.Read<unsigned char>();
|
||||||
surface->something = reader.Read<int>();
|
surface->something = reader.Read<int>();
|
||||||
surface->something2 = reader.Read<int>();
|
surface->something2 = reader.Read<int>();
|
||||||
|
|
||||||
surface->numVertices = reader.Read<unsigned short>();
|
surface->numVertices = reader.Read<unsigned short>();
|
||||||
surface->numPrimitives = reader.Read<unsigned short>();
|
surface->numPrimitives = reader.Read<unsigned short>();
|
||||||
surface->numCT = reader.Read<int>();
|
surface->numCT = reader.Read<int>();
|
||||||
|
|
||||||
surface->blendNum1 = reader.Read<short>();
|
surface->blendNum1 = reader.Read<short>();
|
||||||
surface->blendNum2 = reader.Read<short>();
|
surface->blendNum2 = reader.Read<short>();
|
||||||
surface->blendNum3 = reader.Read<short>();
|
surface->blendNum3 = reader.Read<short>();
|
||||||
surface->blendNum4 = reader.Read<short>();
|
surface->blendNum4 = reader.Read<short>();
|
||||||
|
|
||||||
surface->blendInfo = reinterpret_cast<char*>(reader.Read(2, surface->blendNum1 + (3 * surface->blendNum2) + (5 * surface->blendNum3) + (7 * surface->blendNum4)));
|
surface->blendInfo = reinterpret_cast<char*>(reader.Read(2, surface->blendNum1 + (3 * surface->blendNum2) + (5 * surface->blendNum3) + (7 * surface->blendNum4)));
|
||||||
|
|
||||||
surface->vertexBuffer = reader.ReadArray<Game::GfxPackedVertex>(surface->numVertices);
|
surface->vertexBuffer = reader.ReadArray<Game::GfxPackedVertex>(surface->numVertices);
|
||||||
surface->indexBuffer = reader.ReadArray<Game::Face>(surface->numPrimitives);
|
surface->indexBuffer = reader.ReadArray<Game::Face>(surface->numPrimitives);
|
||||||
|
|
||||||
// Read vert list
|
// Read vert list
|
||||||
if (reader.ReadByte())
|
if (reader.ReadByte())
|
||||||
{
|
{
|
||||||
surface->ct = reader.ReadArray<Game::XRigidVertList>(surface->numCT);
|
surface->ct = reader.ReadArray<Game::XRigidVertList>(surface->numCT);
|
||||||
|
|
||||||
for (int j = 0; j < surface->numCT; ++j)
|
for (int j = 0; j < surface->numCT; ++j)
|
||||||
{
|
{
|
||||||
Game::XRigidVertList* vertList = &surface->ct[j];
|
Game::XRigidVertList* vertList = &surface->ct[j];
|
||||||
|
|
||||||
vertList->entry = reader.ReadArray<Game::XSurfaceCollisionTree>();
|
vertList->entry = reader.ReadArray<Game::XSurfaceCollisionTree>();
|
||||||
vertList->entry->node = reinterpret_cast<char*>(reader.Read(16, vertList->entry->numNode));
|
vertList->entry->node = reinterpret_cast<char*>(reader.Read(16, vertList->entry->numNode));
|
||||||
vertList->entry->leaf = reader.ReadArray<short>(vertList->entry->numLeaf);
|
vertList->entry->leaf = reader.ReadArray<short>(vertList->entry->numLeaf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
surface->ct = nullptr;
|
surface->ct = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read materials
|
// Read materials
|
||||||
model->materials = builder->GetAllocator()->AllocateArray<Game::Material*>(model->numSurfaces);
|
model->materials = builder->GetAllocator()->AllocateArray<Game::Material*>(model->numSurfaces);
|
||||||
for (char i = 0; i < model->numSurfaces; ++i)
|
for (char i = 0; i < model->numSurfaces; ++i)
|
||||||
{
|
{
|
||||||
model->materials[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.ReadString(), builder).material;
|
model->materials[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.ReadString(), builder).material;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read collision surfaces
|
// Read collision surfaces
|
||||||
if (reader.ReadByte())
|
if (reader.ReadByte())
|
||||||
{
|
{
|
||||||
model->colSurf = reader.ReadArray<Game::XModelCollSurf>(model->numColSurfs);
|
model->colSurf = reader.ReadArray<Game::XModelCollSurf>(model->numColSurfs);
|
||||||
|
|
||||||
for (int i = 0; i < model->numColSurfs; ++i)
|
for (int i = 0; i < model->numColSurfs; ++i)
|
||||||
{
|
{
|
||||||
if (model->colSurf[i].tris)
|
if (model->colSurf[i].tris)
|
||||||
{
|
{
|
||||||
model->colSurf[i].tris = reader.Read(48, model->colSurf[i].count);
|
model->colSurf[i].tris = reader.Read(48, model->colSurf[i].count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model->colSurf = nullptr;
|
model->colSurf = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read bone info
|
// Read bone info
|
||||||
if (reader.ReadByte())
|
if (reader.ReadByte())
|
||||||
{
|
{
|
||||||
model->boneInfo = reader.ReadArray<Game::XBoneInfo>(model->numBones);
|
model->boneInfo = reader.ReadArray<Game::XBoneInfo>(model->numBones);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model->boneInfo = nullptr;
|
model->boneInfo = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reader.End())
|
if (!reader.End())
|
||||||
{
|
{
|
||||||
Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data());
|
Components::Logger::Error(0, "Reading model '%s' failed, remaining raw data found!", name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
header->model = model;
|
header->model = model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXModel::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IXModel::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::XModel* asset = header.model;
|
Game::XModel* asset = header.model;
|
||||||
|
|
||||||
if (asset->boneNames)
|
if (asset->boneNames)
|
||||||
{
|
{
|
||||||
for (char i = 0; i < asset->numBones; ++i)
|
for (char i = 0; i < asset->numBones; ++i)
|
||||||
{
|
{
|
||||||
builder->AddScriptString(asset->boneNames[i]);
|
builder->AddScriptString(asset->boneNames[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->materials)
|
if (asset->materials)
|
||||||
{
|
{
|
||||||
for (char i = 0; i < asset->numSurfaces; ++i)
|
for (char i = 0; i < asset->numSurfaces; ++i)
|
||||||
{
|
{
|
||||||
if (asset->materials[i])
|
if (asset->materials[i])
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materials[i]->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materials[i]->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
if (asset->lods[i].surfaces)
|
if (asset->lods[i].surfaces)
|
||||||
{
|
{
|
||||||
// We're not supposed to include xmodelsurfs as standalone asset
|
// We're not supposed to include xmodelsurfs as standalone asset
|
||||||
//builder->LoadAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name);
|
//builder->LoadAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name);
|
||||||
|
|
||||||
IXModelSurfs().Mark({ asset->lods[i].surfaces }, builder);
|
IXModelSurfs().Mark({ asset->lods[i].surfaces }, builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->physPreset)
|
if (asset->physPreset)
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->physCollmap)
|
if (asset->physCollmap)
|
||||||
{
|
{
|
||||||
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name);
|
builder->LoadAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXModel::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IXModel::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XModel, 304);
|
Assert_Size(Game::XModel, 304);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->GetBuffer();
|
Utils::Stream* buffer = builder->GetBuffer();
|
||||||
Game::XModel* asset = header.model;
|
Game::XModel* asset = header.model;
|
||||||
Game::XModel* dest = buffer->Dest<Game::XModel>();
|
Game::XModel* dest = buffer->Dest<Game::XModel>();
|
||||||
buffer->Save(asset);
|
buffer->Save(asset);
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
|
|
||||||
if (asset->name)
|
if (asset->name)
|
||||||
{
|
{
|
||||||
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name));
|
||||||
Utils::Stream::ClearPointer(&dest->name);
|
Utils::Stream::ClearPointer(&dest->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->boneNames)
|
if (asset->boneNames)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
|
|
||||||
unsigned short* destBoneNames = buffer->Dest<unsigned short>();
|
unsigned short* destBoneNames = buffer->Dest<unsigned short>();
|
||||||
buffer->SaveArray(asset->boneNames, asset->numBones);
|
buffer->SaveArray(asset->boneNames, asset->numBones);
|
||||||
|
|
||||||
for (char i = 0; i < asset->numBones; ++i)
|
for (char i = 0; i < asset->numBones; ++i)
|
||||||
{
|
{
|
||||||
builder->MapScriptString(&destBoneNames[i]);
|
builder->MapScriptString(&destBoneNames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->boneNames);
|
Utils::Stream::ClearPointer(&dest->boneNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->parentList)
|
if (asset->parentList)
|
||||||
{
|
{
|
||||||
buffer->Save(asset->parentList, asset->numBones - asset->numRootBones);
|
buffer->Save(asset->parentList, asset->numBones - asset->numRootBones);
|
||||||
Utils::Stream::ClearPointer(&dest->parentList);
|
Utils::Stream::ClearPointer(&dest->parentList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->tagAngles)
|
if (asset->tagAngles)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XModelAngle, 8);
|
Assert_Size(Game::XModelAngle, 8);
|
||||||
|
|
||||||
buffer->Align(Utils::Stream::ALIGN_2);
|
buffer->Align(Utils::Stream::ALIGN_2);
|
||||||
buffer->SaveArray(asset->tagAngles, asset->numBones - asset->numRootBones);
|
buffer->SaveArray(asset->tagAngles, asset->numBones - asset->numRootBones);
|
||||||
Utils::Stream::ClearPointer(&dest->tagAngles);
|
Utils::Stream::ClearPointer(&dest->tagAngles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->tagPositions)
|
if (asset->tagPositions)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XModelTagPos, 12);
|
Assert_Size(Game::XModelTagPos, 12);
|
||||||
|
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->SaveArray(asset->tagPositions, asset->numBones - asset->numRootBones);
|
buffer->SaveArray(asset->tagPositions, asset->numBones - asset->numRootBones);
|
||||||
Utils::Stream::ClearPointer(&dest->tagPositions);
|
Utils::Stream::ClearPointer(&dest->tagPositions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->partClassification)
|
if (asset->partClassification)
|
||||||
{
|
{
|
||||||
buffer->Save(asset->partClassification, asset->numBones);
|
buffer->Save(asset->partClassification, asset->numBones);
|
||||||
Utils::Stream::ClearPointer(&dest->partClassification);
|
Utils::Stream::ClearPointer(&dest->partClassification);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->animMatrix)
|
if (asset->animMatrix)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::DObjAnimMat, 32);
|
Assert_Size(Game::DObjAnimMat, 32);
|
||||||
|
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
buffer->SaveArray(asset->animMatrix, asset->numBones);
|
buffer->SaveArray(asset->animMatrix, asset->numBones);
|
||||||
Utils::Stream::ClearPointer(&dest->animMatrix);
|
Utils::Stream::ClearPointer(&dest->animMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->materials)
|
if (asset->materials)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::Material** destMaterials = buffer->Dest<Game::Material*>();
|
Game::Material** destMaterials = buffer->Dest<Game::Material*>();
|
||||||
buffer->SaveArray(asset->materials, asset->numSurfaces);
|
buffer->SaveArray(asset->materials, asset->numSurfaces);
|
||||||
|
|
||||||
for (char i = 0; i < asset->numSurfaces; ++i)
|
for (char i = 0; i < asset->numSurfaces; ++i)
|
||||||
{
|
{
|
||||||
if (asset->materials[i])
|
if (asset->materials[i])
|
||||||
{
|
{
|
||||||
destMaterials[i] = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materials[i]->name).material;
|
destMaterials[i] = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materials[i]->name).material;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->materials);
|
Utils::Stream::ClearPointer(&dest->materials);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save_XModelLodInfoArray
|
// Save_XModelLodInfoArray
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XModelLodInfo, 44);
|
Assert_Size(Game::XModelLodInfo, 44);
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
if (asset->lods[i].surfaces)
|
if (asset->lods[i].surfaces)
|
||||||
{
|
{
|
||||||
// Requiring this asset is not possible, it has to be loaded as part of the model
|
// Requiring this asset is not possible, it has to be loaded as part of the model
|
||||||
//dest->lods[i].surfaces = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name).surfaces;
|
//dest->lods[i].surfaces = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_XMODELSURFS, asset->lods[i].surfaces->name).surfaces;
|
||||||
|
|
||||||
buffer->PushBlock(Game::XFILE_BLOCK_TEMP);
|
buffer->PushBlock(Game::XFILE_BLOCK_TEMP);
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
IXModelSurfs().Save({ asset->lods[i].surfaces }, builder);
|
IXModelSurfs().Save({ asset->lods[i].surfaces }, builder);
|
||||||
Utils::Stream::ClearPointer(&dest->lods[i].surfaces);
|
Utils::Stream::ClearPointer(&dest->lods[i].surfaces);
|
||||||
|
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save_XModelCollSurfArray
|
// Save_XModelCollSurfArray
|
||||||
if (asset->colSurf)
|
if (asset->colSurf)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XModelCollSurf, 44);
|
Assert_Size(Game::XModelCollSurf, 44);
|
||||||
|
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::XModelCollSurf* destColSurfs = buffer->Dest<Game::XModelCollSurf>();
|
Game::XModelCollSurf* destColSurfs = buffer->Dest<Game::XModelCollSurf>();
|
||||||
buffer->SaveArray(asset->colSurf, asset->numColSurfs);
|
buffer->SaveArray(asset->colSurf, asset->numColSurfs);
|
||||||
|
|
||||||
for (int i = 0; i < asset->numColSurfs; ++i)
|
for (int i = 0; i < asset->numColSurfs; ++i)
|
||||||
{
|
{
|
||||||
Game::XModelCollSurf* destColSurf = &destColSurfs[i];
|
Game::XModelCollSurf* destColSurf = &destColSurfs[i];
|
||||||
Game::XModelCollSurf* colSurf = &asset->colSurf[i];
|
Game::XModelCollSurf* colSurf = &asset->colSurf[i];
|
||||||
|
|
||||||
if (colSurf->tris)
|
if (colSurf->tris)
|
||||||
{
|
{
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
buffer->Save(colSurf->tris, 48, colSurf->count);
|
buffer->Save(colSurf->tris, 48, colSurf->count);
|
||||||
Utils::Stream::ClearPointer(&destColSurf->tris);
|
Utils::Stream::ClearPointer(&destColSurf->tris);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Stream::ClearPointer(&dest->colSurf);
|
Utils::Stream::ClearPointer(&dest->colSurf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->boneInfo)
|
if (asset->boneInfo)
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XBoneInfo, 28);
|
Assert_Size(Game::XBoneInfo, 28);
|
||||||
|
|
||||||
buffer->Align(Utils::Stream::ALIGN_4);
|
buffer->Align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
buffer->SaveArray(asset->boneInfo, asset->numBones);
|
buffer->SaveArray(asset->boneInfo, asset->numBones);
|
||||||
Utils::Stream::ClearPointer(&dest->boneInfo);
|
Utils::Stream::ClearPointer(&dest->boneInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->physPreset)
|
if (asset->physPreset)
|
||||||
{
|
{
|
||||||
dest->physPreset = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name).physPreset;
|
dest->physPreset = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset->name).physPreset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->physCollmap)
|
if (asset->physCollmap)
|
||||||
{
|
{
|
||||||
dest->physCollmap = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name).physCollmap;
|
dest->physCollmap = builder->RequireAsset(Game::XAssetType::ASSET_TYPE_PHYS_COLLMAP, asset->physCollmap->name).physCollmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->PopBlock();
|
buffer->PopBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,494 +1,494 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Auth::AuthInfo Auth::ClientAuthInfo[18];
|
Auth::AuthInfo Auth::ClientAuthInfo[18];
|
||||||
Auth::TokenIncrementing Auth::TokenContainer;
|
Auth::TokenIncrementing Auth::TokenContainer;
|
||||||
|
|
||||||
Utils::Cryptography::Token Auth::GuidToken;
|
Utils::Cryptography::Token Auth::GuidToken;
|
||||||
Utils::Cryptography::Token Auth::ComputeToken;
|
Utils::Cryptography::Token Auth::ComputeToken;
|
||||||
Utils::Cryptography::ECC::Key Auth::GuidKey;
|
Utils::Cryptography::ECC::Key Auth::GuidKey;
|
||||||
|
|
||||||
void Auth::Frame()
|
void Auth::Frame()
|
||||||
{
|
{
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
for (int i = 0; i < *Game::svs_numclients; i++)
|
for (int i = 0; i < *Game::svs_numclients; i++)
|
||||||
{
|
{
|
||||||
Game::client_t* client = &Game::svs_clients[i];
|
Game::client_t* client = &Game::svs_clients[i];
|
||||||
Auth::AuthInfo* info = &Auth::ClientAuthInfo[i];
|
Auth::AuthInfo* info = &Auth::ClientAuthInfo[i];
|
||||||
|
|
||||||
// State must be 5 or greater here, as otherwise the client will crash when being kicked.
|
// State must be 5 or greater here, as otherwise the client will crash when being kicked.
|
||||||
// That's due to the hunk being freed by that time, but it hasn't been reallocated, therefore all future allocations will cause a crash.
|
// That's due to the hunk being freed by that time, but it hasn't been reallocated, therefore all future allocations will cause a crash.
|
||||||
// Additionally, the game won't catch the errors and simply lose the connection, so we even have to add a delay to send the data.
|
// Additionally, the game won't catch the errors and simply lose the connection, so we even have to add a delay to send the data.
|
||||||
|
|
||||||
// Not sure if that's potentially unsafe, though.
|
// Not sure if that's potentially unsafe, though.
|
||||||
// Players faking their GUID will be connected for 5 seconds, which allows them to fuck up everything.
|
// Players faking their GUID will be connected for 5 seconds, which allows them to fuck up everything.
|
||||||
// I think we have to perform the verification when clients are still in state 3, but for now it works.
|
// I think we have to perform the verification when clients are still in state 3, but for now it works.
|
||||||
|
|
||||||
// I think we even have to lock the client into state 3 until the verification is done.
|
// I think we even have to lock the client into state 3 until the verification is done.
|
||||||
// Intercepting the entire connection process to perform the authentication within state 3 solely is necessary, due to having a timeout.
|
// Intercepting the entire connection process to perform the authentication within state 3 solely is necessary, due to having a timeout.
|
||||||
// Not sending a response might allow the player to connect for a few seconds (<= 5) until the timeout is reached.
|
// Not sending a response might allow the player to connect for a few seconds (<= 5) until the timeout is reached.
|
||||||
if (client->state >= 5)
|
if (client->state >= 5)
|
||||||
{
|
{
|
||||||
if (info->state == Auth::STATE_NEGOTIATING && (Game::Sys_Milliseconds() - info->time) > 1000 * 5)
|
if (info->state == Auth::STATE_NEGOTIATING && (Game::Sys_Milliseconds() - info->time) > 1000 * 5)
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
info->time = Game::Sys_Milliseconds();
|
info->time = Game::Sys_Milliseconds();
|
||||||
Game::SV_KickClientError(client, "XUID verification timed out!");
|
Game::SV_KickClientError(client, "XUID verification timed out!");
|
||||||
}
|
}
|
||||||
else if (info->state == Auth::STATE_UNKNOWN && info->time && (Game::Sys_Milliseconds() - info->time) > 1000 * 5) // Wait 5 seconds (error delay)
|
else if (info->state == Auth::STATE_UNKNOWN && info->time && (Game::Sys_Milliseconds() - info->time) > 1000 * 5) // Wait 5 seconds (error delay)
|
||||||
{
|
{
|
||||||
if ((client->steamid & 0xFFFFFFFF00000000) != 0x110000100000000)
|
if ((client->steamid & 0xFFFFFFFF00000000) != 0x110000100000000)
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
info->time = Game::Sys_Milliseconds();
|
info->time = Game::Sys_Milliseconds();
|
||||||
Game::SV_KickClientError(client, "Your XUID is invalid!");
|
Game::SV_KickClientError(client, "Your XUID is invalid!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->addr).GetCString());
|
Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->addr).GetCString());
|
||||||
|
|
||||||
info->state = Auth::STATE_NEGOTIATING;
|
info->state = Auth::STATE_NEGOTIATING;
|
||||||
info->time = Game::Sys_Milliseconds();
|
info->time = Game::Sys_Milliseconds();
|
||||||
info->challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
|
info->challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
|
||||||
Network::SendCommand(client->addr, "xuidAuthReq", info->challenge);
|
Network::SendCommand(client->addr, "xuidAuthReq", info->challenge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (info->state == Auth::STATE_UNKNOWN && !info->time)
|
else if (info->state == Auth::STATE_UNKNOWN && !info->time)
|
||||||
{
|
{
|
||||||
info->time = Game::Sys_Milliseconds();
|
info->time = Game::Sys_Milliseconds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (Auth::TokenContainer.generating)
|
if (Auth::TokenContainer.generating)
|
||||||
{
|
{
|
||||||
static int lastCalc = 0;
|
static int lastCalc = 0;
|
||||||
static double mseconds = 0;
|
static double mseconds = 0;
|
||||||
|
|
||||||
if (!lastCalc || (Game::Sys_Milliseconds() - lastCalc) > 500)
|
if (!lastCalc || (Game::Sys_Milliseconds() - lastCalc) > 500)
|
||||||
{
|
{
|
||||||
lastCalc = Game::Sys_Milliseconds();
|
lastCalc = Game::Sys_Milliseconds();
|
||||||
|
|
||||||
int diff = Game::Sys_Milliseconds() - Auth::TokenContainer.startTime;
|
int diff = Game::Sys_Milliseconds() - Auth::TokenContainer.startTime;
|
||||||
double hashPMS = (Auth::TokenContainer.hashes * 1.0) / diff;
|
double hashPMS = (Auth::TokenContainer.hashes * 1.0) / diff;
|
||||||
double requiredHashes = std::pow(2, Auth::TokenContainer.targetLevel + 1) - Auth::TokenContainer.hashes;
|
double requiredHashes = std::pow(2, Auth::TokenContainer.targetLevel + 1) - Auth::TokenContainer.hashes;
|
||||||
mseconds = requiredHashes / hashPMS;
|
mseconds = requiredHashes / hashPMS;
|
||||||
if (mseconds < 0) mseconds = 0;
|
if (mseconds < 0) mseconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", Utils::VA("Increasing security level from %d to %d (est. %s)", Auth::GetSecurityLevel(), Auth::TokenContainer.targetLevel, Utils::FormatTimeSpan(static_cast<int>(mseconds)).data()));
|
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", fmt::sprintf("Increasing security level from %d to %d (est. %s)", Auth::GetSecurityLevel(), Auth::TokenContainer.targetLevel, Utils::String::FormatTimeSpan(static_cast<int>(mseconds)).data()));
|
||||||
}
|
}
|
||||||
else if(Auth::TokenContainer.thread.joinable())
|
else if(Auth::TokenContainer.thread.joinable())
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.thread.join();
|
Auth::TokenContainer.thread.join();
|
||||||
Auth::TokenContainer.generating = false;
|
Auth::TokenContainer.generating = false;
|
||||||
|
|
||||||
Auth::StoreKey();
|
Auth::StoreKey();
|
||||||
Logger::Print("Security level is %d\n", Auth::GetSecurityLevel());
|
Logger::Print("Security level is %d\n", Auth::GetSecurityLevel());
|
||||||
Command::Execute("closemenu security_increase_popmenu", false);
|
Command::Execute("closemenu security_increase_popmenu", false);
|
||||||
|
|
||||||
if (!Auth::TokenContainer.cancel)
|
if (!Auth::TokenContainer.cancel)
|
||||||
{
|
{
|
||||||
if (Auth::TokenContainer.command.empty())
|
if (Auth::TokenContainer.command.empty())
|
||||||
{
|
{
|
||||||
Game::MessageBox(Utils::VA("Your new security level is %d", Auth::GetSecurityLevel()), "Success");
|
Game::MessageBox(fmt::sprintf("Your new security level is %d", Auth::GetSecurityLevel()), "Success");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Command::Execute(Auth::TokenContainer.command, false);
|
Command::Execute(Auth::TokenContainer.command, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::TokenContainer.cancel = false;
|
Auth::TokenContainer.cancel = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::RegisterClient(int clientNum)
|
void Auth::RegisterClient(int clientNum)
|
||||||
{
|
{
|
||||||
if (clientNum >= 18) return;
|
if (clientNum >= 18) return;
|
||||||
|
|
||||||
Network::Address address(Game::svs_clients[clientNum].addr);
|
Network::Address address(Game::svs_clients[clientNum].addr);
|
||||||
|
|
||||||
if (address.GetType() == Game::netadrtype_t::NA_BOT)
|
if (address.GetType() == Game::netadrtype_t::NA_BOT)
|
||||||
{
|
{
|
||||||
Auth::ClientAuthInfo[clientNum].state = Auth::STATE_VALID;
|
Auth::ClientAuthInfo[clientNum].state = Auth::STATE_VALID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Registering client %s\n", address.GetCString());
|
Logger::Print("Registering client %s\n", address.GetCString());
|
||||||
Auth::ClientAuthInfo[clientNum].time = 0;
|
Auth::ClientAuthInfo[clientNum].time = 0;
|
||||||
Auth::ClientAuthInfo[clientNum].state = Auth::STATE_UNKNOWN;
|
Auth::ClientAuthInfo[clientNum].state = Auth::STATE_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Auth::RegisterClientStub()
|
void __declspec(naked) Auth::RegisterClientStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push esi
|
push esi
|
||||||
call Auth::RegisterClient
|
call Auth::RegisterClient
|
||||||
pop esi
|
pop esi
|
||||||
|
|
||||||
imul esi, 366Ch
|
imul esi, 366Ch
|
||||||
mov eax, 478A18h
|
mov eax, 478A18h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Auth::GetKeyHash()
|
unsigned int Auth::GetKeyHash()
|
||||||
{
|
{
|
||||||
Auth::LoadKey();
|
Auth::LoadKey();
|
||||||
return (Utils::Cryptography::JenkinsOneAtATime::Compute(Auth::GuidKey.GetPublicKey()));
|
return (Utils::Cryptography::JenkinsOneAtATime::Compute(Auth::GuidKey.GetPublicKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::StoreKey()
|
void Auth::StoreKey()
|
||||||
{
|
{
|
||||||
if (!Dedicated::IsDedicated() && !ZoneBuilder::IsEnabled())
|
if (!Dedicated::IsDedicated() && !ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
Proto::Auth::Certificate cert;
|
Proto::Auth::Certificate cert;
|
||||||
cert.set_token(Auth::GuidToken.ToString());
|
cert.set_token(Auth::GuidToken.ToString());
|
||||||
cert.set_ctoken(Auth::ComputeToken.ToString());
|
cert.set_ctoken(Auth::ComputeToken.ToString());
|
||||||
cert.set_privatekey(Auth::GuidKey.Export(PK_PRIVATE));
|
cert.set_privatekey(Auth::GuidKey.Export(PK_PRIVATE));
|
||||||
|
|
||||||
Utils::WriteFile("players/guid.dat", cert.SerializeAsString());
|
Utils::IO::WriteFile("players/guid.dat", cert.SerializeAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::LoadKey(bool force)
|
void Auth::LoadKey(bool force)
|
||||||
{
|
{
|
||||||
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) return;
|
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) return;
|
||||||
if (!force && Auth::GuidKey.IsValid()) return;
|
if (!force && Auth::GuidKey.IsValid()) return;
|
||||||
|
|
||||||
Proto::Auth::Certificate cert;
|
Proto::Auth::Certificate cert;
|
||||||
if (cert.ParseFromString(::Utils::ReadFile("players/guid.dat")))
|
if (cert.ParseFromString(::Utils::IO::ReadFile("players/guid.dat")))
|
||||||
{
|
{
|
||||||
Auth::GuidKey.Import(cert.privatekey(), PK_PRIVATE);
|
Auth::GuidKey.Import(cert.privatekey(), PK_PRIVATE);
|
||||||
Auth::GuidToken = cert.token();
|
Auth::GuidToken = cert.token();
|
||||||
Auth::ComputeToken = cert.ctoken();
|
Auth::ComputeToken = cert.ctoken();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Auth::GuidKey.Free();
|
Auth::GuidKey.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Auth::GuidKey.IsValid())
|
if (!Auth::GuidKey.IsValid())
|
||||||
{
|
{
|
||||||
Auth::GuidToken.Clear();
|
Auth::GuidToken.Clear();
|
||||||
Auth::ComputeToken.Clear();
|
Auth::ComputeToken.Clear();
|
||||||
Auth::GuidKey = Utils::Cryptography::ECC::GenerateKey(512);
|
Auth::GuidKey = Utils::Cryptography::ECC::GenerateKey(512);
|
||||||
Auth::StoreKey();
|
Auth::StoreKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Auth::GetSecurityLevel()
|
uint32_t Auth::GetSecurityLevel()
|
||||||
{
|
{
|
||||||
return Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey());
|
return Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::IncreaseSecurityLevel(uint32_t level, std::string command)
|
void Auth::IncreaseSecurityLevel(uint32_t level, std::string command)
|
||||||
{
|
{
|
||||||
if (Auth::GetSecurityLevel() >= level) return;
|
if (Auth::GetSecurityLevel() >= level) return;
|
||||||
|
|
||||||
if (!Auth::TokenContainer.generating)
|
if (!Auth::TokenContainer.generating)
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.cancel = false;
|
Auth::TokenContainer.cancel = false;
|
||||||
Auth::TokenContainer.targetLevel = level;
|
Auth::TokenContainer.targetLevel = level;
|
||||||
Auth::TokenContainer.command = command;
|
Auth::TokenContainer.command = command;
|
||||||
|
|
||||||
// Open menu
|
// Open menu
|
||||||
Command::Execute("openmenu security_increase_popmenu", true);
|
Command::Execute("openmenu security_increase_popmenu", true);
|
||||||
|
|
||||||
// Start thread
|
// Start thread
|
||||||
Auth::TokenContainer.thread = std::thread([&level] ()
|
Auth::TokenContainer.thread = std::thread([&level] ()
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.generating = true;
|
Auth::TokenContainer.generating = true;
|
||||||
Auth::TokenContainer.hashes = 0;
|
Auth::TokenContainer.hashes = 0;
|
||||||
Auth::TokenContainer.startTime = Game::Sys_Milliseconds();
|
Auth::TokenContainer.startTime = Game::Sys_Milliseconds();
|
||||||
Auth::IncrementToken(Auth::GuidToken, Auth::ComputeToken, Auth::GuidKey.GetPublicKey(), Auth::TokenContainer.targetLevel, &Auth::TokenContainer.cancel, &Auth::TokenContainer.hashes);
|
Auth::IncrementToken(Auth::GuidToken, Auth::ComputeToken, Auth::GuidKey.GetPublicKey(), Auth::TokenContainer.targetLevel, &Auth::TokenContainer.cancel, &Auth::TokenContainer.hashes);
|
||||||
Auth::TokenContainer.generating = false;
|
Auth::TokenContainer.generating = false;
|
||||||
|
|
||||||
if (Auth::TokenContainer.cancel)
|
if (Auth::TokenContainer.cancel)
|
||||||
{
|
{
|
||||||
Logger::Print("Token incrementation thread terminated\n");
|
Logger::Print("Token incrementation thread terminated\n");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Auth::GetZeroBits(Utils::Cryptography::Token token, std::string publicKey)
|
uint32_t Auth::GetZeroBits(Utils::Cryptography::Token token, std::string publicKey)
|
||||||
{
|
{
|
||||||
std::string message = publicKey + token.ToString();
|
std::string message = publicKey + token.ToString();
|
||||||
std::string hash = Utils::Cryptography::SHA512::Compute(message, false);
|
std::string hash = Utils::Cryptography::SHA512::Compute(message, false);
|
||||||
|
|
||||||
uint32_t bits = 0;
|
uint32_t bits = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < hash.size(); ++i)
|
for (unsigned int i = 0; i < hash.size(); ++i)
|
||||||
{
|
{
|
||||||
if (hash[i] == '\0')
|
if (hash[i] == '\0')
|
||||||
{
|
{
|
||||||
bits += 8;
|
bits += 8;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t value = static_cast<uint8_t>(hash[i]);
|
uint8_t value = static_cast<uint8_t>(hash[i]);
|
||||||
for (int j = 7; j >= 0; --j)
|
for (int j = 7; j >= 0; --j)
|
||||||
{
|
{
|
||||||
if ((value >> j) & 1)
|
if ((value >> j) & 1)
|
||||||
{
|
{
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
++bits;
|
++bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::IncrementToken(Utils::Cryptography::Token& token, Utils::Cryptography::Token& computeToken, std::string publicKey, uint32_t zeroBits, bool* cancel, uint64_t* count)
|
void Auth::IncrementToken(Utils::Cryptography::Token& token, Utils::Cryptography::Token& computeToken, std::string publicKey, uint32_t zeroBits, bool* cancel, uint64_t* count)
|
||||||
{
|
{
|
||||||
if (zeroBits > 512) return; // Not possible, due to SHA512
|
if (zeroBits > 512) return; // Not possible, due to SHA512
|
||||||
|
|
||||||
if (computeToken < token)
|
if (computeToken < token)
|
||||||
{
|
{
|
||||||
computeToken = token;
|
computeToken = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we already have the desired security level
|
// Check if we already have the desired security level
|
||||||
uint32_t lastLevel = Auth::GetZeroBits(token, publicKey);
|
uint32_t lastLevel = Auth::GetZeroBits(token, publicKey);
|
||||||
uint32_t level = lastLevel;
|
uint32_t level = lastLevel;
|
||||||
if (level >= zeroBits) return;
|
if (level >= zeroBits) return;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
++computeToken;
|
++computeToken;
|
||||||
if (count) ++(*count);
|
if (count) ++(*count);
|
||||||
level = Auth::GetZeroBits(computeToken, publicKey);
|
level = Auth::GetZeroBits(computeToken, publicKey);
|
||||||
|
|
||||||
// Store level if higher than the last one
|
// Store level if higher than the last one
|
||||||
if (level >= lastLevel)
|
if (level >= lastLevel)
|
||||||
{
|
{
|
||||||
token = computeToken;
|
token = computeToken;
|
||||||
lastLevel = level;
|
lastLevel = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow canceling that shit
|
// Allow canceling that shit
|
||||||
if (cancel && *cancel) return;
|
if (cancel && *cancel) return;
|
||||||
}
|
}
|
||||||
while (level < zeroBits);
|
while (level < zeroBits);
|
||||||
|
|
||||||
token = computeToken;
|
token = computeToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::Auth()
|
Auth::Auth()
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.cancel = false;
|
Auth::TokenContainer.cancel = false;
|
||||||
Auth::TokenContainer.generating = false;
|
Auth::TokenContainer.generating = false;
|
||||||
|
|
||||||
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", "");
|
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", "");
|
||||||
|
|
||||||
Auth::LoadKey(true);
|
Auth::LoadKey(true);
|
||||||
|
|
||||||
// Only clients receive the auth request
|
// Only clients receive the auth request
|
||||||
if (!Dedicated::IsDedicated())
|
if (!Dedicated::IsDedicated())
|
||||||
{
|
{
|
||||||
Network::Handle("xuidAuthReq", [] (Network::Address address, std::string data)
|
Network::Handle("xuidAuthReq", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
Logger::Print("Received XUID authentication request from %s\n", address.GetCString());
|
Logger::Print("Received XUID authentication request from %s\n", address.GetCString());
|
||||||
|
|
||||||
// Only accept requests from the server we're connected to
|
// Only accept requests from the server we're connected to
|
||||||
if (address != *Game::connectedHost) return;
|
if (address != *Game::connectedHost) return;
|
||||||
|
|
||||||
// Ensure our certificate is loaded
|
// Ensure our certificate is loaded
|
||||||
Steam::SteamUser()->GetSteamID();
|
Steam::SteamUser()->GetSteamID();
|
||||||
if (!Auth::GuidKey.IsValid()) return;
|
if (!Auth::GuidKey.IsValid()) return;
|
||||||
|
|
||||||
Proto::Auth::Response response;
|
Proto::Auth::Response response;
|
||||||
response.set_token(Auth::GuidToken.ToString());
|
response.set_token(Auth::GuidToken.ToString());
|
||||||
response.set_publickey(Auth::GuidKey.GetPublicKey());
|
response.set_publickey(Auth::GuidKey.GetPublicKey());
|
||||||
response.set_signature(Utils::Cryptography::ECC::SignMessage(Auth::GuidKey, data));
|
response.set_signature(Utils::Cryptography::ECC::SignMessage(Auth::GuidKey, data));
|
||||||
|
|
||||||
Network::SendCommand(address, "xuidAuthResp", response.SerializeAsString());
|
Network::SendCommand(address, "xuidAuthResp", response.SerializeAsString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Handle("xuidAuthResp", [] (Network::Address address, std::string data)
|
Network::Handle("xuidAuthResp", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
Logger::Print("Received XUID authentication response from %s\n", address.GetCString());
|
Logger::Print("Received XUID authentication response from %s\n", address.GetCString());
|
||||||
|
|
||||||
for (int i = 0; i < *Game::svs_numclients; i++)
|
for (int i = 0; i < *Game::svs_numclients; i++)
|
||||||
{
|
{
|
||||||
Game::client_t* client = &Game::svs_clients[i];
|
Game::client_t* client = &Game::svs_clients[i];
|
||||||
Auth::AuthInfo* info = &Auth::ClientAuthInfo[i];
|
Auth::AuthInfo* info = &Auth::ClientAuthInfo[i];
|
||||||
|
|
||||||
if (client->state >= 3 && address == client->addr && info->state == Auth::STATE_NEGOTIATING)
|
if (client->state >= 3 && address == client->addr && info->state == Auth::STATE_NEGOTIATING)
|
||||||
{
|
{
|
||||||
Proto::Auth::Response response;
|
Proto::Auth::Response response;
|
||||||
unsigned int id = static_cast<unsigned int>(~0x110000100000000 & client->steamid);
|
unsigned int id = static_cast<unsigned int>(~0x110000100000000 & client->steamid);
|
||||||
|
|
||||||
// Check if response is valid
|
// Check if response is valid
|
||||||
if (!response.ParseFromString(data) || response.signature().empty() || response.publickey().empty() || response.token().empty())
|
if (!response.ParseFromString(data) || response.signature().empty() || response.publickey().empty() || response.token().empty())
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
Game::SV_KickClientError(client, "XUID authentication response was invalid!");
|
Game::SV_KickClientError(client, "XUID authentication response was invalid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if guid matches the certificate
|
// Check if guid matches the certificate
|
||||||
else if (id != (Utils::Cryptography::JenkinsOneAtATime::Compute(response.publickey()) & ~0x80000000))
|
else if (id != (Utils::Cryptography::JenkinsOneAtATime::Compute(response.publickey()) & ~0x80000000))
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
Game::SV_KickClientError(client, "XUID doesn't match the certificate!");
|
Game::SV_KickClientError(client, "XUID doesn't match the certificate!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify GUID using the signature and certificate
|
// Verify GUID using the signature and certificate
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info->publicKey.Set(response.publickey());
|
info->publicKey.Set(response.publickey());
|
||||||
|
|
||||||
if (Utils::Cryptography::ECC::VerifyMessage(info->publicKey, info->challenge, response.signature()))
|
if (Utils::Cryptography::ECC::VerifyMessage(info->publicKey, info->challenge, response.signature()))
|
||||||
{
|
{
|
||||||
uint32_t ourLevel = static_cast<uint32_t>(Dvar::Var("sv_securityLevel").Get<int>());
|
uint32_t ourLevel = static_cast<uint32_t>(Dvar::Var("sv_securityLevel").Get<int>());
|
||||||
uint32_t userLevel = Auth::GetZeroBits(response.token(), response.publickey());
|
uint32_t userLevel = Auth::GetZeroBits(response.token(), response.publickey());
|
||||||
|
|
||||||
if (userLevel >= ourLevel)
|
if (userLevel >= ourLevel)
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_VALID;
|
info->state = Auth::STATE_VALID;
|
||||||
Logger::Print("Verified XUID %llX (%d) from %s\n", client->steamid, userLevel, address.GetCString());
|
Logger::Print("Verified XUID %llX (%d) from %s\n", client->steamid, userLevel, address.GetCString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
Game::SV_KickClientError(client, Utils::VA("Your security level (%d) is lower than the server's security level (%d)", userLevel, ourLevel));
|
Game::SV_KickClientError(client, fmt::sprintf("Your security level (%d) is lower than the server's security level (%d)", userLevel, ourLevel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info->state = Auth::STATE_INVALID;
|
info->state = Auth::STATE_INVALID;
|
||||||
Game::SV_KickClientError(client, "Challenge signature was invalid!");
|
Game::SV_KickClientError(client, "Challenge signature was invalid!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Install frame handlers
|
// Install frame handlers
|
||||||
QuickPatch::OnFrame(Auth::Frame);
|
QuickPatch::OnFrame(Auth::Frame);
|
||||||
|
|
||||||
// Register dvar
|
// Register dvar
|
||||||
Dvar::Register<int>("sv_securityLevel", 23, 0, 512, Game::dvar_flag::DVAR_FLAG_SERVERINFO, "Security level for GUID certificates (POW)");
|
Dvar::Register<int>("sv_securityLevel", 23, 0, 512, Game::dvar_flag::DVAR_FLAG_SERVERINFO, "Security level for GUID certificates (POW)");
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
// Install registration hook
|
// Install registration hook
|
||||||
Utils::Hook(0x478A12, Auth::RegisterClientStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x478A12, Auth::RegisterClientStub, HOOK_JUMP).Install()->Quick();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Guid command
|
// Guid command
|
||||||
Command::Add("guid", [] (Command::Params params)
|
Command::Add("guid", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
Logger::Print("Your guid: %llX\n", Steam::SteamUser()->GetSteamID().Bits);
|
Logger::Print("Your guid: %llX\n", Steam::SteamUser()->GetSteamID().Bits);
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::Add("securityLevel", [] (Command::Params params)
|
Command::Add("securityLevel", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2)
|
if (params.Length() < 2)
|
||||||
{
|
{
|
||||||
uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey());
|
uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey());
|
||||||
Logger::Print("Your current security level is %d\n", level);
|
Logger::Print("Your current security level is %d\n", level);
|
||||||
Logger::Print("Your security token is: %s\n", Utils::DumpHex(Auth::GuidToken.ToString(), "").data());
|
Logger::Print("Your security token is: %s\n", Utils::String::DumpHex(Auth::GuidToken.ToString(), "").data());
|
||||||
Logger::Print("Your computation token is: %s\n", Utils::DumpHex(Auth::ComputeToken.ToString(), "").data());
|
Logger::Print("Your computation token is: %s\n", Utils::String::DumpHex(Auth::ComputeToken.ToString(), "").data());
|
||||||
|
|
||||||
Toast::Show("cardicon_locked", "^5Security Level", Utils::VA("Your security level is %d", level), 3000);
|
Toast::Show("cardicon_locked", "^5Security Level", fmt::sprintf("Your security level is %d", level), 3000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t level = static_cast<uint32_t>(atoi(params[1]));
|
uint32_t level = static_cast<uint32_t>(atoi(params[1]));
|
||||||
Auth::IncreaseSecurityLevel(level);
|
Auth::IncreaseSecurityLevel(level);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
UIScript::Add("security_increase_cancel", [] ()
|
UIScript::Add("security_increase_cancel", [] ()
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.cancel = true;
|
Auth::TokenContainer.cancel = true;
|
||||||
Logger::Print("Token incrementation process canceled!\n");
|
Logger::Print("Token incrementation process canceled!\n");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::~Auth()
|
Auth::~Auth()
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.cancel = true;
|
Auth::TokenContainer.cancel = true;
|
||||||
Auth::TokenContainer.generating = false;
|
Auth::TokenContainer.generating = false;
|
||||||
|
|
||||||
// Terminate thread
|
// Terminate thread
|
||||||
if (Auth::TokenContainer.thread.joinable())
|
if (Auth::TokenContainer.thread.joinable())
|
||||||
{
|
{
|
||||||
Auth::TokenContainer.thread.join();
|
Auth::TokenContainer.thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::StoreKey();
|
Auth::StoreKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Auth::UnitTest()
|
bool Auth::UnitTest()
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
printf("Testing logical token operators:\n");
|
printf("Testing logical token operators:\n");
|
||||||
|
|
||||||
Utils::Cryptography::Token token1;
|
Utils::Cryptography::Token token1;
|
||||||
Utils::Cryptography::Token token2;
|
Utils::Cryptography::Token token2;
|
||||||
++token1, token2++; // Test incrementation operator
|
++token1, token2++; // Test incrementation operator
|
||||||
|
|
||||||
printf("Operator == : ");
|
printf("Operator == : ");
|
||||||
if (token1 == token2 && !(++token1 == token2)) printf("Success\n");
|
if (token1 == token2 && !(++token1 == token2)) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Operator != : ");
|
printf("Operator != : ");
|
||||||
if (token1 != token2 && !(++token2 != token1)) printf("Success\n");
|
if (token1 != token2 && !(++token2 != token1)) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Operator >= : ");
|
printf("Operator >= : ");
|
||||||
if (token1 >= token2 && ++token1 >= token2) printf("Success\n");
|
if (token1 >= token2 && ++token1 >= token2) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Operator > : ");
|
printf("Operator > : ");
|
||||||
if (token1 > token2) printf("Success\n");
|
if (token1 > token2) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Operator <= : ");
|
printf("Operator <= : ");
|
||||||
if (token1 <= ++token2 && token1 <= ++token2) printf("Success\n");
|
if (token1 <= ++token2 && token1 <= ++token2) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Operator < : ");
|
printf("Operator < : ");
|
||||||
if (token1 < token2) printf("Success\n");
|
if (token1 < token2) printf("Success\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Error\n");
|
printf("Error\n");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,137 +1,137 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::vector<Game::cmd_function_t*> Command::Functions;
|
std::vector<Game::cmd_function_t*> Command::Functions;
|
||||||
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMap;
|
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMap;
|
||||||
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMapSV;
|
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMapSV;
|
||||||
|
|
||||||
char* Command::Params::operator[](size_t index)
|
char* Command::Params::operator[](size_t index)
|
||||||
{
|
{
|
||||||
if (index >= this->Length()) return "";
|
if (index >= this->Length()) return "";
|
||||||
if (this->IsSV) return Game::cmd_argv_sv[this->CommandId][index];
|
if (this->IsSV) return Game::cmd_argv_sv[this->CommandId][index];
|
||||||
else return Game::cmd_argv[this->CommandId][index];
|
else return Game::cmd_argv[this->CommandId][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Command::Params::Length()
|
size_t Command::Params::Length()
|
||||||
{
|
{
|
||||||
if (this->IsSV) return Game::cmd_argc_sv[this->CommandId];
|
if (this->IsSV) return Game::cmd_argc_sv[this->CommandId];
|
||||||
else return Game::cmd_argc[this->CommandId];
|
else return Game::cmd_argc[this->CommandId];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Command::Params::Join(size_t startIndex)
|
std::string Command::Params::Join(size_t startIndex)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
for (size_t i = startIndex; i < this->Length(); ++i)
|
for (size_t i = startIndex; i < this->Length(); ++i)
|
||||||
{
|
{
|
||||||
if (i > startIndex) result.append(" ");
|
if (i > startIndex) result.append(" ");
|
||||||
result.append(this->operator[](i));
|
result.append(this->operator[](i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::Add(const char* name, Command::Callback* callback)
|
void Command::Add(const char* name, Command::Callback* callback)
|
||||||
{
|
{
|
||||||
std::string command = Utils::StrToLower(name);
|
std::string command = Utils::String::StrToLower(name);
|
||||||
|
|
||||||
if (Command::FunctionMap.find(command) == Command::FunctionMap.end())
|
if (Command::FunctionMap.find(command) == Command::FunctionMap.end())
|
||||||
{
|
{
|
||||||
Command::AddRaw(name, Command::MainCallback);
|
Command::AddRaw(name, Command::MainCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::FunctionMap[command] = callback;
|
Command::FunctionMap[command] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::AddSV(const char* name, Command::Callback* callback)
|
void Command::AddSV(const char* name, Command::Callback* callback)
|
||||||
{
|
{
|
||||||
std::string command = Utils::StrToLower(name);
|
std::string command = Utils::String::StrToLower(name);
|
||||||
|
|
||||||
if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end())
|
if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end())
|
||||||
{
|
{
|
||||||
Command::AddRawSV(name, Command::MainCallbackSV);
|
Command::AddRawSV(name, Command::MainCallbackSV);
|
||||||
|
|
||||||
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
|
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
|
||||||
Command::AddRaw(name, Game::Cbuf_AddServerText);
|
Command::AddRaw(name, Game::Cbuf_AddServerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::FunctionMapSV[command] = callback;
|
Command::FunctionMapSV[command] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::AddRaw(const char* name, void(*callback)())
|
void Command::AddRaw(const char* name, void(*callback)())
|
||||||
{
|
{
|
||||||
Game::Cmd_AddCommand(name, callback, Command::Allocate(), 0);
|
Game::Cmd_AddCommand(name, callback, Command::Allocate(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::AddRawSV(const char* name, void(*callback)())
|
void Command::AddRawSV(const char* name, void(*callback)())
|
||||||
{
|
{
|
||||||
Game::Cmd_AddServerCommand(name, callback, Command::Allocate());
|
Game::Cmd_AddServerCommand(name, callback, Command::Allocate());
|
||||||
|
|
||||||
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
|
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
|
||||||
Command::AddRaw(name, Game::Cbuf_AddServerText);
|
Command::AddRaw(name, Game::Cbuf_AddServerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::Execute(std::string command, bool sync)
|
void Command::Execute(std::string command, bool sync)
|
||||||
{
|
{
|
||||||
command.append("\n"); // Make sure it's terminated
|
command.append("\n"); // Make sure it's terminated
|
||||||
|
|
||||||
if (sync)
|
if (sync)
|
||||||
{
|
{
|
||||||
Game::Cmd_ExecuteSingleCommand(0, 0, command.data());
|
Game::Cmd_ExecuteSingleCommand(0, 0, command.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game::Cbuf_AddText(0, command.data());
|
Game::Cbuf_AddText(0, command.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::cmd_function_t* Command::Allocate()
|
Game::cmd_function_t* Command::Allocate()
|
||||||
{
|
{
|
||||||
Game::cmd_function_t* cmd = new Game::cmd_function_t;
|
Game::cmd_function_t* cmd = new Game::cmd_function_t;
|
||||||
Command::Functions.push_back(cmd);
|
Command::Functions.push_back(cmd);
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::MainCallback()
|
void Command::MainCallback()
|
||||||
{
|
{
|
||||||
Command::Params params(false, *Game::cmd_id);
|
Command::Params params(false, *Game::cmd_id);
|
||||||
|
|
||||||
std::string command = Utils::StrToLower(params[0]);
|
std::string command = Utils::String::StrToLower(params[0]);
|
||||||
|
|
||||||
if (Command::FunctionMap.find(command) != Command::FunctionMap.end())
|
if (Command::FunctionMap.find(command) != Command::FunctionMap.end())
|
||||||
{
|
{
|
||||||
Command::FunctionMap[command](params);
|
Command::FunctionMap[command](params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command::MainCallbackSV()
|
void Command::MainCallbackSV()
|
||||||
{
|
{
|
||||||
Command::Params params(true, *Game::cmd_id_sv);
|
Command::Params params(true, *Game::cmd_id_sv);
|
||||||
|
|
||||||
std::string command = Utils::StrToLower(params[0]);
|
std::string command = Utils::String::StrToLower(params[0]);
|
||||||
|
|
||||||
if (Command::FunctionMapSV.find(command) != Command::FunctionMapSV.end())
|
if (Command::FunctionMapSV.find(command) != Command::FunctionMapSV.end())
|
||||||
{
|
{
|
||||||
Command::FunctionMapSV[command](params);
|
Command::FunctionMapSV[command](params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Command()
|
Command::Command()
|
||||||
{
|
{
|
||||||
// TODO: Add commands here?
|
// TODO: Add commands here?
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::~Command()
|
Command::~Command()
|
||||||
{
|
{
|
||||||
for (auto command : Command::Functions)
|
for (auto command : Command::Functions)
|
||||||
{
|
{
|
||||||
delete command;
|
delete command;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Functions.clear();
|
Command::Functions.clear();
|
||||||
Command::FunctionMap.clear();
|
Command::FunctionMap.clear();
|
||||||
Command::FunctionMapSV.clear();
|
Command::FunctionMapSV.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,234 +1,234 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
ConnectProtocol::Container ConnectProtocol::ConnectContainer = { false, false, "" };
|
ConnectProtocol::Container ConnectProtocol::ConnectContainer = { false, false, "" };
|
||||||
|
|
||||||
bool ConnectProtocol::Evaluated()
|
bool ConnectProtocol::Evaluated()
|
||||||
{
|
{
|
||||||
return ConnectProtocol::ConnectContainer.Evaluated;
|
return ConnectProtocol::ConnectContainer.Evaluated;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectProtocol::Used()
|
bool ConnectProtocol::Used()
|
||||||
{
|
{
|
||||||
if (!ConnectProtocol::Evaluated())
|
if (!ConnectProtocol::Evaluated())
|
||||||
{
|
{
|
||||||
ConnectProtocol::EvaluateProtocol();
|
ConnectProtocol::EvaluateProtocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ConnectProtocol::ConnectContainer.ConnectString.size() > 0);
|
return (ConnectProtocol::ConnectContainer.ConnectString.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectProtocol::InstallProtocol()
|
bool ConnectProtocol::InstallProtocol()
|
||||||
{
|
{
|
||||||
HKEY hKey = NULL;
|
HKEY hKey = NULL;
|
||||||
std::string data;
|
std::string data;
|
||||||
|
|
||||||
char ownPth[MAX_PATH] = { 0 };
|
char ownPth[MAX_PATH] = { 0 };
|
||||||
char workdir[MAX_PATH] = { 0 };
|
char workdir[MAX_PATH] = { 0 };
|
||||||
|
|
||||||
DWORD dwsize = MAX_PATH;
|
DWORD dwsize = MAX_PATH;
|
||||||
HMODULE hModule = GetModuleHandle(NULL);
|
HMODULE hModule = GetModuleHandle(NULL);
|
||||||
|
|
||||||
if (hModule != NULL)
|
if (hModule != NULL)
|
||||||
{
|
{
|
||||||
if (GetModuleFileNameA(hModule, ownPth, MAX_PATH) == ERROR)
|
if (GetModuleFileNameA(hModule, ownPth, MAX_PATH) == ERROR)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetModuleFileNameA(hModule, workdir, MAX_PATH) == ERROR)
|
if (GetModuleFileNameA(hModule, workdir, MAX_PATH) == ERROR)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* endPtr = strstr(workdir, "iw4x.exe");
|
char* endPtr = strstr(workdir, "iw4x.exe");
|
||||||
if (endPtr != NULL)
|
if (endPtr != NULL)
|
||||||
{
|
{
|
||||||
*endPtr = 0;
|
*endPtr = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentDirectoryA(workdir);
|
SetCurrentDirectoryA(workdir);
|
||||||
|
|
||||||
LONG openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x\\shell\\open\\command", 0, KEY_ALL_ACCESS, &hKey);
|
LONG openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x\\shell\\open\\command", 0, KEY_ALL_ACCESS, &hKey);
|
||||||
if (openRes == ERROR_SUCCESS)
|
if (openRes == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
char regred[MAX_PATH] = { 0 };
|
char regred[MAX_PATH] = { 0 };
|
||||||
|
|
||||||
// Check if the game has been moved.
|
// Check if the game has been moved.
|
||||||
openRes = RegQueryValueExA(hKey, 0, 0, 0, reinterpret_cast<BYTE*>(regred), &dwsize);
|
openRes = RegQueryValueExA(hKey, 0, 0, 0, reinterpret_cast<BYTE*>(regred), &dwsize);
|
||||||
if (openRes == ERROR_SUCCESS)
|
if (openRes == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
char* endPtr = strstr(regred, "\" \"%1\"");
|
char* endPtr = strstr(regred, "\" \"%1\"");
|
||||||
if (endPtr != NULL)
|
if (endPtr != NULL)
|
||||||
{
|
{
|
||||||
*endPtr = 0;
|
*endPtr = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
if (strcmp(regred + 1, ownPth))
|
if (strcmp(regred + 1, ownPth))
|
||||||
{
|
{
|
||||||
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open SOFTWARE\\Classes
|
// Open SOFTWARE\\Classes
|
||||||
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &hKey);
|
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &hKey);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create SOFTWARE\\Classes\\iw4x
|
// Create SOFTWARE\\Classes\\iw4x
|
||||||
openRes = RegCreateKeyExA(hKey, "iw4x", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
openRes = RegCreateKeyExA(hKey, "iw4x", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write URL:IW4x Protocol
|
// Write URL:IW4x Protocol
|
||||||
data = "URL:IW4x Protocol";
|
data = "URL:IW4x Protocol";
|
||||||
openRes = RegSetValueExA(hKey, "URL Protocol", 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
openRes = RegSetValueExA(hKey, "URL Protocol", 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create SOFTWARE\\Classes\\iw4x\\DefaultIcon
|
// Create SOFTWARE\\Classes\\iw4x\\DefaultIcon
|
||||||
openRes = RegCreateKeyExA(hKey, "DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
openRes = RegCreateKeyExA(hKey, "DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = Utils::VA("%s,1", ownPth);
|
data = fmt::sprintf("%s,1", ownPth);
|
||||||
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x", 0, KEY_ALL_ACCESS, &hKey);
|
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x", 0, KEY_ALL_ACCESS, &hKey);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
openRes = RegCreateKeyExA(hKey, "shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
openRes = RegCreateKeyExA(hKey, "shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = Utils::VA("\"%s\" \"%s\"", ownPth, "%1");
|
data = fmt::sprintf("\"%s\" \"%s\"", ownPth, "%1");
|
||||||
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
if (openRes != ERROR_SUCCESS)
|
if (openRes != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectProtocol::EvaluateProtocol()
|
void ConnectProtocol::EvaluateProtocol()
|
||||||
{
|
{
|
||||||
if (ConnectProtocol::ConnectContainer.Evaluated) return;
|
if (ConnectProtocol::ConnectContainer.Evaluated) return;
|
||||||
ConnectProtocol::ConnectContainer.Evaluated = true;
|
ConnectProtocol::ConnectContainer.Evaluated = true;
|
||||||
|
|
||||||
std::string cmdLine = GetCommandLineA();
|
std::string cmdLine = GetCommandLineA();
|
||||||
|
|
||||||
auto pos = cmdLine.find("iw4x://");
|
auto pos = cmdLine.find("iw4x://");
|
||||||
|
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
cmdLine = cmdLine.substr(pos + 7);
|
cmdLine = cmdLine.substr(pos + 7);
|
||||||
pos = cmdLine.find_first_of("/");
|
pos = cmdLine.find_first_of("/");
|
||||||
|
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
cmdLine = cmdLine.substr(0, pos);
|
cmdLine = cmdLine.substr(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectProtocol::ConnectContainer.ConnectString = cmdLine;
|
ConnectProtocol::ConnectContainer.ConnectString = cmdLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectProtocol::ConnectProtocol()
|
ConnectProtocol::ConnectProtocol()
|
||||||
{
|
{
|
||||||
// IPC handler
|
// IPC handler
|
||||||
IPCPipe::On("connect", [] (std::string data)
|
IPCPipe::On("connect", [] (std::string data)
|
||||||
{
|
{
|
||||||
Command::Execute(Utils::VA("connect %s", data.data()), false);
|
Command::Execute(fmt::sprintf("connect %s", data.data()), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Invocation handler
|
// Invocation handler
|
||||||
// TODO: Don't call it every frame, once is enough!
|
// TODO: Don't call it every frame, once is enough!
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
if (!ConnectProtocol::ConnectContainer.Invoked && ConnectProtocol::Used())
|
if (!ConnectProtocol::ConnectContainer.Invoked && ConnectProtocol::Used())
|
||||||
{
|
{
|
||||||
ConnectProtocol::ConnectContainer.Invoked = true;
|
ConnectProtocol::ConnectContainer.Invoked = true;
|
||||||
Command::Execute(Utils::VA("connect %s", ConnectProtocol::ConnectContainer.ConnectString.data()), false);
|
Command::Execute(fmt::sprintf("connect %s", ConnectProtocol::ConnectContainer.ConnectString.data()), false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ConnectProtocol::InstallProtocol();
|
ConnectProtocol::InstallProtocol();
|
||||||
ConnectProtocol::EvaluateProtocol();
|
ConnectProtocol::EvaluateProtocol();
|
||||||
|
|
||||||
// Fire protocol handlers
|
// Fire protocol handlers
|
||||||
// Make sure this happens after the pipe-initialization!
|
// Make sure this happens after the pipe-initialization!
|
||||||
if (ConnectProtocol::Used())
|
if (ConnectProtocol::Used())
|
||||||
{
|
{
|
||||||
if (!Singleton::IsFirstInstance())
|
if (!Singleton::IsFirstInstance())
|
||||||
{
|
{
|
||||||
IPCPipe::Write("connect", ConnectProtocol::ConnectContainer.ConnectString);
|
IPCPipe::Write("connect", ConnectProtocol::ConnectContainer.ConnectString);
|
||||||
ExitProcess(0);
|
ExitProcess(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only skip intro here, invocation will be done later.
|
// Only skip intro here, invocation will be done later.
|
||||||
Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
|
Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,411 +1,411 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameSignal;
|
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameSignal;
|
||||||
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameOnceSignal;
|
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameOnceSignal;
|
||||||
|
|
||||||
bool Dedicated::SendChat;
|
bool Dedicated::SendChat;
|
||||||
|
|
||||||
bool Dedicated::IsDedicated()
|
bool Dedicated::IsDedicated()
|
||||||
{
|
{
|
||||||
return Flags::HasFlag("dedicated");
|
return Flags::HasFlag("dedicated");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::InitDedicatedServer()
|
void Dedicated::InitDedicatedServer()
|
||||||
{
|
{
|
||||||
static const char* fastfiles[7] =
|
static const char* fastfiles[7] =
|
||||||
{
|
{
|
||||||
"code_post_gfx_mp",
|
"code_post_gfx_mp",
|
||||||
"localized_code_post_gfx_mp",
|
"localized_code_post_gfx_mp",
|
||||||
"ui_mp",
|
"ui_mp",
|
||||||
"localized_ui_mp",
|
"localized_ui_mp",
|
||||||
"common_mp",
|
"common_mp",
|
||||||
"localized_common_mp",
|
"localized_common_mp",
|
||||||
"patch_mp"
|
"patch_mp"
|
||||||
};
|
};
|
||||||
|
|
||||||
std::memcpy(reinterpret_cast<void*>(0x66E1CB0), &fastfiles, sizeof(fastfiles));
|
std::memcpy(reinterpret_cast<void*>(0x66E1CB0), &fastfiles, sizeof(fastfiles));
|
||||||
Game::R_LoadGraphicsAssets();
|
Game::R_LoadGraphicsAssets();
|
||||||
|
|
||||||
Utils::Hook::Call<void()>(0x4F84C0)();
|
Utils::Hook::Call<void()>(0x4F84C0)();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::PostInitialization()
|
void Dedicated::PostInitialization()
|
||||||
{
|
{
|
||||||
Command::Execute("exec autoexec.cfg");
|
Command::Execute("exec autoexec.cfg");
|
||||||
Command::Execute("onlinegame 1");
|
Command::Execute("onlinegame 1");
|
||||||
Command::Execute("exec default_xboxlive.cfg");
|
Command::Execute("exec default_xboxlive.cfg");
|
||||||
Command::Execute("xblive_rankedmatch 1");
|
Command::Execute("xblive_rankedmatch 1");
|
||||||
Command::Execute("xblive_privatematch 1");
|
Command::Execute("xblive_privatematch 1");
|
||||||
Command::Execute("xblive_privateserver 0");
|
Command::Execute("xblive_privateserver 0");
|
||||||
Command::Execute("xstartprivatematch");
|
Command::Execute("xstartprivatematch");
|
||||||
//Command::Execute("xstartlobby");
|
//Command::Execute("xstartlobby");
|
||||||
Command::Execute("sv_network_fps 1000");
|
Command::Execute("sv_network_fps 1000");
|
||||||
Command::Execute("com_maxfps 125");
|
Command::Execute("com_maxfps 125");
|
||||||
|
|
||||||
// Process command line?
|
// Process command line?
|
||||||
Utils::Hook::Call<void()>(0x60C3D0)();
|
Utils::Hook::Call<void()>(0x60C3D0)();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Dedicated::PostInitializationStub()
|
void __declspec(naked) Dedicated::PostInitializationStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
call Dedicated::PostInitialization
|
call Dedicated::PostInitialization
|
||||||
|
|
||||||
// Start Com_EvenLoop
|
// Start Com_EvenLoop
|
||||||
mov eax, 43D140h
|
mov eax, 43D140h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Dedicated::EvaluateSay(char* text)
|
const char* Dedicated::EvaluateSay(char* text)
|
||||||
{
|
{
|
||||||
Dedicated::SendChat = true;
|
Dedicated::SendChat = true;
|
||||||
|
|
||||||
if (text[1] == '/')
|
if (text[1] == '/')
|
||||||
{
|
{
|
||||||
Dedicated::SendChat = false;
|
Dedicated::SendChat = false;
|
||||||
text[1] = text[0];
|
text[1] = text[0];
|
||||||
++text;
|
++text;
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Dedicated::PreSayStub()
|
void __declspec(naked) Dedicated::PreSayStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, [esp + 100h + 10h]
|
mov eax, [esp + 100h + 10h]
|
||||||
|
|
||||||
push eax
|
push eax
|
||||||
call EvaluateSay
|
call EvaluateSay
|
||||||
add esp, 4h
|
add esp, 4h
|
||||||
|
|
||||||
mov [esp + 100h + 10h], eax
|
mov [esp + 100h + 10h], eax
|
||||||
|
|
||||||
jmp Colors::CleanStrStub
|
jmp Colors::CleanStrStub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Dedicated::PostSayStub()
|
void __declspec(naked) Dedicated::PostSayStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
// eax is used by the callee
|
// eax is used by the callee
|
||||||
push eax
|
push eax
|
||||||
|
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov al, Dedicated::SendChat
|
mov al, Dedicated::SendChat
|
||||||
|
|
||||||
test al, al
|
test al, al
|
||||||
jnz return
|
jnz return
|
||||||
|
|
||||||
// Don't send the chat
|
// Don't send the chat
|
||||||
pop eax
|
pop eax
|
||||||
retn
|
retn
|
||||||
|
|
||||||
return:
|
return:
|
||||||
pop eax
|
pop eax
|
||||||
|
|
||||||
// Jump to the target
|
// Jump to the target
|
||||||
push 5DF620h
|
push 5DF620h
|
||||||
retn
|
retn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::MapRotate()
|
void Dedicated::MapRotate()
|
||||||
{
|
{
|
||||||
if (!Dedicated::IsDedicated() && Dvar::Var("sv_dontrotate").Get<bool>())
|
if (!Dedicated::IsDedicated() && Dvar::Var("sv_dontrotate").Get<bool>())
|
||||||
{
|
{
|
||||||
Dvar::Var("sv_dontrotate").SetRaw(0);
|
Dvar::Var("sv_dontrotate").SetRaw(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>())
|
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>())
|
||||||
{
|
{
|
||||||
Logger::Print("Not performing map rotation as we are hosting a party!\n");
|
Logger::Print("Not performing map rotation as we are hosting a party!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print("Rotating map...\n");
|
Logger::Print("Rotating map...\n");
|
||||||
|
|
||||||
// if nothing, just restart
|
// if nothing, just restart
|
||||||
if (Dvar::Var("sv_mapRotation").Get<std::string>().empty())
|
if (Dvar::Var("sv_mapRotation").Get<std::string>().empty())
|
||||||
{
|
{
|
||||||
Logger::Print("No rotation defined, restarting map.\n");
|
Logger::Print("No rotation defined, restarting map.\n");
|
||||||
Command::Execute(Utils::VA("map %s", Dvar::Var("mapname").Get<const char*>()), true);
|
Command::Execute(fmt::sprintf("map %s", Dvar::Var("mapname").Get<const char*>()), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, check if the string contains nothing
|
// first, check if the string contains nothing
|
||||||
if (Dvar::Var("sv_mapRotationCurrent").Get<std::string>().empty())
|
if (Dvar::Var("sv_mapRotationCurrent").Get<std::string>().empty())
|
||||||
{
|
{
|
||||||
Logger::Print("Current map rotation has finished, reloading...\n");
|
Logger::Print("Current map rotation has finished, reloading...\n");
|
||||||
Dvar::Var("sv_mapRotationCurrent").Set(Dvar::Var("sv_mapRotation").Get<const char*>());
|
Dvar::Var("sv_mapRotationCurrent").Set(Dvar::Var("sv_mapRotation").Get<const char*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rotation = Dvar::Var("sv_mapRotationCurrent").Get<std::string>();
|
std::string rotation = Dvar::Var("sv_mapRotationCurrent").Get<std::string>();
|
||||||
|
|
||||||
auto tokens = Utils::Explode(rotation, ' ');
|
auto tokens = Utils::String::Explode(rotation, ' ');
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (tokens.size() - 1); i += 2)
|
for (unsigned int i = 0; i < (tokens.size() - 1); i += 2)
|
||||||
{
|
{
|
||||||
if (i + 1 >= tokens.size())
|
if (i + 1 >= tokens.size())
|
||||||
{
|
{
|
||||||
Dvar::Var("sv_mapRotationCurrent").Set("");
|
Dvar::Var("sv_mapRotationCurrent").Set("");
|
||||||
Command::Execute("map_rotate", true);
|
Command::Execute("map_rotate", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string key = tokens[i];
|
std::string key = tokens[i];
|
||||||
std::string value = tokens[i + 1];
|
std::string value = tokens[i + 1];
|
||||||
|
|
||||||
if (key == "map")
|
if (key == "map")
|
||||||
{
|
{
|
||||||
// Rebuild map rotation string
|
// Rebuild map rotation string
|
||||||
rotation.clear();
|
rotation.clear();
|
||||||
for (unsigned int j = (i + 2); j < tokens.size(); ++j)
|
for (unsigned int j = (i + 2); j < tokens.size(); ++j)
|
||||||
{
|
{
|
||||||
if (j != (i + 2)) rotation += " ";
|
if (j != (i + 2)) rotation += " ";
|
||||||
rotation += tokens[j];
|
rotation += tokens[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
Dvar::Var("sv_mapRotationCurrent").Set(rotation);
|
Dvar::Var("sv_mapRotationCurrent").Set(rotation);
|
||||||
|
|
||||||
Logger::Print("Loading new map: %s\n", value.data());
|
Logger::Print("Loading new map: %s\n", value.data());
|
||||||
Command::Execute(Utils::VA("map %s", value.data()), true);
|
Command::Execute(fmt::sprintf("map %s", value.data()), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (key == "gametype")
|
else if (key == "gametype")
|
||||||
{
|
{
|
||||||
Logger::Print("Applying new gametype: %s\n", value.data());
|
Logger::Print("Applying new gametype: %s\n", value.data());
|
||||||
Dvar::Var("g_gametype").Set(value);
|
Dvar::Var("g_gametype").Set(value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Unsupported maprotation key '%s', motherfucker!\n", key.data());
|
Logger::Print("Unsupported maprotation key '%s', motherfucker!\n", key.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::Heartbeat()
|
void Dedicated::Heartbeat()
|
||||||
{
|
{
|
||||||
int masterPort = Dvar::Var("masterPort").Get<int>();
|
int masterPort = Dvar::Var("masterPort").Get<int>();
|
||||||
const char* masterServerName = Dvar::Var("masterServerName").Get<const char*>();
|
const char* masterServerName = Dvar::Var("masterServerName").Get<const char*>();
|
||||||
|
|
||||||
Network::Address master(Utils::VA("%s:%u", masterServerName, masterPort));
|
Network::Address master(fmt::sprintf("%s:%u", masterServerName, masterPort));
|
||||||
|
|
||||||
Logger::Print("Sending heartbeat to master: %s:%u\n", masterServerName, masterPort);
|
Logger::Print("Sending heartbeat to master: %s:%u\n", masterServerName, masterPort);
|
||||||
Network::SendCommand(master, "heartbeat", "IW4");
|
Network::SendCommand(master, "heartbeat", "IW4");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::Once(Dedicated::Callback* callback)
|
void Dedicated::Once(Dedicated::Callback* callback)
|
||||||
{
|
{
|
||||||
Dedicated::FrameOnceSignal.connect(callback);
|
Dedicated::FrameOnceSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::OnFrame(Dedicated::Callback* callback)
|
void Dedicated::OnFrame(Dedicated::Callback* callback)
|
||||||
{
|
{
|
||||||
Dedicated::FrameSignal.connect(callback);
|
Dedicated::FrameSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::FrameStub()
|
void Dedicated::FrameStub()
|
||||||
{
|
{
|
||||||
Dedicated::FrameSignal();
|
Dedicated::FrameSignal();
|
||||||
Dedicated::FrameOnceSignal();
|
Dedicated::FrameOnceSignal();
|
||||||
Dedicated::FrameOnceSignal.clear();
|
Dedicated::FrameOnceSignal.clear();
|
||||||
Utils::Hook::Call<void()>(0x5A8E80)();
|
Utils::Hook::Call<void()>(0x5A8E80)();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dedicated::Dedicated()
|
Dedicated::Dedicated()
|
||||||
{
|
{
|
||||||
// Map rotation
|
// Map rotation
|
||||||
Utils::Hook::Set(0x4152E8, Dedicated::MapRotate);
|
Utils::Hook::Set(0x4152E8, Dedicated::MapRotate);
|
||||||
Dvar::Register<bool>("sv_dontrotate", false, Game::dvar_flag::DVAR_FLAG_CHEAT, "");
|
Dvar::Register<bool>("sv_dontrotate", false, Game::dvar_flag::DVAR_FLAG_CHEAT, "");
|
||||||
|
|
||||||
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) // Run zonebuilder as dedi :P
|
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) // Run zonebuilder as dedi :P
|
||||||
{
|
{
|
||||||
Dvar::Register<bool>("sv_lanOnly", false, Game::dvar_flag::DVAR_FLAG_NONE, "Don't act as node");
|
Dvar::Register<bool>("sv_lanOnly", false, Game::dvar_flag::DVAR_FLAG_NONE, "Don't act as node");
|
||||||
|
|
||||||
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server
|
Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x5B4FF0, 0xC3); // self-registration on party
|
Utils::Hook::Set<BYTE>(0x5B4FF0, 0xC3); // self-registration on party
|
||||||
Utils::Hook::Set<BYTE>(0x426130, 0xC3); // other party stuff?
|
Utils::Hook::Set<BYTE>(0x426130, 0xC3); // other party stuff?
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x4D7030, 0xC3); // upnp stuff
|
Utils::Hook::Set<BYTE>(0x4D7030, 0xC3); // upnp stuff
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x4B0FC3, 0x04); // make CL_Frame do client packets, even for game state 9
|
Utils::Hook::Set<BYTE>(0x4B0FC3, 0x04); // make CL_Frame do client packets, even for game state 9
|
||||||
Utils::Hook::Set<BYTE>(0x4F5090, 0xC3); // init sound system (1)
|
Utils::Hook::Set<BYTE>(0x4F5090, 0xC3); // init sound system (1)
|
||||||
Utils::Hook::Set<BYTE>(0x507B80, 0xC3); // start render thread
|
Utils::Hook::Set<BYTE>(0x507B80, 0xC3); // start render thread
|
||||||
Utils::Hook::Set<BYTE>(0x4F84C0, 0xC3); // R_Init caller
|
Utils::Hook::Set<BYTE>(0x4F84C0, 0xC3); // R_Init caller
|
||||||
Utils::Hook::Set<BYTE>(0x46A630, 0xC3); // init sound system (2)
|
Utils::Hook::Set<BYTE>(0x46A630, 0xC3); // init sound system (2)
|
||||||
Utils::Hook::Set<BYTE>(0x41FDE0, 0xC3); // Com_Frame audio processor?
|
Utils::Hook::Set<BYTE>(0x41FDE0, 0xC3); // Com_Frame audio processor?
|
||||||
Utils::Hook::Set<BYTE>(0x41B9F0, 0xC3); // called from Com_Frame, seems to do renderer stuff
|
Utils::Hook::Set<BYTE>(0x41B9F0, 0xC3); // called from Com_Frame, seems to do renderer stuff
|
||||||
Utils::Hook::Set<BYTE>(0x41D010, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly
|
Utils::Hook::Set<BYTE>(0x41D010, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly
|
||||||
Utils::Hook::Set<BYTE>(0x62B6C0, 0xC3); // UI expression 'DebugPrint', mainly to prevent some console spam
|
Utils::Hook::Set<BYTE>(0x62B6C0, 0xC3); // UI expression 'DebugPrint', mainly to prevent some console spam
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x468960, 0xC3); // some mixer-related function called on shutdown
|
Utils::Hook::Set<BYTE>(0x468960, 0xC3); // some mixer-related function called on shutdown
|
||||||
Utils::Hook::Set<BYTE>(0x60AD90, 0); // masterServerName flags
|
Utils::Hook::Set<BYTE>(0x60AD90, 0); // masterServerName flags
|
||||||
|
|
||||||
Utils::Hook::Nop(0x4DCEC9, 2); // some check preventing proper game functioning
|
Utils::Hook::Nop(0x4DCEC9, 2); // some check preventing proper game functioning
|
||||||
Utils::Hook::Nop(0x507C79, 6); // another similar bsp check
|
Utils::Hook::Nop(0x507C79, 6); // another similar bsp check
|
||||||
Utils::Hook::Nop(0x414E4D, 6); // unknown check in SV_ExecuteClientMessage (0x20F0890 == 0, related to client->f_40)
|
Utils::Hook::Nop(0x414E4D, 6); // unknown check in SV_ExecuteClientMessage (0x20F0890 == 0, related to client->f_40)
|
||||||
Utils::Hook::Nop(0x4DCEE9, 5); // some deinit renderer function
|
Utils::Hook::Nop(0x4DCEE9, 5); // some deinit renderer function
|
||||||
Utils::Hook::Nop(0x59A896, 5); // warning message on a removed subsystem
|
Utils::Hook::Nop(0x59A896, 5); // warning message on a removed subsystem
|
||||||
Utils::Hook::Nop(0x4B4EEF, 5); // same as above
|
Utils::Hook::Nop(0x4B4EEF, 5); // same as above
|
||||||
Utils::Hook::Nop(0x64CF77, 5); // function detecting video card, causes Direct3DCreate9 to be called
|
Utils::Hook::Nop(0x64CF77, 5); // function detecting video card, causes Direct3DCreate9 to be called
|
||||||
Utils::Hook::Nop(0x60BC52, 0x15); // recommended settings check
|
Utils::Hook::Nop(0x60BC52, 0x15); // recommended settings check
|
||||||
|
|
||||||
Utils::Hook::Nop(0x45148B, 5); // Disable splash screen
|
Utils::Hook::Nop(0x45148B, 5); // Disable splash screen
|
||||||
|
|
||||||
// isHost script call return 0
|
// isHost script call return 0
|
||||||
Utils::Hook::Set<DWORD>(0x5DEC04, 0);
|
Utils::Hook::Set<DWORD>(0x5DEC04, 0);
|
||||||
|
|
||||||
// sv_network_fps max 1000, and uncheat
|
// sv_network_fps max 1000, and uncheat
|
||||||
Utils::Hook::Set<BYTE>(0x4D3C67, 0); // ?
|
Utils::Hook::Set<BYTE>(0x4D3C67, 0); // ?
|
||||||
Utils::Hook::Set<DWORD>(0x4D3C69, 1000);
|
Utils::Hook::Set<DWORD>(0x4D3C69, 1000);
|
||||||
|
|
||||||
// r_loadForRenderer default to 0
|
// r_loadForRenderer default to 0
|
||||||
Utils::Hook::Set<BYTE>(0x519DDF, 0);
|
Utils::Hook::Set<BYTE>(0x519DDF, 0);
|
||||||
|
|
||||||
// disable cheat protection on onlinegame
|
// disable cheat protection on onlinegame
|
||||||
Utils::Hook::Set<BYTE>(0x404CF7, 0x80);
|
Utils::Hook::Set<BYTE>(0x404CF7, 0x80);
|
||||||
|
|
||||||
// some d3d9 call on error
|
// some d3d9 call on error
|
||||||
Utils::Hook::Set<BYTE>(0x508470, 0xC3);
|
Utils::Hook::Set<BYTE>(0x508470, 0xC3);
|
||||||
|
|
||||||
// stop saving a config_mp.cfg
|
// stop saving a config_mp.cfg
|
||||||
Utils::Hook::Set<BYTE>(0x60B240, 0xC3);
|
Utils::Hook::Set<BYTE>(0x60B240, 0xC3);
|
||||||
|
|
||||||
// don't load the config
|
// don't load the config
|
||||||
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
|
||||||
|
|
||||||
// Dedicated frame handler
|
// Dedicated frame handler
|
||||||
Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Intercept chat sending
|
// Intercept chat sending
|
||||||
Utils::Hook(0x4D000B, Dedicated::PreSayStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4D000B, Dedicated::PreSayStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x4D00D4, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4D00D4, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x4D0110, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4D0110, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
if (!ZoneBuilder::IsEnabled())
|
if (!ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
// Post initialization point
|
// Post initialization point
|
||||||
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
#ifdef USE_LEGACY_SERVER_LIST
|
#ifdef USE_LEGACY_SERVER_LIST
|
||||||
|
|
||||||
// Heartbeats
|
// Heartbeats
|
||||||
Dedicated::OnFrame([] ()
|
Dedicated::OnFrame([] ()
|
||||||
{
|
{
|
||||||
static int LastHeartbeat = 0;
|
static int LastHeartbeat = 0;
|
||||||
|
|
||||||
if (Dvar::Var("sv_maxclients").Get<int>() > 0 && !LastHeartbeat || (Game::Com_Milliseconds() - LastHeartbeat) > 120 * 1000)
|
if (Dvar::Var("sv_maxclients").Get<int>() > 0 && !LastHeartbeat || (Game::Com_Milliseconds() - LastHeartbeat) > 120 * 1000)
|
||||||
{
|
{
|
||||||
LastHeartbeat = Game::Com_Milliseconds();
|
LastHeartbeat = Game::Com_Milliseconds();
|
||||||
Dedicated::Heartbeat();
|
Dedicated::Heartbeat();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Dvar::OnInit([] ()
|
Dvar::OnInit([] ()
|
||||||
{
|
{
|
||||||
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_FLAG_NONE, "The name to pose as for 'say' commands");
|
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_FLAG_NONE, "The name to pose as for 'say' commands");
|
||||||
|
|
||||||
// Say command
|
// Say command
|
||||||
Command::AddSV("say", [] (Command::Params params)
|
Command::AddSV("say", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2) return;
|
if (params.Length() < 2) return;
|
||||||
|
|
||||||
std::string message = params.Join(1);
|
std::string message = params.Join(1);
|
||||||
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
|
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
|
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
|
||||||
Game::Com_Printf(15, "%s: %s\n", name.data(), message.data());
|
Game::Com_Printf(15, "%s: %s\n", name.data(), message.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"Console: %s\"", 104, message.data()));
|
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
|
||||||
Game::Com_Printf(15, "Console: %s\n", message.data());
|
Game::Com_Printf(15, "Console: %s\n", message.data());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tell command
|
// Tell command
|
||||||
Command::AddSV("tell", [] (Command::Params params)
|
Command::AddSV("tell", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 3) return;
|
if (params.Length() < 3) return;
|
||||||
|
|
||||||
int client = atoi(params[1]);
|
int client = atoi(params[1]);
|
||||||
std::string message = params.Join(2);
|
std::string message = params.Join(2);
|
||||||
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
|
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
|
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
|
||||||
Game::Com_Printf(15, "%s -> %i: %s\n", name.data(), client, message.data());
|
Game::Com_Printf(15, "%s -> %i: %s\n", name.data(), client, message.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"Console: %s\"", 104, message.data()));
|
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"Console: %s\"", 104, message.data()));
|
||||||
Game::Com_Printf(15, "Console -> %i: %s\n", client, message.data());
|
Game::Com_Printf(15, "Console -> %i: %s\n", client, message.data());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sayraw command
|
// Sayraw command
|
||||||
Command::AddSV("sayraw", [] (Command::Params params)
|
Command::AddSV("sayraw", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2) return;
|
if (params.Length() < 2) return;
|
||||||
|
|
||||||
std::string message = params.Join(1);
|
std::string message = params.Join(1);
|
||||||
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"%s\"", 104, message.data()));
|
Game::SV_GameSendServerCommand(-1, 0, Utils::String::VA("%c \"%s\"", 104, message.data()));
|
||||||
Game::Com_Printf(15, "Raw: %s\n", message.data());
|
Game::Com_Printf(15, "Raw: %s\n", message.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tellraw command
|
// Tellraw command
|
||||||
Command::AddSV("tellraw", [] (Command::Params params)
|
Command::AddSV("tellraw", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 3) return;
|
if (params.Length() < 3) return;
|
||||||
|
|
||||||
int client = atoi(params[1]);
|
int client = atoi(params[1]);
|
||||||
std::string message = params.Join(2);
|
std::string message = params.Join(2);
|
||||||
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"%s\"", 104, message.data()));
|
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"%s\"", 104, message.data()));
|
||||||
Game::Com_Printf(15, "Raw -> %i: %s\n", client, message.data());
|
Game::Com_Printf(15, "Raw -> %i: %s\n", client, message.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
// ! command
|
// ! command
|
||||||
Command::AddSV("!", [] (Command::Params params)
|
Command::AddSV("!", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() != 2) return;
|
if (params.Length() != 2) return;
|
||||||
|
|
||||||
int client = -1;
|
int client = -1;
|
||||||
if (params[1] != "all"s)
|
if (params[1] != "all"s)
|
||||||
{
|
{
|
||||||
client = atoi(params[1]);
|
client = atoi(params[1]);
|
||||||
|
|
||||||
if (client >= *reinterpret_cast<int*>(0x31D938C))
|
if (client >= *reinterpret_cast<int*>(0x31D938C))
|
||||||
{
|
{
|
||||||
Game::Com_Printf(0, "Invalid player.\n");
|
Game::Com_Printf(0, "Invalid player.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"\"", 106));
|
Game::SV_GameSendServerCommand(client, 0, Utils::String::VA("%c \"\"", 106));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dedicated::~Dedicated()
|
Dedicated::~Dedicated()
|
||||||
{
|
{
|
||||||
Dedicated::FrameOnceSignal.clear();
|
Dedicated::FrameOnceSignal.clear();
|
||||||
Dedicated::FrameSignal.clear();
|
Dedicated::FrameSignal.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,93 +1,93 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Discovery::Container Discovery::DiscoveryContainer = { false, false, std::thread() };
|
Discovery::Container Discovery::DiscoveryContainer = { false, false, std::thread() };
|
||||||
|
|
||||||
void Discovery::Perform()
|
void Discovery::Perform()
|
||||||
{
|
{
|
||||||
Discovery::DiscoveryContainer.Perform = true;
|
Discovery::DiscoveryContainer.Perform = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Discovery::Discovery()
|
Discovery::Discovery()
|
||||||
{
|
{
|
||||||
Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::dvar_flag::DVAR_FLAG_SAVED, "Minimum scan range port for local server discovery");
|
Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::dvar_flag::DVAR_FLAG_SAVED, "Minimum scan range port for local server discovery");
|
||||||
Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::dvar_flag::DVAR_FLAG_SAVED, "Maximum scan range port for local server discovery");
|
Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::dvar_flag::DVAR_FLAG_SAVED, "Maximum scan range port for local server discovery");
|
||||||
|
|
||||||
Discovery::DiscoveryContainer.Perform = false;
|
Discovery::DiscoveryContainer.Perform = false;
|
||||||
Discovery::DiscoveryContainer.Terminate = false;
|
Discovery::DiscoveryContainer.Terminate = false;
|
||||||
Discovery::DiscoveryContainer.Thread = std::thread([] ()
|
Discovery::DiscoveryContainer.Thread = std::thread([] ()
|
||||||
{
|
{
|
||||||
while (!Discovery::DiscoveryContainer.Terminate)
|
while (!Discovery::DiscoveryContainer.Terminate)
|
||||||
{
|
{
|
||||||
if (Discovery::DiscoveryContainer.Perform)
|
if (Discovery::DiscoveryContainer.Perform)
|
||||||
{
|
{
|
||||||
int start = Game::Sys_Milliseconds();
|
int start = Game::Sys_Milliseconds();
|
||||||
|
|
||||||
Logger::Print("Starting local server discovery...\n");
|
Logger::Print("Starting local server discovery...\n");
|
||||||
|
|
||||||
Discovery::DiscoveryContainer.Challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
|
Discovery::DiscoveryContainer.Challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
|
||||||
|
|
||||||
unsigned int minPort = Dvar::Var("net_discoveryPortRangeMin").Get<unsigned int>();
|
unsigned int minPort = Dvar::Var("net_discoveryPortRangeMin").Get<unsigned int>();
|
||||||
unsigned int maxPort = Dvar::Var("net_discoveryPortRangeMax").Get<unsigned int>();
|
unsigned int maxPort = Dvar::Var("net_discoveryPortRangeMax").Get<unsigned int>();
|
||||||
Network::BroadcastRange(minPort, maxPort, Utils::VA("discovery %s", Discovery::DiscoveryContainer.Challenge.data()));
|
Network::BroadcastRange(minPort, maxPort, fmt::sprintf("discovery %s", Discovery::DiscoveryContainer.Challenge.data()));
|
||||||
|
|
||||||
Logger::Print("Discovery sent within %dms, awaiting responses...\n", Game::Sys_Milliseconds() - start);
|
Logger::Print("Discovery sent within %dms, awaiting responses...\n", Game::Sys_Milliseconds() - start);
|
||||||
|
|
||||||
Discovery::DiscoveryContainer.Perform = false;
|
Discovery::DiscoveryContainer.Perform = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(50ms);
|
std::this_thread::sleep_for(50ms);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("discovery", [] (Network::Address address, std::string data)
|
Network::Handle("discovery", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
if (address.IsSelf()) return;
|
if (address.IsSelf()) return;
|
||||||
|
|
||||||
if (!address.IsLocal())
|
if (!address.IsLocal())
|
||||||
{
|
{
|
||||||
Logger::Print("Received discovery request from non-local address: %s\n", address.GetCString());
|
Logger::Print("Received discovery request from non-local address: %s\n", address.GetCString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print("Received discovery request from %s\n", address.GetCString());
|
Logger::Print("Received discovery request from %s\n", address.GetCString());
|
||||||
Network::SendCommand(address, "discoveryResponse", data);
|
Network::SendCommand(address, "discoveryResponse", data);
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("discoveryResponse", [] (Network::Address address, std::string data)
|
Network::Handle("discoveryResponse", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
if (address.IsSelf()) return;
|
if (address.IsSelf()) return;
|
||||||
|
|
||||||
if (!address.IsLocal())
|
if (!address.IsLocal())
|
||||||
{
|
{
|
||||||
Logger::Print("Received discovery response from non-local address: %s\n", address.GetCString());
|
Logger::Print("Received discovery response from non-local address: %s\n", address.GetCString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils::ParseChallenge(data) != Discovery::DiscoveryContainer.Challenge)
|
if (Utils::ParseChallenge(data) != Discovery::DiscoveryContainer.Challenge)
|
||||||
{
|
{
|
||||||
Logger::Print("Received discovery with invalid challenge from: %s\n", address.GetCString());
|
Logger::Print("Received discovery with invalid challenge from: %s\n", address.GetCString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print("Received discovery response from: %s\n", address.GetCString());
|
Logger::Print("Received discovery response from: %s\n", address.GetCString());
|
||||||
|
|
||||||
if (ServerList::IsOfflineList())
|
if (ServerList::IsOfflineList())
|
||||||
{
|
{
|
||||||
ServerList::InsertRequest(address, true);
|
ServerList::InsertRequest(address, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Discovery::~Discovery()
|
Discovery::~Discovery()
|
||||||
{
|
{
|
||||||
Discovery::DiscoveryContainer.Perform = false;
|
Discovery::DiscoveryContainer.Perform = false;
|
||||||
Discovery::DiscoveryContainer.Terminate = true;
|
Discovery::DiscoveryContainer.Terminate = true;
|
||||||
|
|
||||||
if (Discovery::DiscoveryContainer.Thread.joinable())
|
if (Discovery::DiscoveryContainer.Thread.joinable())
|
||||||
{
|
{
|
||||||
Discovery::DiscoveryContainer.Thread.join();
|
Discovery::DiscoveryContainer.Thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,331 +1,331 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
mg_mgr Download::Mgr;
|
mg_mgr Download::Mgr;
|
||||||
|
|
||||||
bool Download::IsClient(mg_connection *nc)
|
bool Download::IsClient(mg_connection *nc)
|
||||||
{
|
{
|
||||||
return (Download::GetClient(nc) != nullptr);
|
return (Download::GetClient(nc) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::client_t* Download::GetClient(mg_connection *nc)
|
Game::client_t* Download::GetClient(mg_connection *nc)
|
||||||
{
|
{
|
||||||
Network::Address address(nc->sa.sa);
|
Network::Address address(nc->sa.sa);
|
||||||
|
|
||||||
for (int i = 0; i < *Game::svs_numclients; ++i)
|
for (int i = 0; i < *Game::svs_numclients; ++i)
|
||||||
{
|
{
|
||||||
Game::client_t* client = &Game::svs_clients[i];
|
Game::client_t* client = &Game::svs_clients[i];
|
||||||
|
|
||||||
if (client->state >= 3)
|
if (client->state >= 3)
|
||||||
{
|
{
|
||||||
if (address.GetIP().full == Network::Address(client->addr).GetIP().full)
|
if (address.GetIP().full == Network::Address(client->addr).GetIP().full)
|
||||||
{
|
{
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::Forbid(mg_connection *nc)
|
void Download::Forbid(mg_connection *nc)
|
||||||
{
|
{
|
||||||
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
|
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"403 - Forbidden");
|
"403 - Forbidden");
|
||||||
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::ListHandler(mg_connection *nc, int ev, void *ev_data)
|
void Download::ListHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
// if (!Download::IsClient(nc))
|
// if (!Download::IsClient(nc))
|
||||||
// {
|
// {
|
||||||
// Download::Forbid(nc);
|
// Download::Forbid(nc);
|
||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
{
|
{
|
||||||
static std::string fsGamePre;
|
static std::string fsGamePre;
|
||||||
static json11::Json jsonList;
|
static json11::Json jsonList;
|
||||||
|
|
||||||
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
|
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
|
||||||
|
|
||||||
if (!fsGame.empty() && fsGame != fsGamePre)
|
if (!fsGame.empty() && fsGame != fsGamePre)
|
||||||
{
|
{
|
||||||
std::vector<json11::Json> fileList;
|
std::vector<json11::Json> fileList;
|
||||||
|
|
||||||
fsGamePre = fsGame;
|
fsGamePre = fsGame;
|
||||||
|
|
||||||
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame;
|
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame;
|
||||||
auto list = FileSystem::GetSysFileList(path, "iwd", false);
|
auto list = FileSystem::GetSysFileList(path, "iwd", false);
|
||||||
|
|
||||||
list.push_back("mod.ff");
|
list.push_back("mod.ff");
|
||||||
|
|
||||||
for (auto i = list.begin(); i != list.end(); ++i)
|
for (auto i = list.begin(); i != list.end(); ++i)
|
||||||
{
|
{
|
||||||
std::string filename = path + "\\" + *i;
|
std::string filename = path + "\\" + *i;
|
||||||
if (strstr(i->data(), "_svr_") == NULL && Utils::FileExists(filename))
|
if (strstr(i->data(), "_svr_") == NULL && Utils::IO::FileExists(filename))
|
||||||
{
|
{
|
||||||
std::map<std::string, json11::Json> file;
|
std::map<std::string, json11::Json> file;
|
||||||
std::string fileBuffer = Utils::ReadFile(path + "\\" + *i);
|
std::string fileBuffer = Utils::IO::ReadFile(path + "\\" + *i);
|
||||||
|
|
||||||
file["name"] = *i;
|
file["name"] = *i;
|
||||||
file["size"] = static_cast<int>(fileBuffer.size());
|
file["size"] = static_cast<int>(fileBuffer.size());
|
||||||
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
||||||
|
|
||||||
fileList.push_back(file);
|
fileList.push_back(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonList = fileList;
|
jsonList = fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: application/json\r\n"
|
"Content-Type: application/json\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"%s", jsonList.dump().data());
|
"%s", jsonList.dump().data());
|
||||||
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::FileHandler(mg_connection *nc, int ev, void *ev_data)
|
void Download::FileHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||||
|
|
||||||
// if (!Download::IsClient(nc))
|
// if (!Download::IsClient(nc))
|
||||||
// {
|
// {
|
||||||
// Download::Forbid(nc);
|
// Download::Forbid(nc);
|
||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
{
|
{
|
||||||
std::string url(message->uri.p, message->uri.len);
|
std::string url(message->uri.p, message->uri.len);
|
||||||
Utils::Replace(url, "\\", "/");
|
Utils::String::Replace(url, "\\", "/");
|
||||||
url = url.substr(6);
|
url = url.substr(6);
|
||||||
|
|
||||||
if (url.find_first_of("/") != std::string::npos || (!Utils::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL)
|
if (url.find_first_of("/") != std::string::npos || (!Utils::String::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL)
|
||||||
{
|
{
|
||||||
Download::Forbid(nc);
|
Download::Forbid(nc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
|
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
|
||||||
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame + "\\" + url;
|
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame + "\\" + url;
|
||||||
|
|
||||||
if (fsGame.empty() || !Utils::FileExists(path))
|
if (fsGame.empty() || !Utils::IO::FileExists(path))
|
||||||
{
|
{
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 404 Not Found\r\n"
|
"HTTP/1.1 404 Not Found\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"404 - Not Found %s", path.data());
|
"404 - Not Found %s", path.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string file = Utils::ReadFile(path);
|
std::string file = Utils::IO::ReadFile(path);
|
||||||
|
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: application/octet-stream\r\n"
|
"Content-Type: application/octet-stream\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n", file.size());
|
"\r\n", file.size());
|
||||||
|
|
||||||
mg_send(nc, file.data(), static_cast<int>(file.size()));
|
mg_send(nc, file.data(), static_cast<int>(file.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::InfoHandler(mg_connection *nc, int ev, void *ev_data)
|
void Download::InfoHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
//http_message* message = reinterpret_cast<http_message*>(ev_data);
|
//http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||||
|
|
||||||
Utils::InfoString status = ServerInfo::GetInfo();
|
Utils::InfoString status = ServerInfo::GetInfo();
|
||||||
|
|
||||||
std::map<std::string, json11::Json> info;
|
std::map<std::string, json11::Json> info;
|
||||||
info["status"] = status.to_json();
|
info["status"] = status.to_json();
|
||||||
|
|
||||||
std::vector<json11::Json> players;
|
std::vector<json11::Json> players;
|
||||||
|
|
||||||
// Build player list
|
// Build player list
|
||||||
for (int i = 0; i < atoi(status.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
for (int i = 0; i < atoi(status.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
||||||
{
|
{
|
||||||
std::map<std::string, json11::Json> playerInfo;
|
std::map<std::string, json11::Json> playerInfo;
|
||||||
playerInfo["score"] = 0;
|
playerInfo["score"] = 0;
|
||||||
playerInfo["ping"] = 0;
|
playerInfo["ping"] = 0;
|
||||||
playerInfo["name"] = "";
|
playerInfo["name"] = "";
|
||||||
|
|
||||||
if (Dvar::Var("sv_running").Get<bool>())
|
if (Dvar::Var("sv_running").Get<bool>())
|
||||||
{
|
{
|
||||||
if (Game::svs_clients[i].state < 3) continue;
|
if (Game::svs_clients[i].state < 3) continue;
|
||||||
|
|
||||||
playerInfo["score"] = Game::SV_GameClientNum_Score(i);
|
playerInfo["score"] = Game::SV_GameClientNum_Score(i);
|
||||||
playerInfo["ping"] = Game::svs_clients[i].ping;
|
playerInfo["ping"] = Game::svs_clients[i].ping;
|
||||||
playerInfo["name"] = Game::svs_clients[i].name;
|
playerInfo["name"] = Game::svs_clients[i].name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Score and ping are irrelevant
|
// Score and ping are irrelevant
|
||||||
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
|
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
|
||||||
if (!namePtr || !namePtr[0]) continue;
|
if (!namePtr || !namePtr[0]) continue;
|
||||||
|
|
||||||
playerInfo["name"] = namePtr;
|
playerInfo["name"] = namePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
players.push_back(playerInfo);
|
players.push_back(playerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
info["players"] = players;
|
info["players"] = players;
|
||||||
|
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: application/json\r\n"
|
"Content-Type: application/json\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"Access-Control-Allow-Origin: *\r\n"
|
"Access-Control-Allow-Origin: *\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"%s", json11::Json(info).dump().data());
|
"%s", json11::Json(info).dump().data());
|
||||||
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
|
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||||
|
|
||||||
// if (message->uri.p, message->uri.len == "/"s)
|
// if (message->uri.p, message->uri.len == "/"s)
|
||||||
// {
|
// {
|
||||||
// mg_printf(nc,
|
// mg_printf(nc,
|
||||||
// "HTTP/1.1 200 OK\r\n"
|
// "HTTP/1.1 200 OK\r\n"
|
||||||
// "Content-Type: text/html\r\n"
|
// "Content-Type: text/html\r\n"
|
||||||
// "Connection: close\r\n"
|
// "Connection: close\r\n"
|
||||||
// "\r\n"
|
// "\r\n"
|
||||||
// "Hi fella!<br>You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not"));
|
// "Hi fella!<br>You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not"));
|
||||||
//
|
//
|
||||||
// Game::client_t* client = Download::GetClient(nc);
|
// Game::client_t* client = Download::GetClient(nc);
|
||||||
//
|
//
|
||||||
// if (client)
|
// if (client)
|
||||||
// {
|
// {
|
||||||
// mg_printf(nc, "<br>Hello %s!", client->name);
|
// mg_printf(nc, "<br>Hello %s!", client->name);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
{
|
{
|
||||||
//std::string path = (Dvar::Var("fs_basepath").Get<std::string>() + "\\" BASEGAME "\\html");
|
//std::string path = (Dvar::Var("fs_basepath").Get<std::string>() + "\\" BASEGAME "\\html");
|
||||||
//mg_serve_http_opts opts = { 0 };
|
//mg_serve_http_opts opts = { 0 };
|
||||||
//opts.document_root = path.data();
|
//opts.document_root = path.data();
|
||||||
//mg_serve_http(nc, message, opts);
|
//mg_serve_http(nc, message, opts);
|
||||||
|
|
||||||
FileSystem::File file;
|
FileSystem::File file;
|
||||||
std::string url = "html" + std::string(message->uri.p, message->uri.len);
|
std::string url = "html" + std::string(message->uri.p, message->uri.len);
|
||||||
|
|
||||||
if (Utils::EndsWith(url, "/"))
|
if (Utils::String::EndsWith(url, "/"))
|
||||||
{
|
{
|
||||||
url.append("index.html");
|
url.append("index.html");
|
||||||
file = FileSystem::File(url);
|
file = FileSystem::File(url);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
file = FileSystem::File(url);
|
file = FileSystem::File(url);
|
||||||
|
|
||||||
if (!file.Exists())
|
if (!file.Exists())
|
||||||
{
|
{
|
||||||
url.append("/index.html");
|
url.append("/index.html");
|
||||||
file = FileSystem::File(url);
|
file = FileSystem::File(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mimeType = Utils::GetMimeType(url);
|
std::string mimeType = Utils::GetMimeType(url);
|
||||||
|
|
||||||
if (file.Exists())
|
if (file.Exists())
|
||||||
{
|
{
|
||||||
std::string& buffer = file.GetBuffer();
|
std::string& buffer = file.GetBuffer();
|
||||||
|
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: %s\r\n"
|
"Content-Type: %s\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n", mimeType.data(), buffer.size());
|
"\r\n", mimeType.data(), buffer.size());
|
||||||
|
|
||||||
mg_send(nc, buffer.data(), static_cast<int>(buffer.size()));
|
mg_send(nc, buffer.data(), static_cast<int>(buffer.size()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mg_printf(nc,
|
mg_printf(nc,
|
||||||
"HTTP/1.1 404 Not Found\r\n"
|
"HTTP/1.1 404 Not Found\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"404 - Not Found");
|
"404 - Not Found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Download::Download()
|
Download::Download()
|
||||||
{
|
{
|
||||||
if (Dedicated::IsDedicated())
|
if (Dedicated::IsDedicated())
|
||||||
{
|
{
|
||||||
mg_mgr_init(&Download::Mgr, NULL);
|
mg_mgr_init(&Download::Mgr, NULL);
|
||||||
|
|
||||||
Network::OnStart([] ()
|
Network::OnStart([] ()
|
||||||
{
|
{
|
||||||
mg_connection* nc = mg_bind(&Download::Mgr, Utils::VA("%hu", (Dvar::Var("net_port").Get<int>() & 0xFFFF)), Download::EventHandler);
|
mg_connection* nc = mg_bind(&Download::Mgr, Utils::String::VA("%hu", (Dvar::Var("net_port").Get<int>() & 0xFFFF)), Download::EventHandler);
|
||||||
|
|
||||||
// Handle special requests
|
// Handle special requests
|
||||||
mg_register_http_endpoint(nc, "/info", Download::InfoHandler);
|
mg_register_http_endpoint(nc, "/info", Download::InfoHandler);
|
||||||
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
|
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
|
||||||
mg_register_http_endpoint(nc, "/file", Download::FileHandler);
|
mg_register_http_endpoint(nc, "/file", Download::FileHandler);
|
||||||
|
|
||||||
mg_set_protocol_http_websocket(nc);
|
mg_set_protocol_http_websocket(nc);
|
||||||
});
|
});
|
||||||
|
|
||||||
QuickPatch::OnFrame([]
|
QuickPatch::OnFrame([]
|
||||||
{
|
{
|
||||||
mg_mgr_poll(&Download::Mgr, 0);
|
mg_mgr_poll(&Download::Mgr, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils::Hook(0x5AC6E9, [] ()
|
Utils::Hook(0x5AC6E9, [] ()
|
||||||
{
|
{
|
||||||
// TODO: Perform moddownload here
|
// TODO: Perform moddownload here
|
||||||
|
|
||||||
Game::CL_DownloadsComplete(0);
|
Game::CL_DownloadsComplete(0);
|
||||||
}, HOOK_CALL).Install()->Quick();
|
}, HOOK_CALL).Install()->Quick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Download::~Download()
|
Download::~Download()
|
||||||
{
|
{
|
||||||
if (Dedicated::IsDedicated())
|
if (Dedicated::IsDedicated())
|
||||||
{
|
{
|
||||||
mg_mgr_free(&Download::Mgr);
|
mg_mgr_free(&Download::Mgr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,207 +1,207 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
wink::signal<wink::slot<Dvar::Callback>> Dvar::RegistrationSignal;
|
wink::signal<wink::slot<Dvar::Callback>> Dvar::RegistrationSignal;
|
||||||
|
|
||||||
Dvar::Var::Var(std::string dvarName) : Var()
|
Dvar::Var::Var(std::string dvarName) : Var()
|
||||||
{
|
{
|
||||||
this->dvar = Game::Dvar_FindVar(dvarName.data());
|
this->dvar = Game::Dvar_FindVar(dvarName.data());
|
||||||
|
|
||||||
if (!this->dvar)
|
if (!this->dvar)
|
||||||
{
|
{
|
||||||
// Quick-register the dvar
|
// Quick-register the dvar
|
||||||
Game::Dvar_SetStringByName(dvarName.data(), "");
|
Game::Dvar_SetStringByName(dvarName.data(), "");
|
||||||
this->dvar = Game::Dvar_FindVar(dvarName.data());
|
this->dvar = Game::Dvar_FindVar(dvarName.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> Game::dvar_t* Dvar::Var::Get()
|
template <> Game::dvar_t* Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
return this->dvar;
|
return this->dvar;
|
||||||
}
|
}
|
||||||
template <> char* Dvar::Var::Get()
|
template <> char* Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING && this->dvar->current.string)
|
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING && this->dvar->current.string)
|
||||||
{
|
{
|
||||||
return this->dvar->current.string;
|
return this->dvar->current.string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
template <> const char* Dvar::Var::Get()
|
template <> const char* Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
return this->Get<char*>();
|
return this->Get<char*>();
|
||||||
}
|
}
|
||||||
template <> int Dvar::Var::Get()
|
template <> int Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_INT)
|
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_INT)
|
||||||
{
|
{
|
||||||
return this->dvar->current.integer;
|
return this->dvar->current.integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
template <> unsigned int Dvar::Var::Get()
|
template <> unsigned int Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
return static_cast<unsigned int>(this->Get<int>());
|
return static_cast<unsigned int>(this->Get<int>());
|
||||||
}
|
}
|
||||||
template <> float Dvar::Var::Get()
|
template <> float Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT)
|
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT)
|
||||||
{
|
{
|
||||||
return this->dvar->current.value;
|
return this->dvar->current.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
template <> float* Dvar::Var::Get()
|
template <> float* Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
static float val[4] = { 0 };
|
static float val[4] = { 0 };
|
||||||
|
|
||||||
if (this->dvar && (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4))
|
if (this->dvar && (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4))
|
||||||
{
|
{
|
||||||
return this->dvar->current.vec4;
|
return this->dvar->current.vec4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
template <> bool Dvar::Var::Get()
|
template <> bool Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL)
|
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL)
|
||||||
{
|
{
|
||||||
return this->dvar->current.boolean;
|
return this->dvar->current.boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <> std::string Dvar::Var::Get()
|
template <> std::string Dvar::Var::Get()
|
||||||
{
|
{
|
||||||
return this->Get<const char*>();
|
return this->Get<const char*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dvar::Var::Set(char* string)
|
void Dvar::Var::Set(char* string)
|
||||||
{
|
{
|
||||||
this->Set(const_cast<const char*>(string));
|
this->Set(const_cast<const char*>(string));
|
||||||
}
|
}
|
||||||
void Dvar::Var::Set(const char* string)
|
void Dvar::Var::Set(const char* string)
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->name)
|
if (this->dvar && this->dvar->name)
|
||||||
{
|
{
|
||||||
Game::Dvar_SetCommand(this->dvar->name, string);
|
Game::Dvar_SetCommand(this->dvar->name, string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Dvar::Var::Set(std::string string)
|
void Dvar::Var::Set(std::string string)
|
||||||
{
|
{
|
||||||
this->Set(string.data());
|
this->Set(string.data());
|
||||||
}
|
}
|
||||||
void Dvar::Var::Set(int integer)
|
void Dvar::Var::Set(int integer)
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->name)
|
if (this->dvar && this->dvar->name)
|
||||||
{
|
{
|
||||||
Game::Dvar_SetCommand(this->dvar->name, Utils::VA("%i", integer));
|
Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%i", integer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Dvar::Var::Set(float value)
|
void Dvar::Var::Set(float value)
|
||||||
{
|
{
|
||||||
if (this->dvar && this->dvar->name)
|
if (this->dvar && this->dvar->name)
|
||||||
{
|
{
|
||||||
Game::Dvar_SetCommand(this->dvar->name, Utils::VA("%f", value));
|
Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%f", value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dvar::Var::SetRaw(int integer)
|
void Dvar::Var::SetRaw(int integer)
|
||||||
{
|
{
|
||||||
if (this->dvar)
|
if (this->dvar)
|
||||||
{
|
{
|
||||||
this->dvar->current.integer = integer;
|
this->dvar->current.integer = integer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description)
|
template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description)
|
||||||
{
|
{
|
||||||
return Game::Dvar_RegisterBool(name, value, flag.val, description);
|
return Game::Dvar_RegisterBool(name, value, flag.val, description);
|
||||||
}
|
}
|
||||||
template<> static Dvar::Var Dvar::Register(const char* name, const char* value, Dvar::Flag flag, const char* description)
|
template<> static Dvar::Var Dvar::Register(const char* name, const char* value, Dvar::Flag flag, const char* description)
|
||||||
{
|
{
|
||||||
return Game::Dvar_RegisterString(name, value, flag.val, description);
|
return Game::Dvar_RegisterString(name, value, flag.val, description);
|
||||||
}
|
}
|
||||||
template<> static Dvar::Var Dvar::Register(const char* name, int value, int min, int max, Dvar::Flag flag, const char* description)
|
template<> static Dvar::Var Dvar::Register(const char* name, int value, int min, int max, Dvar::Flag flag, const char* description)
|
||||||
{
|
{
|
||||||
return Game::Dvar_RegisterInt(name, value, min, max, flag.val, description);
|
return Game::Dvar_RegisterInt(name, value, min, max, flag.val, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dvar::OnInit(Dvar::Callback* callback)
|
void Dvar::OnInit(Dvar::Callback* callback)
|
||||||
{
|
{
|
||||||
Dvar::RegistrationSignal.connect(callback);
|
Dvar::RegistrationSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::dvar_t* Dvar::RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description)
|
Game::dvar_t* Dvar::RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description)
|
||||||
{
|
{
|
||||||
// Run callbacks
|
// Run callbacks
|
||||||
Dvar::RegistrationSignal();
|
Dvar::RegistrationSignal();
|
||||||
|
|
||||||
// Name watcher
|
// Name watcher
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
static std::string lastValidName = "Unknown Soldier";
|
static std::string lastValidName = "Unknown Soldier";
|
||||||
std::string name = Dvar::Var("name").Get<char*>();
|
std::string name = Dvar::Var("name").Get<char*>();
|
||||||
|
|
||||||
// Don't perform any checks if name didn't change
|
// Don't perform any checks if name didn't change
|
||||||
if (name == lastValidName) return;
|
if (name == lastValidName) return;
|
||||||
|
|
||||||
std::string saneName = Colors::Strip(Utils::Trim(name));
|
std::string saneName = Colors::Strip(Utils::String::Trim(name));
|
||||||
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
|
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
|
||||||
{
|
{
|
||||||
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
|
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
|
||||||
Dvar::Var("name").Set(lastValidName);
|
Dvar::Var("name").Set(lastValidName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lastValidName = name;
|
lastValidName = name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Dvar::Register<const char*>(name, "Unknown Soldier", Dvar::Flag(flag | Game::dvar_flag::DVAR_FLAG_SAVED).val, description).Get<Game::dvar_t*>();
|
return Dvar::Register<const char*>(name, "Unknown Soldier", Dvar::Flag(flag | Game::dvar_flag::DVAR_FLAG_SAVED).val, description).Get<Game::dvar_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dvar::Dvar()
|
Dvar::Dvar()
|
||||||
{
|
{
|
||||||
// set flags of cg_drawFPS to archive
|
// set flags of cg_drawFPS to archive
|
||||||
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED);
|
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED);
|
||||||
|
|
||||||
// un-cheat cg_fov and add archive flags
|
// un-cheat cg_fov and add archive flags
|
||||||
Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
|
Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
|
||||||
|
|
||||||
// un-cheat cg_debugInfoCornerOffset and add archive flags
|
// un-cheat cg_debugInfoCornerOffset and add archive flags
|
||||||
Utils::Hook::Xor<BYTE>(0x4F8FC2, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
|
Utils::Hook::Xor<BYTE>(0x4F8FC2, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
|
||||||
|
|
||||||
// remove archive flags for cg_hudchatposition
|
// remove archive flags for cg_hudchatposition
|
||||||
Utils::Hook::Xor<BYTE>(0x4F9992, Game::dvar_flag::DVAR_FLAG_SAVED);
|
Utils::Hook::Xor<BYTE>(0x4F9992, Game::dvar_flag::DVAR_FLAG_SAVED);
|
||||||
|
|
||||||
// remove write protection from fs_game
|
// remove write protection from fs_game
|
||||||
Utils::Hook::Xor<DWORD>(0x6431EA, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED);
|
Utils::Hook::Xor<DWORD>(0x6431EA, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED);
|
||||||
|
|
||||||
// set cg_fov max to 90.0
|
// set cg_fov max to 90.0
|
||||||
static float cgFov90 = 90.0f;
|
static float cgFov90 = 90.0f;
|
||||||
Utils::Hook::Set<float*>(0x4F8E28, &cgFov90);
|
Utils::Hook::Set<float*>(0x4F8E28, &cgFov90);
|
||||||
|
|
||||||
// set max volume to 1
|
// set max volume to 1
|
||||||
static float volume = 1.0f;
|
static float volume = 1.0f;
|
||||||
Utils::Hook::Set<float*>(0x408078, &volume);
|
Utils::Hook::Set<float*>(0x408078, &volume);
|
||||||
|
|
||||||
// Uncheat ui_showList
|
// Uncheat ui_showList
|
||||||
Utils::Hook::Xor<BYTE>(0x6310DC, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
Utils::Hook::Xor<BYTE>(0x6310DC, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
||||||
|
|
||||||
// Uncheat ui_debugMode
|
// Uncheat ui_debugMode
|
||||||
Utils::Hook::Xor<BYTE>(0x6312DE, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
Utils::Hook::Xor<BYTE>(0x6312DE, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
||||||
|
|
||||||
// Hook dvar 'name' registration
|
// Hook dvar 'name' registration
|
||||||
Utils::Hook(0x40531C, Dvar::RegisterName, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x40531C, Dvar::RegisterName, HOOK_CALL).Install()->Quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dvar::~Dvar()
|
Dvar::~Dvar()
|
||||||
{
|
{
|
||||||
Dvar::RegistrationSignal.clear();
|
Dvar::RegistrationSignal.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,101 +1,101 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
// Stuff causes warnings
|
// Stuff causes warnings
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4091)
|
#pragma warning(disable: 4091)
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#pragma comment(lib, "dbghelp.lib")
|
#pragma comment(lib, "dbghelp.lib")
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo)
|
LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo)
|
||||||
{
|
{
|
||||||
char filename[MAX_PATH];
|
char filename[MAX_PATH];
|
||||||
__time64_t time;
|
__time64_t time;
|
||||||
tm* ltime;
|
tm* ltime;
|
||||||
|
|
||||||
_time64(&time);
|
_time64(&time);
|
||||||
ltime = _localtime64(&time);
|
ltime = _localtime64(&time);
|
||||||
strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime);
|
strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime);
|
||||||
|
|
||||||
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
if (hFile && hFile != INVALID_HANDLE_VALUE)
|
if (hFile && hFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(),ExceptionInfo, FALSE };
|
MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(),ExceptionInfo, FALSE };
|
||||||
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ex, NULL, NULL);
|
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ex, NULL, NULL);
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
|
||||||
{
|
{
|
||||||
Logger::Error("Termination because of a stack overflow.\n");
|
Logger::Error("Termination because of a stack overflow.\n");
|
||||||
TerminateProcess(GetCurrentProcess(), EXCEPTION_STACK_OVERFLOW);
|
TerminateProcess(GetCurrentProcess(), EXCEPTION_STACK_OVERFLOW);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Error("Fatal error (0x%08x) at 0x%08x.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress);
|
Logger::Error("Fatal error (0x%08x) at 0x%08x.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
|
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
|
||||||
{
|
{
|
||||||
SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
|
SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
|
||||||
return lpTopLevelExceptionFilter;
|
return lpTopLevelExceptionFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception::Exception()
|
Exception::Exception()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Display DEBUG branding, so we know we're on a debug build
|
// Display DEBUG branding, so we know we're on a debug build
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
Game::Font* font = Game::R_RegisterFont("fonts/normalFont");
|
Game::Font* font = Game::R_RegisterFont("fonts/normalFont");
|
||||||
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
|
||||||
// Change the color when attaching a debugger
|
// Change the color when attaching a debugger
|
||||||
if (IsDebuggerPresent())
|
if (IsDebuggerPresent())
|
||||||
{
|
{
|
||||||
color[0] = 0.6588f;
|
color[0] = 0.6588f;
|
||||||
color[1] = 1.0000f;
|
color[1] = 1.0000f;
|
||||||
color[2] = 0.0000f;
|
color[2] = 0.0000f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED);
|
Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED);
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
Utils::Hook::Set(0x6D70AC, Exception::SetUnhandledExceptionFilterStub);
|
Utils::Hook::Set(0x6D70AC, Exception::SetUnhandledExceptionFilterStub);
|
||||||
SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
|
SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Command::Add("mapTest", [] (Command::Params params)
|
Command::Add("mapTest", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
std::string command;
|
std::string command;
|
||||||
|
|
||||||
int max = (params.Length() >= 2 ? atoi(params[1]) : 16), current = 0;
|
int max = (params.Length() >= 2 ? atoi(params[1]) : 16), current = 0;
|
||||||
|
|
||||||
for (int i =0;;)
|
for (int i =0;;)
|
||||||
{
|
{
|
||||||
char* mapname = reinterpret_cast<char*>(0x7471D0) + 40 * i;
|
char* mapname = reinterpret_cast<char*>(0x7471D0) + 40 * i;
|
||||||
if (!*mapname)
|
if (!*mapname)
|
||||||
{
|
{
|
||||||
i = 0;
|
i = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(i % 2)) command.append(Utils::VA("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect
|
if(!(i % 2)) command.append(fmt::sprintf("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect
|
||||||
else command.append(Utils::VA("wait 500;", mapname)); // Test direct map switch
|
else command.append(fmt::sprintf("wait 500;", mapname)); // Test direct map switch
|
||||||
command.append(Utils::VA("map %s;", mapname));
|
command.append(fmt::sprintf("map %s;", mapname));
|
||||||
|
|
||||||
++i, ++current;
|
++i, ++current;
|
||||||
|
|
||||||
if (current >= max) break;
|
if (current >= max) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Execute(command, false);
|
Command::Execute(command, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,226 +1,226 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::vector<std::string> FastFiles::ZonePaths;
|
std::vector<std::string> FastFiles::ZonePaths;
|
||||||
|
|
||||||
// This has to be called only once, when the game starts
|
// This has to be called only once, when the game starts
|
||||||
void FastFiles::LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
void FastFiles::LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
||||||
{
|
{
|
||||||
std::vector<Game::XZoneInfo> data;
|
std::vector<Game::XZoneInfo> data;
|
||||||
Utils::Merge(&data, zoneInfo, zoneCount);
|
Utils::Merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
if (FastFiles::Exists("iw4x_patch_mp"))
|
if (FastFiles::Exists("iw4x_patch_mp"))
|
||||||
{
|
{
|
||||||
data.push_back({ "iw4x_patch_mp", 1, 0 });
|
data.push_back({ "iw4x_patch_mp", 1, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load custom weapons, if present (force that later on)
|
// Load custom weapons, if present (force that later on)
|
||||||
if (FastFiles::Exists("iw4x_weapons_mp"))
|
if (FastFiles::Exists("iw4x_weapons_mp"))
|
||||||
{
|
{
|
||||||
data.push_back({ "iw4x_weapons_mp", 1, 0 });
|
data.push_back({ "iw4x_weapons_mp", 1, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
return FastFiles::LoadDLCUIZones(data.data(), data.size(), sync);
|
return FastFiles::LoadDLCUIZones(data.data(), data.size(), sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This has to be called every time the cgame is reinitialized
|
// This has to be called every time the cgame is reinitialized
|
||||||
void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
||||||
{
|
{
|
||||||
std::vector<Game::XZoneInfo> data;
|
std::vector<Game::XZoneInfo> data;
|
||||||
Utils::Merge(&data, zoneInfo, zoneCount);
|
Utils::Merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
Game::XZoneInfo info = { nullptr, 2, 0 };
|
Game::XZoneInfo info = { nullptr, 2, 0 };
|
||||||
|
|
||||||
// Custom ui stuff
|
// Custom ui stuff
|
||||||
if (FastFiles::Exists("iw4x_ui_mp"))
|
if (FastFiles::Exists("iw4x_ui_mp"))
|
||||||
{
|
{
|
||||||
info.name = "iw4x_ui_mp";
|
info.name = "iw4x_ui_mp";
|
||||||
data.push_back(info);
|
data.push_back(info);
|
||||||
}
|
}
|
||||||
else // Fallback
|
else // Fallback
|
||||||
{
|
{
|
||||||
info.name = "dlc1_ui_mp";
|
info.name = "dlc1_ui_mp";
|
||||||
data.push_back(info);
|
data.push_back(info);
|
||||||
|
|
||||||
info.name = "dlc2_ui_mp";
|
info.name = "dlc2_ui_mp";
|
||||||
data.push_back(info);
|
data.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
|
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFiles::LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
void FastFiles::LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
||||||
{
|
{
|
||||||
std::vector<Game::XZoneInfo> data;
|
std::vector<Game::XZoneInfo> data;
|
||||||
Utils::Merge(&data, zoneInfo, zoneCount);
|
Utils::Merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
if (FastFiles::Exists("iw4x_code_post_gfx_mp"))
|
if (FastFiles::Exists("iw4x_code_post_gfx_mp"))
|
||||||
{
|
{
|
||||||
data.push_back({ "iw4x_code_post_gfx_mp", zoneInfo->allocFlags, zoneInfo->freeFlags });
|
data.push_back({ "iw4x_code_post_gfx_mp", zoneInfo->allocFlags, zoneInfo->freeFlags });
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::DB_LoadXAssets(data.data(), data.size(), sync);
|
Game::DB_LoadXAssets(data.data(), data.size(), sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This has to be called every time fastfiles are loaded :D
|
// This has to be called every time fastfiles are loaded :D
|
||||||
void FastFiles::LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
void FastFiles::LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
||||||
{
|
{
|
||||||
std::vector<Game::XZoneInfo> data;
|
std::vector<Game::XZoneInfo> data;
|
||||||
Utils::Merge(&data, zoneInfo, zoneCount);
|
Utils::Merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
Game::XZoneInfo info = { nullptr, 4, 0 };
|
Game::XZoneInfo info = { nullptr, 4, 0 };
|
||||||
|
|
||||||
// Not sure how they should be loaded :S
|
// Not sure how they should be loaded :S
|
||||||
std::string langZone = Utils::VA("iw4x_localized_%s", Game::Win_GetLanguage());
|
std::string langZone = fmt::sprintf("iw4x_localized_%s", Game::Win_GetLanguage());
|
||||||
|
|
||||||
if (FastFiles::Exists(langZone))
|
if (FastFiles::Exists(langZone))
|
||||||
{
|
{
|
||||||
info.name = langZone.data();
|
info.name = langZone.data();
|
||||||
}
|
}
|
||||||
else if (FastFiles::Exists("iw4x_localized_english")) // Fallback
|
else if (FastFiles::Exists("iw4x_localized_english")) // Fallback
|
||||||
{
|
{
|
||||||
info.name = "iw4x_localized_english";
|
info.name = "iw4x_localized_english";
|
||||||
}
|
}
|
||||||
|
|
||||||
data.push_back(info);
|
data.push_back(info);
|
||||||
|
|
||||||
Game::DB_LoadXAssets(data.data(), data.size(), sync);
|
Game::DB_LoadXAssets(data.data(), data.size(), sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name is a bit weird, due to FasFileS and ExistS :P
|
// Name is a bit weird, due to FasFileS and ExistS :P
|
||||||
bool FastFiles::Exists(std::string file)
|
bool FastFiles::Exists(std::string file)
|
||||||
{
|
{
|
||||||
std::string path = FastFiles::GetZoneLocation(file.data());
|
std::string path = FastFiles::GetZoneLocation(file.data());
|
||||||
path.append(file);
|
path.append(file);
|
||||||
|
|
||||||
if (!Utils::EndsWith(path.data(), ".ff"))
|
if (!Utils::String::EndsWith(path.data(), ".ff"))
|
||||||
{
|
{
|
||||||
path.append(".ff");
|
path.append(".ff");
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::ifstream(path.data()).good();
|
return std::ifstream(path.data()).good();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* FastFiles::GetZoneLocation(const char* file)
|
const char* FastFiles::GetZoneLocation(const char* file)
|
||||||
{
|
{
|
||||||
const char* dir = Dvar::Var("fs_basepath").Get<const char*>();
|
const char* dir = Dvar::Var("fs_basepath").Get<const char*>();
|
||||||
|
|
||||||
for (auto &path : FastFiles::ZonePaths)
|
for (auto &path : FastFiles::ZonePaths)
|
||||||
{
|
{
|
||||||
std::string absoluteFile = Utils::VA("%s\\%s%s", dir, path.data(), file);
|
std::string absoluteFile = fmt::sprintf("%s\\%s%s", dir, path.data(), file);
|
||||||
|
|
||||||
// No ".ff" appended, append it manually
|
// No ".ff" appended, append it manually
|
||||||
if (!Utils::EndsWith(absoluteFile.data(), ".ff"))
|
if (!Utils::String::EndsWith(absoluteFile, ".ff"))
|
||||||
{
|
{
|
||||||
absoluteFile.append(".ff");
|
absoluteFile.append(".ff");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if FastFile exists
|
// Check if FastFile exists
|
||||||
if (std::ifstream(absoluteFile.data()).good())
|
if (Utils::IO::FileExists(absoluteFile))
|
||||||
{
|
{
|
||||||
return Utils::VA("%s", path.data());
|
return Utils::String::VA("%s", path.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::VA("zone\\%s\\", Game::Win_GetLanguage());
|
return Utils::String::VA("zone\\%s\\", Game::Win_GetLanguage());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFiles::AddZonePath(std::string path)
|
void FastFiles::AddZonePath(std::string path)
|
||||||
{
|
{
|
||||||
FastFiles::ZonePaths.push_back(path);
|
FastFiles::ZonePaths.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FastFiles::Current()
|
std::string FastFiles::Current()
|
||||||
{
|
{
|
||||||
const char* file = (Utils::Hook::Get<char*>(0x112A680) + 4);
|
const char* file = (Utils::Hook::Get<char*>(0x112A680) + 4);
|
||||||
|
|
||||||
if (file == reinterpret_cast<char*>(4))
|
if (file == reinterpret_cast<char*>(4))
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFiles::ReadVersionStub(unsigned int* version, int size)
|
void FastFiles::ReadVersionStub(unsigned int* version, int size)
|
||||||
{
|
{
|
||||||
Game::DB_ReadXFileUncompressed(version, size);
|
Game::DB_ReadXFileUncompressed(version, size);
|
||||||
|
|
||||||
// Allow loading out custom version
|
// Allow loading out custom version
|
||||||
if (*version == XFILE_VERSION_IW4X)
|
if (*version == XFILE_VERSION_IW4X)
|
||||||
{
|
{
|
||||||
*version = XFILE_VERSION;
|
*version = XFILE_VERSION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFiles::FastFiles()
|
FastFiles::FastFiles()
|
||||||
{
|
{
|
||||||
Dvar::Register<bool>("ui_zoneDebug", false, Game::dvar_flag::DVAR_FLAG_SAVED, "Display current loaded zone.");
|
Dvar::Register<bool>("ui_zoneDebug", false, Game::dvar_flag::DVAR_FLAG_SAVED, "Display current loaded zone.");
|
||||||
|
|
||||||
// Redirect zone paths
|
// Redirect zone paths
|
||||||
Utils::Hook(0x44DA90, FastFiles::GetZoneLocation, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x44DA90, FastFiles::GetZoneLocation, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// Allow loading 'newer' zones
|
// Allow loading 'newer' zones
|
||||||
Utils::Hook(0x4158E7, FastFiles::ReadVersionStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4158E7, FastFiles::ReadVersionStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Allow custom zone loading
|
// Allow custom zone loading
|
||||||
if (!ZoneBuilder::IsEnabled())
|
if (!ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).Install()->Quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
// basic checks (hash jumps, both normal and playlist)
|
// basic checks (hash jumps, both normal and playlist)
|
||||||
Utils::Hook::Nop(0x5B97A3, 2);
|
Utils::Hook::Nop(0x5B97A3, 2);
|
||||||
Utils::Hook::Nop(0x5BA493, 2);
|
Utils::Hook::Nop(0x5BA493, 2);
|
||||||
|
|
||||||
Utils::Hook::Nop(0x5B991C, 2);
|
Utils::Hook::Nop(0x5B991C, 2);
|
||||||
Utils::Hook::Nop(0x5BA60C, 2);
|
Utils::Hook::Nop(0x5BA60C, 2);
|
||||||
|
|
||||||
Utils::Hook::Nop(0x5B97B4, 2);
|
Utils::Hook::Nop(0x5B97B4, 2);
|
||||||
Utils::Hook::Nop(0x5BA4A4, 2);
|
Utils::Hook::Nop(0x5BA4A4, 2);
|
||||||
|
|
||||||
// allow loading of IWffu (unsigned) files
|
// allow loading of IWffu (unsigned) files
|
||||||
Utils::Hook::Set<BYTE>(0x4158D9, 0xEB); // main function
|
Utils::Hook::Set<BYTE>(0x4158D9, 0xEB); // main function
|
||||||
Utils::Hook::Nop(0x4A1D97, 2); // DB_AuthLoad_InflateInit
|
Utils::Hook::Nop(0x4A1D97, 2); // DB_AuthLoad_InflateInit
|
||||||
|
|
||||||
// some other, unknown, check
|
// some other, unknown, check
|
||||||
Utils::Hook::Set<BYTE>(0x5B9912, 0xB8);
|
Utils::Hook::Set<BYTE>(0x5B9912, 0xB8);
|
||||||
Utils::Hook::Set<DWORD>(0x5B9913, 1);
|
Utils::Hook::Set<DWORD>(0x5B9913, 1);
|
||||||
|
|
||||||
Utils::Hook::Set<BYTE>(0x5BA602, 0xB8);
|
Utils::Hook::Set<BYTE>(0x5BA602, 0xB8);
|
||||||
Utils::Hook::Set<DWORD>(0x5BA603, 1);
|
Utils::Hook::Set<DWORD>(0x5BA603, 1);
|
||||||
|
|
||||||
// Add custom zone paths
|
// Add custom zone paths
|
||||||
FastFiles::AddZonePath("zone\\patch\\");
|
FastFiles::AddZonePath("zone\\patch\\");
|
||||||
FastFiles::AddZonePath("zone\\dlc\\");
|
FastFiles::AddZonePath("zone\\dlc\\");
|
||||||
|
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").Get<bool>()) return;
|
if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").Get<bool>()) return;
|
||||||
|
|
||||||
Game::Font* font = Game::R_RegisterFont("fonts/consoleFont"); // Inlining that seems to skip xpos, no idea why xD
|
Game::Font* font = Game::R_RegisterFont("fonts/consoleFont"); // Inlining that seems to skip xpos, no idea why xD
|
||||||
float color[4] = { 1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f) };
|
float color[4] = { 1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f) };
|
||||||
Game::R_AddCmdDrawText(Utils::VA("Loading FastFile: %s", FastFiles::Current().data()), 0x7FFFFFFF, font, 5.0f, static_cast<float>(Renderer::Height() - 5), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL);
|
Game::R_AddCmdDrawText(Utils::String::VA("Loading FastFile: %s", FastFiles::Current().data()), 0x7FFFFFFF, font, 5.0f, static_cast<float>(Renderer::Height() - 5), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL);
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::Add("loadzone", [] (Command::Params params)
|
Command::Add("loadzone", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2) return;
|
if (params.Length() < 2) return;
|
||||||
|
|
||||||
Game::XZoneInfo info;
|
Game::XZoneInfo info;
|
||||||
info.name = params[1];
|
info.name = params[1];
|
||||||
info.allocFlags = 1;//0x01000000;
|
info.allocFlags = 1;//0x01000000;
|
||||||
info.freeFlags = 0;
|
info.freeFlags = 0;
|
||||||
|
|
||||||
Game::DB_LoadXAssets(&info, 1, true);
|
Game::DB_LoadXAssets(&info, 1, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFiles::~FastFiles()
|
FastFiles::~FastFiles()
|
||||||
{
|
{
|
||||||
FastFiles::ZonePaths.clear();
|
FastFiles::ZonePaths.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,154 +1,154 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
void FileSystem::File::Read()
|
void FileSystem::File::Read()
|
||||||
{
|
{
|
||||||
char* buffer = nullptr;
|
char* buffer = nullptr;
|
||||||
int size = Game::FS_ReadFile(this->FilePath.data(), &buffer);
|
int size = Game::FS_ReadFile(this->FilePath.data(), &buffer);
|
||||||
|
|
||||||
this->Buffer.clear();
|
this->Buffer.clear();
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
{
|
{
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
Game::FS_FreeFile(buffer);
|
Game::FS_FreeFile(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->Buffer.append(buffer, size);
|
this->Buffer.append(buffer, size);
|
||||||
Game::FS_FreeFile(buffer);
|
Game::FS_FreeFile(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::FileWriter::Write(std::string data)
|
void FileSystem::FileWriter::Write(std::string data)
|
||||||
{
|
{
|
||||||
if (this->Handle)
|
if (this->Handle)
|
||||||
{
|
{
|
||||||
Game::FS_Write(data.data(), data.size(), this->Handle);
|
Game::FS_Write(data.data(), data.size(), this->Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::FileWriter::Open()
|
void FileSystem::FileWriter::Open()
|
||||||
{
|
{
|
||||||
this->Handle = Game::FS_FOpenFileWrite(this->FilePath.data());
|
this->Handle = Game::FS_FOpenFileWrite(this->FilePath.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::FileWriter::Close()
|
void FileSystem::FileWriter::Close()
|
||||||
{
|
{
|
||||||
if (this->Handle)
|
if (this->Handle)
|
||||||
{
|
{
|
||||||
Game::FS_FCloseFile(this->Handle);
|
Game::FS_FCloseFile(this->Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> FileSystem::GetFileList(std::string path, std::string extension)
|
std::vector<std::string> FileSystem::GetFileList(std::string path, std::string extension)
|
||||||
{
|
{
|
||||||
std::vector<std::string> fileList;
|
std::vector<std::string> fileList;
|
||||||
|
|
||||||
int numFiles = 0;
|
int numFiles = 0;
|
||||||
char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0);
|
char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0);
|
||||||
|
|
||||||
if (files)
|
if (files)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numFiles; ++i)
|
for (int i = 0; i < numFiles; ++i)
|
||||||
{
|
{
|
||||||
if (files[i])
|
if (files[i])
|
||||||
{
|
{
|
||||||
fileList.push_back(files[i]);
|
fileList.push_back(files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::FS_FreeFileList(files);
|
Game::FS_FreeFileList(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> FileSystem::GetSysFileList(std::string path, std::string extension, bool folders)
|
std::vector<std::string> FileSystem::GetSysFileList(std::string path, std::string extension, bool folders)
|
||||||
{
|
{
|
||||||
std::vector<std::string> fileList;
|
std::vector<std::string> fileList;
|
||||||
|
|
||||||
int numFiles = 0;
|
int numFiles = 0;
|
||||||
char** files = Game::Sys_ListFiles(path.data(), extension.data(), NULL, &numFiles, folders);
|
char** files = Game::Sys_ListFiles(path.data(), extension.data(), NULL, &numFiles, folders);
|
||||||
|
|
||||||
if (files)
|
if (files)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numFiles; ++i)
|
for (int i = 0; i < numFiles; ++i)
|
||||||
{
|
{
|
||||||
if (files[i])
|
if (files[i])
|
||||||
{
|
{
|
||||||
fileList.push_back(files[i]);
|
fileList.push_back(files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::Sys_FreeFileList(files);
|
Game::Sys_FreeFileList(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::DeleteFile(std::string folder, std::string file)
|
void FileSystem::DeleteFile(std::string folder, std::string file)
|
||||||
{
|
{
|
||||||
char path[MAX_PATH] = { 0 };
|
char path[MAX_PATH] = { 0 };
|
||||||
Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").Get<const char*>(), reinterpret_cast<char*>(0x63D0BB8), Utils::VA("%s/%s", folder.data(), file.data()), reinterpret_cast<char**>(&path));
|
Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").Get<const char*>(), reinterpret_cast<char*>(0x63D0BB8), Utils::String::VA("%s/%s", folder.data(), file.data()), reinterpret_cast<char**>(&path));
|
||||||
Game::FS_Remove(path);
|
Game::FS_Remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::RegisterFolder(const char* folder)
|
void FileSystem::RegisterFolder(const char* folder)
|
||||||
{
|
{
|
||||||
std::string fs_cdpath = Dvar::Var("fs_cdpath").Get<std::string>();
|
std::string fs_cdpath = Dvar::Var("fs_cdpath").Get<std::string>();
|
||||||
std::string fs_basepath = Dvar::Var("fs_basepath").Get<std::string>();
|
std::string fs_basepath = Dvar::Var("fs_basepath").Get<std::string>();
|
||||||
std::string fs_homepath = Dvar::Var("fs_homepath").Get<std::string>();
|
std::string fs_homepath = Dvar::Var("fs_homepath").Get<std::string>();
|
||||||
|
|
||||||
if (!fs_cdpath.empty()) Game::FS_AddLocalizedGameDirectory(fs_cdpath.data(), folder);
|
if (!fs_cdpath.empty()) Game::FS_AddLocalizedGameDirectory(fs_cdpath.data(), folder);
|
||||||
if (!fs_basepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_basepath.data(), folder);
|
if (!fs_basepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_basepath.data(), folder);
|
||||||
if (!fs_homepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_homepath.data(), folder);
|
if (!fs_homepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_homepath.data(), folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::RegisterFolders()
|
void FileSystem::RegisterFolders()
|
||||||
{
|
{
|
||||||
FileSystem::RegisterFolder("userraw");
|
FileSystem::RegisterFolder("userraw");
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) FileSystem::StartupStub()
|
void __declspec(naked) FileSystem::StartupStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push esi
|
push esi
|
||||||
call FileSystem::RegisterFolders
|
call FileSystem::RegisterFolders
|
||||||
pop esi
|
pop esi
|
||||||
|
|
||||||
mov edx, ds:63D0CC0h
|
mov edx, ds:63D0CC0h
|
||||||
|
|
||||||
mov eax, 48264Dh
|
mov eax, 48264Dh
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileSystem::ExecIsFSStub(const char* execFilename)
|
int FileSystem::ExecIsFSStub(const char* execFilename)
|
||||||
{
|
{
|
||||||
return !File(execFilename).Exists();
|
return !File(execFilename).Exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystem::FileSystem()
|
FileSystem::FileSystem()
|
||||||
{
|
{
|
||||||
// Filesystem config checks
|
// Filesystem config checks
|
||||||
Utils::Hook(0x6098FD, FileSystem::ExecIsFSStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x6098FD, FileSystem::ExecIsFSStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Register additional folders
|
// Register additional folders
|
||||||
Utils::Hook(0x482647, FileSystem::StartupStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x482647, FileSystem::StartupStub, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// exec whitelist removal (YAYFINITY WARD)
|
// exec whitelist removal (YAYFINITY WARD)
|
||||||
Utils::Hook::Nop(0x609685, 5);
|
Utils::Hook::Nop(0x609685, 5);
|
||||||
Utils::Hook::Nop(0x60968C, 2);
|
Utils::Hook::Nop(0x60968C, 2);
|
||||||
|
|
||||||
// ignore 'no iwd files found in main'
|
// ignore 'no iwd files found in main'
|
||||||
Utils::Hook::Nop(0x642A4B, 5);
|
Utils::Hook::Nop(0x642A4B, 5);
|
||||||
|
|
||||||
// Ignore bad magic, when trying to free hunk when it's already cleared
|
// Ignore bad magic, when trying to free hunk when it's already cleared
|
||||||
Utils::Hook::Set<WORD>(0x49AACE, 0xC35E);
|
Utils::Hook::Set<WORD>(0x49AACE, 0xC35E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::vector<std::string> Flags::EnabledFlags;
|
std::vector<std::string> Flags::EnabledFlags;
|
||||||
|
|
||||||
bool Flags::HasFlag(std::string flag)
|
bool Flags::HasFlag(std::string flag)
|
||||||
{
|
{
|
||||||
for (auto entry : Flags::EnabledFlags)
|
for (auto entry : Flags::EnabledFlags)
|
||||||
{
|
{
|
||||||
if (Utils::StrToLower(entry) == Utils::StrToLower(flag))
|
if (Utils::String::StrToLower(entry) == Utils::String::StrToLower(flag))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flags::ParseFlags()
|
void Flags::ParseFlags()
|
||||||
{
|
{
|
||||||
int numArgs;
|
int numArgs;
|
||||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs);
|
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs);
|
||||||
|
|
||||||
if (argv)
|
if (argv)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numArgs; ++i)
|
for (int i = 0; i < numArgs; ++i)
|
||||||
{
|
{
|
||||||
std::wstring wFlag(argv[i]);
|
std::wstring wFlag(argv[i]);
|
||||||
if (wFlag[0] == L'-')
|
if (wFlag[0] == L'-')
|
||||||
{
|
{
|
||||||
Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end()));
|
Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalFree(argv);
|
LocalFree(argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags::Flags()
|
Flags::Flags()
|
||||||
{
|
{
|
||||||
Flags::ParseFlags();
|
Flags::ParseFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags::~Flags()
|
Flags::~Flags()
|
||||||
{
|
{
|
||||||
Flags::EnabledFlags.clear();
|
Flags::EnabledFlags.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,201 +1,201 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Dvar::Var Localization::UseLocalization;
|
Dvar::Var Localization::UseLocalization;
|
||||||
std::map<std::string, Game::LocalizedEntry*> Localization::LocalizeMap;
|
std::map<std::string, Game::LocalizedEntry*> Localization::LocalizeMap;
|
||||||
std::map<std::string, Game::LocalizedEntry*> Localization::TempLocalizeMap;
|
std::map<std::string, Game::LocalizedEntry*> Localization::TempLocalizeMap;
|
||||||
|
|
||||||
void Localization::Set(const char* key, const char* value)
|
void Localization::Set(std::string key, std::string value)
|
||||||
{
|
{
|
||||||
if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
|
if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
|
||||||
{
|
{
|
||||||
Game::LocalizedEntry* entry = Localization::LocalizeMap[key];
|
Game::LocalizedEntry* entry = Localization::LocalizeMap[key];
|
||||||
|
|
||||||
char* newStaticValue = Utils::Memory::DuplicateString(value);
|
char* newStaticValue = Utils::Memory::DuplicateString(value);
|
||||||
if (!newStaticValue) return;
|
if (!newStaticValue) return;
|
||||||
if (entry->value) Utils::Memory::Free(entry->value);
|
if (entry->value) Utils::Memory::Free(entry->value);
|
||||||
entry->value = newStaticValue;
|
entry->value = newStaticValue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::LocalizedEntry* entry = Utils::Memory::AllocateArray<Game::LocalizedEntry>(1);
|
Game::LocalizedEntry* entry = Utils::Memory::AllocateArray<Game::LocalizedEntry>(1);
|
||||||
if (!entry) return;
|
if (!entry) return;
|
||||||
|
|
||||||
entry->name = Utils::Memory::DuplicateString(key);
|
entry->name = Utils::Memory::DuplicateString(key);
|
||||||
if (!entry->name)
|
if (!entry->name)
|
||||||
{
|
{
|
||||||
Utils::Memory::Free(entry);
|
Utils::Memory::Free(entry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->value = Utils::Memory::DuplicateString(value);
|
entry->value = Utils::Memory::DuplicateString(value);
|
||||||
if (!entry->value)
|
if (!entry->value)
|
||||||
{
|
{
|
||||||
Utils::Memory::Free(entry->name);
|
Utils::Memory::Free(entry->name);
|
||||||
Utils::Memory::Free(entry);
|
Utils::Memory::Free(entry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::LocalizeMap[key] = entry;
|
Localization::LocalizeMap[key] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Localization::Get(const char* key)
|
const char* Localization::Get(const char* key)
|
||||||
{
|
{
|
||||||
if (!Localization::UseLocalization.Get<bool>()) return key;
|
if (!Localization::UseLocalization.Get<bool>()) return key;
|
||||||
|
|
||||||
Game::LocalizedEntry* entry = nullptr;
|
Game::LocalizedEntry* entry = nullptr;
|
||||||
|
|
||||||
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
|
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
|
||||||
{
|
{
|
||||||
entry = Localization::TempLocalizeMap[key];
|
entry = Localization::TempLocalizeMap[key];
|
||||||
}
|
}
|
||||||
else if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
|
else if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
|
||||||
{
|
{
|
||||||
entry = Localization::LocalizeMap[key];
|
entry = Localization::LocalizeMap[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entry || !entry->value) entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE, key).localize;
|
if (!entry || !entry->value) entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE, key).localize;
|
||||||
|
|
||||||
if (entry && entry->value)
|
if (entry && entry->value)
|
||||||
{
|
{
|
||||||
return entry->value;
|
return entry->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Localization::SetTemp(std::string key, std::string value)
|
void Localization::SetTemp(std::string key, std::string value)
|
||||||
{
|
{
|
||||||
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
|
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
|
||||||
{
|
{
|
||||||
Game::LocalizedEntry* entry = Localization::TempLocalizeMap[key];
|
Game::LocalizedEntry* entry = Localization::TempLocalizeMap[key];
|
||||||
if(entry->value) Utils::Memory::Free(entry->value);
|
if(entry->value) Utils::Memory::Free(entry->value);
|
||||||
entry->value = Utils::Memory::DuplicateString(value);
|
entry->value = Utils::Memory::DuplicateString(value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game::LocalizedEntry* entry = Utils::Memory::AllocateArray<Game::LocalizedEntry>(1);
|
Game::LocalizedEntry* entry = Utils::Memory::AllocateArray<Game::LocalizedEntry>(1);
|
||||||
if (!entry) return;
|
if (!entry) return;
|
||||||
|
|
||||||
entry->name = Utils::Memory::DuplicateString(key);
|
entry->name = Utils::Memory::DuplicateString(key);
|
||||||
if (!entry->name)
|
if (!entry->name)
|
||||||
{
|
{
|
||||||
Utils::Memory::Free(entry);
|
Utils::Memory::Free(entry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->value = Utils::Memory::DuplicateString(value);
|
entry->value = Utils::Memory::DuplicateString(value);
|
||||||
if (!entry->value)
|
if (!entry->value)
|
||||||
{
|
{
|
||||||
Utils::Memory::Free(entry->name);
|
Utils::Memory::Free(entry->name);
|
||||||
Utils::Memory::Free(entry);
|
Utils::Memory::Free(entry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::TempLocalizeMap[key] = entry;
|
Localization::TempLocalizeMap[key] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Localization::ClearTemp()
|
void Localization::ClearTemp()
|
||||||
{
|
{
|
||||||
for (auto i = Localization::TempLocalizeMap.begin(); i != Localization::TempLocalizeMap.end(); ++i)
|
for (auto i = Localization::TempLocalizeMap.begin(); i != Localization::TempLocalizeMap.end(); ++i)
|
||||||
{
|
{
|
||||||
if (i->second)
|
if (i->second)
|
||||||
{
|
{
|
||||||
if (i->second->name) Utils::Memory::Free(i->second->name);
|
if (i->second->name) Utils::Memory::Free(i->second->name);
|
||||||
if (i->second->value) Utils::Memory::Free(i->second->value);
|
if (i->second->value) Utils::Memory::Free(i->second->value);
|
||||||
Utils::Memory::Free(i->second);
|
Utils::Memory::Free(i->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::TempLocalizeMap.clear();
|
Localization::TempLocalizeMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __stdcall Localization::SetStringStub(const char* key, const char* value, bool isEnglish)
|
void __stdcall Localization::SetStringStub(const char* key, const char* value, bool isEnglish)
|
||||||
{
|
{
|
||||||
Localization::Set(key, value);
|
Localization::Set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Localization::SELoadLanguageStub()
|
DWORD Localization::SELoadLanguageStub()
|
||||||
{
|
{
|
||||||
//'official' iw4m localized strings
|
//'official' iw4x localized strings
|
||||||
Game::SE_Load("localizedstrings/iw4m.str", 0);
|
Game::SE_Load("localizedstrings/iw4x.str", 0);
|
||||||
|
|
||||||
return Utils::Hook::Call<DWORD()>(0x629E20)();
|
return Utils::Hook::Call<DWORD()>(0x629E20)();
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::Localization()
|
Localization::Localization()
|
||||||
{
|
{
|
||||||
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE, [] (Game::XAssetType, std::string filename)
|
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE, [] (Game::XAssetType, std::string filename)
|
||||||
{
|
{
|
||||||
Game::XAssetHeader header = { 0 };
|
Game::XAssetHeader header = { 0 };
|
||||||
|
|
||||||
if (Localization::TempLocalizeMap.find(filename) != Localization::TempLocalizeMap.end())
|
if (Localization::TempLocalizeMap.find(filename) != Localization::TempLocalizeMap.end())
|
||||||
{
|
{
|
||||||
header.localize = Localization::TempLocalizeMap[filename];
|
header.localize = Localization::TempLocalizeMap[filename];
|
||||||
}
|
}
|
||||||
else if (Localization::LocalizeMap.find(filename) != Localization::LocalizeMap.end())
|
else if (Localization::LocalizeMap.find(filename) != Localization::LocalizeMap.end())
|
||||||
{
|
{
|
||||||
header.localize = Localization::LocalizeMap[filename];
|
header.localize = Localization::LocalizeMap[filename];
|
||||||
}
|
}
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Resolving hook
|
// Resolving hook
|
||||||
Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// Set loading entry point
|
// Set loading entry point
|
||||||
Utils::Hook(0x41D859, Localization::SELoadLanguageStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x41D859, Localization::SELoadLanguageStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Overwrite SetString
|
// Overwrite SetString
|
||||||
Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// TODO: Get rid of those!
|
// TODO: Get rid of those!
|
||||||
Localization::Set("MENU_SEARCHINGFORGAMES_100MS", "");
|
Localization::Set("MENU_SEARCHINGFORGAMES_100MS", "");
|
||||||
Localization::Set("MP_SEARCHING_FOR_PLAYER", "Waiting");
|
Localization::Set("MP_SEARCHING_FOR_PLAYER", "Waiting");
|
||||||
Localization::Set("MENU_WAITING_FOR_MORE_PLAYERS_TEAMS", "Waiting for more players to balance teams");
|
Localization::Set("MENU_WAITING_FOR_MORE_PLAYERS_TEAMS", "Waiting for more players to balance teams");
|
||||||
Localization::Set("MENU_MOTD", "News");
|
Localization::Set("MENU_MOTD", "News");
|
||||||
Localization::Set("MENU_MOTD_CAPS", "NEWS");
|
Localization::Set("MENU_MOTD_CAPS", "NEWS");
|
||||||
Localization::Set("MENU_MODS", "Mods");
|
Localization::Set("MENU_MODS", "Mods");
|
||||||
Localization::Set("MENU_MODS_CAPS", "MODS");
|
Localization::Set("MENU_MODS_CAPS", "MODS");
|
||||||
Localization::Set("MPUI_DESC_MODS", "Browse your Mods.");
|
Localization::Set("MPUI_DESC_MODS", "Browse your Mods.");
|
||||||
Localization::Set("MENU_THEATER", "Theater");
|
Localization::Set("MENU_THEATER", "Theater");
|
||||||
Localization::Set("MENU_THEATER_CAPS", "THEATER");
|
Localization::Set("MENU_THEATER_CAPS", "THEATER");
|
||||||
Localization::Set("MPUI_DESC_THEATER", "View your played matches.");
|
Localization::Set("MPUI_DESC_THEATER", "View your played matches.");
|
||||||
Localization::Set("MENU_FOV", "Field of View");
|
Localization::Set("MENU_FOV", "Field of View");
|
||||||
Localization::Set("MENU_NOBORDER", "Disable Window Border");
|
Localization::Set("MENU_NOBORDER", "Disable Window Border");
|
||||||
Localization::Set("MENU_NATIVECURSOR", "Display native cursor");
|
Localization::Set("MENU_NATIVECURSOR", "Display native cursor");
|
||||||
Localization::Set("MENU_MAXPACKETS", "Max. Packets per frame");
|
Localization::Set("MENU_MAXPACKETS", "Max. Packets per frame");
|
||||||
Localization::Set("MENU_SNAPS", "Snapshot rate");
|
Localization::Set("MENU_SNAPS", "Snapshot rate");
|
||||||
Localization::Set("MENU_LAGOMETER", "Show Lagometer");
|
Localization::Set("MENU_LAGOMETER", "Show Lagometer");
|
||||||
Localization::Set("MENU_DRAWFPS", "Show FPS");
|
Localization::Set("MENU_DRAWFPS", "Show FPS");
|
||||||
Localization::Set("MENU_FPSLABELS", "Show FPS Labels");
|
Localization::Set("MENU_FPSLABELS", "Show FPS Labels");
|
||||||
Localization::Set("MENU_NEWCOLORS", "Use new color codes");
|
Localization::Set("MENU_NEWCOLORS", "Use new color codes");
|
||||||
Localization::Set("MPUI_DESC_OPTIONS", "Set your game options.");
|
Localization::Set("MPUI_DESC_OPTIONS", "Set your game options.");
|
||||||
Localization::Set("MPUI_DESC_QUIT", "Quit the game.");
|
Localization::Set("MPUI_DESC_QUIT", "Quit the game.");
|
||||||
|
|
||||||
Localization::Set("PLATFORM_REFRESH_LIST", "Refresh List ^0- ^3F5");
|
Localization::Set("PLATFORM_REFRESH_LIST", "Refresh List ^0- ^3F5");
|
||||||
Localization::Set("PLATFORM_REFRESH_LIST_CAPS", "REFRESH LIST ^0- ^3F5");
|
Localization::Set("PLATFORM_REFRESH_LIST_CAPS", "REFRESH LIST ^0- ^3F5");
|
||||||
|
|
||||||
Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings");
|
Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings");
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::~Localization()
|
Localization::~Localization()
|
||||||
{
|
{
|
||||||
Localization::ClearTemp();
|
Localization::ClearTemp();
|
||||||
|
|
||||||
for (auto i = Localization::LocalizeMap.begin(); i != Localization::LocalizeMap.end(); ++i)
|
for (auto i = Localization::LocalizeMap.begin(); i != Localization::LocalizeMap.end(); ++i)
|
||||||
{
|
{
|
||||||
if (i->second)
|
if (i->second)
|
||||||
{
|
{
|
||||||
if (i->second->name) Utils::Memory::Free(i->second->name);
|
if (i->second->name) Utils::Memory::Free(i->second->name);
|
||||||
if (i->second->value) Utils::Memory::Free(i->second->value);
|
if (i->second->value) Utils::Memory::Free(i->second->value);
|
||||||
Utils::Memory::Free(i->second);
|
Utils::Memory::Free(i->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Localization::LocalizeMap.clear();
|
Localization::LocalizeMap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
class Localization : public Component
|
class Localization : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Localization();
|
Localization();
|
||||||
~Localization();
|
~Localization();
|
||||||
const char* GetName() { return "Localization"; };
|
const char* GetName() { return "Localization"; };
|
||||||
|
|
||||||
static void Set(const char* key, const char* value);
|
static void Set(std::string key, std::string value);
|
||||||
static const char* Get(const char* key);
|
static const char* Get(const char* key);
|
||||||
|
|
||||||
static void SetTemp(std::string key, std::string value);
|
static void SetTemp(std::string key, std::string value);
|
||||||
static void ClearTemp();
|
static void ClearTemp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map<std::string, Game::LocalizedEntry*> LocalizeMap;
|
static std::map<std::string, Game::LocalizedEntry*> LocalizeMap;
|
||||||
static std::map<std::string, Game::LocalizedEntry*> TempLocalizeMap;
|
static std::map<std::string, Game::LocalizedEntry*> TempLocalizeMap;
|
||||||
static Dvar::Var UseLocalization;
|
static Dvar::Var UseLocalization;
|
||||||
|
|
||||||
static void __stdcall SetStringStub(const char* key, const char* value, bool isEnglish);
|
static void __stdcall SetStringStub(const char* key, const char* value, bool isEnglish);
|
||||||
static DWORD SELoadLanguageStub();
|
static DWORD SELoadLanguageStub();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,223 +1,223 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> Maps::DependencyList;
|
std::map<std::string, std::string> Maps::DependencyList;
|
||||||
std::vector<std::string> Maps::CurrentDependencies;
|
std::vector<std::string> Maps::CurrentDependencies;
|
||||||
|
|
||||||
std::vector<Game::XAssetEntry> Maps::EntryPool;
|
std::vector<Game::XAssetEntry> Maps::EntryPool;
|
||||||
|
|
||||||
void Maps::LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
void Maps::LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
|
||||||
{
|
{
|
||||||
if (!zoneInfo) return;
|
if (!zoneInfo) return;
|
||||||
|
|
||||||
Maps::CurrentDependencies.clear();
|
Maps::CurrentDependencies.clear();
|
||||||
for (auto i = Maps::DependencyList.begin(); i != Maps::DependencyList.end(); ++i)
|
for (auto i = Maps::DependencyList.begin(); i != Maps::DependencyList.end(); ++i)
|
||||||
{
|
{
|
||||||
if (std::regex_match(zoneInfo->name, std::regex(i->first)))
|
if (std::regex_match(zoneInfo->name, std::regex(i->first)))
|
||||||
{
|
{
|
||||||
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), i->second) == Maps::CurrentDependencies.end())
|
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), i->second) == Maps::CurrentDependencies.end())
|
||||||
{
|
{
|
||||||
Maps::CurrentDependencies.push_back(i->second);
|
Maps::CurrentDependencies.push_back(i->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Game::XZoneInfo> data;
|
std::vector<Game::XZoneInfo> data;
|
||||||
Utils::Merge(&data, zoneInfo, zoneCount);
|
Utils::Merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Maps::CurrentDependencies.size(); ++i)
|
for (unsigned int i = 0; i < Maps::CurrentDependencies.size(); ++i)
|
||||||
{
|
{
|
||||||
Game::XZoneInfo info;
|
Game::XZoneInfo info;
|
||||||
|
|
||||||
info.name = (&Maps::CurrentDependencies[i])->data();
|
info.name = (&Maps::CurrentDependencies[i])->data();
|
||||||
info.allocFlags = zoneInfo->allocFlags;
|
info.allocFlags = zoneInfo->allocFlags;
|
||||||
info.freeFlags = zoneInfo->freeFlags;
|
info.freeFlags = zoneInfo->freeFlags;
|
||||||
|
|
||||||
data.push_back(info);
|
data.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load patch files
|
// Load patch files
|
||||||
std::string patchZone = Utils::VA("patch_%s", zoneInfo->name);
|
std::string patchZone = fmt::sprintf("patch_%s", zoneInfo->name);
|
||||||
if (FastFiles::Exists(patchZone))
|
if (FastFiles::Exists(patchZone))
|
||||||
{
|
{
|
||||||
data.push_back({ patchZone.data(), zoneInfo->allocFlags, zoneInfo->freeFlags });
|
data.push_back({ patchZone.data(), zoneInfo->allocFlags, zoneInfo->freeFlags });
|
||||||
}
|
}
|
||||||
|
|
||||||
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
|
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maps::OverrideMapEnts(Game::MapEnts* ents)
|
void Maps::OverrideMapEnts(Game::MapEnts* ents)
|
||||||
{
|
{
|
||||||
auto callback = [] (Game::XAssetHeader header, void* ents)
|
auto callback = [] (Game::XAssetHeader header, void* ents)
|
||||||
{
|
{
|
||||||
Game::MapEnts* mapEnts = reinterpret_cast<Game::MapEnts*>(ents);
|
Game::MapEnts* mapEnts = reinterpret_cast<Game::MapEnts*>(ents);
|
||||||
Game::clipMap_t* clipMap = header.clipMap;
|
Game::clipMap_t* clipMap = header.clipMap;
|
||||||
|
|
||||||
if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name))
|
if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name))
|
||||||
{
|
{
|
||||||
clipMap->mapEnts = mapEnts;
|
clipMap->mapEnts = mapEnts;
|
||||||
//*Game::marMapEntsPtr = mapEnts;
|
//*Game::marMapEntsPtr = mapEnts;
|
||||||
//Game::G_SpawnEntitiesFromString();
|
//Game::G_SpawnEntitiesFromString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal doesn't lock the thread, as locking is impossible, due to executing this in the thread that holds the current lock
|
// Internal doesn't lock the thread, as locking is impossible, due to executing this in the thread that holds the current lock
|
||||||
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_COL_MAP_MP, callback, ents, true);
|
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_COL_MAP_MP, callback, ents, true);
|
||||||
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_COL_MAP_SP, callback, ents, true);
|
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_COL_MAP_SP, callback, ents, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict)
|
void Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict)
|
||||||
{
|
{
|
||||||
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end())
|
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end())
|
||||||
{
|
{
|
||||||
if (type == Game::XAssetType::ASSET_TYPE_GAME_MAP_MP || type == Game::XAssetType::ASSET_TYPE_COL_MAP_MP || type == Game::XAssetType::ASSET_TYPE_GFX_MAP || type == Game::XAssetType::ASSET_TYPE_MAP_ENTS || type == Game::XAssetType::ASSET_TYPE_COM_MAP || type == Game::XAssetType::ASSET_TYPE_FX_MAP)
|
if (type == Game::XAssetType::ASSET_TYPE_GAME_MAP_MP || type == Game::XAssetType::ASSET_TYPE_COL_MAP_MP || type == Game::XAssetType::ASSET_TYPE_GFX_MAP || type == Game::XAssetType::ASSET_TYPE_MAP_ENTS || type == Game::XAssetType::ASSET_TYPE_COM_MAP || type == Game::XAssetType::ASSET_TYPE_FX_MAP)
|
||||||
{
|
{
|
||||||
*restrict = true;
|
*restrict = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Game::XAssetType::ASSET_TYPE_ADDON_MAP_ENTS)
|
if (type == Game::XAssetType::ASSET_TYPE_ADDON_MAP_ENTS)
|
||||||
{
|
{
|
||||||
*restrict = true;
|
*restrict = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS)
|
if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS)
|
||||||
{
|
{
|
||||||
static std::string mapEntities;
|
static std::string mapEntities;
|
||||||
FileSystem::File ents(name + ".ents");
|
FileSystem::File ents(name + ".ents");
|
||||||
if (ents.Exists())
|
if (ents.Exists())
|
||||||
{
|
{
|
||||||
mapEntities = ents.GetBuffer();
|
mapEntities = ents.GetBuffer();
|
||||||
asset.mapEnts->entityString = const_cast<char*>(mapEntities.data());
|
asset.mapEnts->entityString = const_cast<char*>(mapEntities.data());
|
||||||
asset.mapEnts->numEntityChars = mapEntities.size() + 1;
|
asset.mapEnts->numEntityChars = mapEntities.size() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply new mapEnts
|
// Apply new mapEnts
|
||||||
// This doesn't work, entities are spawned before the patch file is loaded
|
// This doesn't work, entities are spawned before the patch file is loaded
|
||||||
//Maps::OverrideMapEnts(asset.mapEnts);
|
//Maps::OverrideMapEnts(asset.mapEnts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
|
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
|
||||||
{
|
{
|
||||||
if (_strnicmp("mp_", mapname, 3))
|
if (_strnicmp("mp_", mapname, 3))
|
||||||
{
|
{
|
||||||
format = "maps/%s.d3dbsp";
|
format = "maps/%s.d3dbsp";
|
||||||
|
|
||||||
// Adjust pointer to GameMap_Data
|
// Adjust pointer to GameMap_Data
|
||||||
Utils::Hook::Set<Game::GameMap_Data**>(0x4D90B7, &(Game::DB_XAssetPool[Game::XAssetType::ASSET_TYPE_GAME_MAP_SP].gameMapSP[0].data));
|
Utils::Hook::Set<Game::GameMap_Data**>(0x4D90B7, &(Game::DB_XAssetPool[Game::XAssetType::ASSET_TYPE_GAME_MAP_SP].gameMapSP[0].data));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Adjust pointer to GameMap_Data
|
// Adjust pointer to GameMap_Data
|
||||||
Utils::Hook::Set<Game::GameMap_Data**>(0x4D90B7, &(Game::DB_XAssetPool[Game::XAssetType::ASSET_TYPE_GAME_MAP_MP].gameMapMP[0].data));
|
Utils::Hook::Set<Game::GameMap_Data**>(0x4D90B7, &(Game::DB_XAssetPool[Game::XAssetType::ASSET_TYPE_GAME_MAP_MP].gameMapMP[0].data));
|
||||||
}
|
}
|
||||||
|
|
||||||
AntiCheat::EmptyHash();
|
AntiCheat::EmptyHash();
|
||||||
|
|
||||||
_snprintf(buffer, size, format, mapname);
|
_snprintf(buffer, size, format, mapname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maps::AddDependency(std::string expression, std::string zone)
|
void Maps::AddDependency(std::string expression, std::string zone)
|
||||||
{
|
{
|
||||||
// Test expression before adding it
|
// Test expression before adding it
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::regex _(expression);
|
std::regex _(expression);
|
||||||
}
|
}
|
||||||
catch (const std::exception e)
|
catch (const std::exception e)
|
||||||
{
|
{
|
||||||
MessageBoxA(0, Utils::VA("Invalid regular expression: %s", expression.data()), "Warning", MB_ICONEXCLAMATION);
|
MessageBoxA(0, Utils::String::VA("Invalid regular expression: %s", expression.data()), "Warning", MB_ICONEXCLAMATION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Maps::DependencyList[expression] = zone;
|
Maps::DependencyList[expression] = zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maps::ReallocateEntryPool()
|
void Maps::ReallocateEntryPool()
|
||||||
{
|
{
|
||||||
Assert_Size(Game::XAssetEntry, 16);
|
Assert_Size(Game::XAssetEntry, 16);
|
||||||
|
|
||||||
Maps::EntryPool.clear();
|
Maps::EntryPool.clear();
|
||||||
Maps::EntryPool.resize(789312);
|
Maps::EntryPool.resize(789312);
|
||||||
|
|
||||||
// Apply new size
|
// Apply new size
|
||||||
Utils::Hook::Set<DWORD>(0x5BAEB0, Maps::EntryPool.size());
|
Utils::Hook::Set<DWORD>(0x5BAEB0, Maps::EntryPool.size());
|
||||||
|
|
||||||
// Apply new pool
|
// Apply new pool
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x48E6F4, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x48E6F4, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x4C67E4, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x4C67E4, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x4C8584, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x4C8584, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA8, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA8, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0C4, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0C4, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0F5, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0F5, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB1D4, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB1D4, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB235, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB235, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB278, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB278, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB34C, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB34C, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB484, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB484, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB570, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB570, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB6B7, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB6B7, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB844, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB844, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB98D, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB98D, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBA66, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBA66, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBB8D, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBB8D, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBCB1, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBCB1, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBD9B, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBD9B, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBE4C, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBE4C, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF14, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF14, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF54, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF54, Maps::EntryPool.data());
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBFB8, Maps::EntryPool.data());
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBFB8, Maps::EntryPool.data());
|
||||||
|
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, Maps::EntryPool.data() + 1);
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, Maps::EntryPool.data() + 1);
|
||||||
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
|
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maps::Maps()
|
Maps::Maps()
|
||||||
{
|
{
|
||||||
// Restrict asset loading
|
// Restrict asset loading
|
||||||
AssetHandler::OnLoad(Maps::LoadAssetRestrict);
|
AssetHandler::OnLoad(Maps::LoadAssetRestrict);
|
||||||
|
|
||||||
// hunk size (was 300 MiB)
|
// hunk size (was 300 MiB)
|
||||||
Utils::Hook::Set<DWORD>(0x64A029, 0x1C200000); // 450 MiB
|
Utils::Hook::Set<DWORD>(0x64A029, 0x1C200000); // 450 MiB
|
||||||
Utils::Hook::Set<DWORD>(0x64A057, 0x1C200000);
|
Utils::Hook::Set<DWORD>(0x64A057, 0x1C200000);
|
||||||
|
|
||||||
// Intercept BSP name resolving
|
// Intercept BSP name resolving
|
||||||
Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Intercept map zone loading
|
// Intercept map zone loading
|
||||||
Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE, 14000);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE, 14000);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIM, 8192);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIM, 8192);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 10000);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 10000);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 3072);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 3072);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 196);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 196);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400);
|
||||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
|
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
|
||||||
|
|
||||||
Maps::ReallocateEntryPool();
|
Maps::ReallocateEntryPool();
|
||||||
|
|
||||||
// Dependencies
|
// Dependencies
|
||||||
//Maps::AddDependency("oilrig", "mp_subbase");
|
//Maps::AddDependency("oilrig", "mp_subbase");
|
||||||
//Maps::AddDependency("gulag", "mp_subbase");
|
//Maps::AddDependency("gulag", "mp_subbase");
|
||||||
//Maps::AddDependency("invasion", "mp_rust");
|
//Maps::AddDependency("invasion", "mp_rust");
|
||||||
Maps::AddDependency("co_hunted", "mp_storm");
|
Maps::AddDependency("co_hunted", "mp_storm");
|
||||||
Maps::AddDependency("^(?!mp_).*", "iw4x_dependencies_mp"); // All maps not starting with "mp_"
|
Maps::AddDependency("^(?!mp_).*", "iw4x_dependencies_mp"); // All maps not starting with "mp_"
|
||||||
}
|
}
|
||||||
|
|
||||||
Maps::~Maps()
|
Maps::~Maps()
|
||||||
{
|
{
|
||||||
Maps::EntryPool.clear();
|
Maps::EntryPool.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,102 +1,102 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::vector<std::string> ModList::Mods;
|
std::vector<std::string> ModList::Mods;
|
||||||
unsigned int ModList::CurrentMod;
|
unsigned int ModList::CurrentMod;
|
||||||
|
|
||||||
bool ModList::HasMod(std::string modName)
|
bool ModList::HasMod(std::string modName)
|
||||||
{
|
{
|
||||||
auto list = FileSystem::GetSysFileList(Dvar::Var("fs_basepath").Get<std::string>() + "\\mods", "", true);
|
auto list = FileSystem::GetSysFileList(Dvar::Var("fs_basepath").Get<std::string>() + "\\mods", "", true);
|
||||||
|
|
||||||
for (auto mod : list)
|
for (auto mod : list)
|
||||||
{
|
{
|
||||||
if (mod == modName)
|
if (mod == modName)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ModList::GetItemCount()
|
unsigned int ModList::GetItemCount()
|
||||||
{
|
{
|
||||||
return ModList::Mods.size();
|
return ModList::Mods.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ModList::GetItemText(unsigned int index, int column)
|
const char* ModList::GetItemText(unsigned int index, int column)
|
||||||
{
|
{
|
||||||
if (index < ModList::Mods.size())
|
if (index < ModList::Mods.size())
|
||||||
{
|
{
|
||||||
return ModList::Mods[index].data();
|
return ModList::Mods[index].data();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "...";
|
return "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModList::Select(unsigned int index)
|
void ModList::Select(unsigned int index)
|
||||||
{
|
{
|
||||||
ModList::CurrentMod = index;
|
ModList::CurrentMod = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModList::UIScript_LoadMods()
|
void ModList::UIScript_LoadMods()
|
||||||
{
|
{
|
||||||
auto folder = Dvar::Var("fs_basepath").Get<std::string>() + "\\mods";
|
auto folder = Dvar::Var("fs_basepath").Get<std::string>() + "\\mods";
|
||||||
Game::Com_Printf(0, "Searching for mods in %s...\n", folder.data());
|
Game::Com_Printf(0, "Searching for mods in %s...\n", folder.data());
|
||||||
ModList::Mods = FileSystem::GetSysFileList(folder, "", true);
|
ModList::Mods = FileSystem::GetSysFileList(folder, "", true);
|
||||||
Game::Com_Printf(0, "Found %i mods!\n", ModList::Mods.size());
|
Game::Com_Printf(0, "Found %i mods!\n", ModList::Mods.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModList::UIScript_RunMod()
|
void ModList::UIScript_RunMod()
|
||||||
{
|
{
|
||||||
if (ModList::CurrentMod < ModList::Mods.size())
|
if (ModList::CurrentMod < ModList::Mods.size())
|
||||||
{
|
{
|
||||||
auto fsGame = Dvar::Var("fs_game");
|
auto fsGame = Dvar::Var("fs_game");
|
||||||
fsGame.Set(Utils::VA("mods/%s", ModList::Mods[ModList::CurrentMod].data()));
|
fsGame.Set(fmt::sprintf("mods/%s", ModList::Mods[ModList::CurrentMod].data()));
|
||||||
fsGame.Get<Game::dvar_t*>()->pad2[0] = 1;
|
fsGame.Get<Game::dvar_t*>()->pad2[0] = 1;
|
||||||
|
|
||||||
if (Dvar::Var("cl_modVidRestart").Get<bool>())
|
if (Dvar::Var("cl_modVidRestart").Get<bool>())
|
||||||
{
|
{
|
||||||
Command::Execute("vid_restart", false);
|
Command::Execute("vid_restart", false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Command::Execute("closemenu mods_menu", false);
|
Command::Execute("closemenu mods_menu", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModList::UIScript_ClearMods()
|
void ModList::UIScript_ClearMods()
|
||||||
{
|
{
|
||||||
auto fsGame = Dvar::Var("fs_game");
|
auto fsGame = Dvar::Var("fs_game");
|
||||||
fsGame.Set("");
|
fsGame.Set("");
|
||||||
fsGame.Get<Game::dvar_t*>()->pad2[0] = 1;
|
fsGame.Get<Game::dvar_t*>()->pad2[0] = 1;
|
||||||
|
|
||||||
if (Dvar::Var("cl_modVidRestart").Get<bool>())
|
if (Dvar::Var("cl_modVidRestart").Get<bool>())
|
||||||
{
|
{
|
||||||
Game::Cmd_ExecuteSingleCommand(0, 0, "vid_restart");
|
Game::Cmd_ExecuteSingleCommand(0, 0, "vid_restart");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game::Cmd_ExecuteSingleCommand(0, 0, "closemenu mods_menu");
|
Game::Cmd_ExecuteSingleCommand(0, 0, "closemenu mods_menu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModList::ModList()
|
ModList::ModList()
|
||||||
{
|
{
|
||||||
ModList::CurrentMod = 0;
|
ModList::CurrentMod = 0;
|
||||||
Dvar::Register("cl_modVidRestart", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Perform a vid_restart when loading a mod.");
|
Dvar::Register("cl_modVidRestart", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Perform a vid_restart when loading a mod.");
|
||||||
|
|
||||||
UIScript::Add("LoadMods", ModList::UIScript_LoadMods);
|
UIScript::Add("LoadMods", ModList::UIScript_LoadMods);
|
||||||
UIScript::Add("RunMod", ModList::UIScript_RunMod);
|
UIScript::Add("RunMod", ModList::UIScript_RunMod);
|
||||||
UIScript::Add("ClearMods", ModList::UIScript_ClearMods);
|
UIScript::Add("ClearMods", ModList::UIScript_ClearMods);
|
||||||
|
|
||||||
UIFeeder::Add(9.0f, ModList::GetItemCount, ModList::GetItemText, ModList::Select);
|
UIFeeder::Add(9.0f, ModList::GetItemCount, ModList::GetItemText, ModList::Select);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModList::~ModList()
|
ModList::~ModList()
|
||||||
{
|
{
|
||||||
ModList::Mods.clear();
|
ModList::Mods.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,45 +1,45 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::map<std::string, const char*> MusicalTalent::SoundAliasList;
|
std::map<std::string, const char*> MusicalTalent::SoundAliasList;
|
||||||
|
|
||||||
void MusicalTalent::Replace(std::string sound, const char* file)
|
void MusicalTalent::Replace(std::string sound, const char* file)
|
||||||
{
|
{
|
||||||
MusicalTalent::SoundAliasList[Utils::StrToLower(sound)] = file;
|
MusicalTalent::SoundAliasList[Utils::String::StrToLower(sound)] = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename)
|
Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename)
|
||||||
{
|
{
|
||||||
Game::XAssetHeader header = { 0 };
|
Game::XAssetHeader header = { 0 };
|
||||||
|
|
||||||
if (MusicalTalent::SoundAliasList.find(Utils::StrToLower(filename)) != MusicalTalent::SoundAliasList.end())
|
if (MusicalTalent::SoundAliasList.find(Utils::String::StrToLower(filename)) != MusicalTalent::SoundAliasList.end())
|
||||||
{
|
{
|
||||||
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).aliasList;
|
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).aliasList;
|
||||||
|
|
||||||
if (aliases)
|
if (aliases)
|
||||||
{
|
{
|
||||||
if (aliases->aliases->stream->type == 2)
|
if (aliases->aliases->stream->type == 2)
|
||||||
{
|
{
|
||||||
aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::StrToLower(filename)];
|
aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::String::StrToLower(filename)];
|
||||||
}
|
}
|
||||||
|
|
||||||
header.aliasList = aliases;
|
header.aliasList = aliases;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicalTalent::MusicalTalent()
|
MusicalTalent::MusicalTalent()
|
||||||
{
|
{
|
||||||
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases);
|
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases);
|
||||||
|
|
||||||
MusicalTalent::Replace("music_mainmenu_mp", "hz_t_menumusic.mp3");
|
MusicalTalent::Replace("music_mainmenu_mp", "hz_t_menumusic.mp3");
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicalTalent::~MusicalTalent()
|
MusicalTalent::~MusicalTalent()
|
||||||
{
|
{
|
||||||
MusicalTalent::SoundAliasList.clear();
|
MusicalTalent::SoundAliasList.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,342 +1,342 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::string Network::SelectedPacket;
|
std::string Network::SelectedPacket;
|
||||||
wink::signal<wink::slot<Network::CallbackRaw>> Network::StartupSignal;
|
wink::signal<wink::slot<Network::CallbackRaw>> Network::StartupSignal;
|
||||||
std::map<std::string, wink::slot<Network::Callback>> Network::PacketHandlers;
|
std::map<std::string, wink::slot<Network::Callback>> Network::PacketHandlers;
|
||||||
|
|
||||||
Network::Address::Address(std::string addrString)
|
Network::Address::Address(std::string addrString)
|
||||||
{
|
{
|
||||||
Game::NET_StringToAdr(addrString.data(), &this->address);
|
Game::NET_StringToAdr(addrString.data(), &this->address);
|
||||||
}
|
}
|
||||||
Network::Address::Address(sockaddr* addr)
|
Network::Address::Address(sockaddr* addr)
|
||||||
{
|
{
|
||||||
Game::SockadrToNetadr(addr, &this->address);
|
Game::SockadrToNetadr(addr, &this->address);
|
||||||
}
|
}
|
||||||
bool Network::Address::operator==(const Network::Address &obj)
|
bool Network::Address::operator==(const Network::Address &obj)
|
||||||
{
|
{
|
||||||
return Game::NET_CompareAdr(this->address, obj.address);
|
return Game::NET_CompareAdr(this->address, obj.address);
|
||||||
}
|
}
|
||||||
void Network::Address::SetPort(unsigned short port)
|
void Network::Address::SetPort(unsigned short port)
|
||||||
{
|
{
|
||||||
this->address.port = htons(port);
|
this->address.port = htons(port);
|
||||||
}
|
}
|
||||||
unsigned short Network::Address::GetPort()
|
unsigned short Network::Address::GetPort()
|
||||||
{
|
{
|
||||||
return ntohs(this->address.port);
|
return ntohs(this->address.port);
|
||||||
}
|
}
|
||||||
void Network::Address::SetIP(DWORD ip)
|
void Network::Address::SetIP(DWORD ip)
|
||||||
{
|
{
|
||||||
this->address.ip.full = ip;
|
this->address.ip.full = ip;
|
||||||
}
|
}
|
||||||
void Network::Address::SetIP(Game::netIP_t ip)
|
void Network::Address::SetIP(Game::netIP_t ip)
|
||||||
{
|
{
|
||||||
this->address.ip = ip;
|
this->address.ip = ip;
|
||||||
}
|
}
|
||||||
Game::netIP_t Network::Address::GetIP()
|
Game::netIP_t Network::Address::GetIP()
|
||||||
{
|
{
|
||||||
return this->address.ip;
|
return this->address.ip;
|
||||||
}
|
}
|
||||||
void Network::Address::SetType(Game::netadrtype_t type)
|
void Network::Address::SetType(Game::netadrtype_t type)
|
||||||
{
|
{
|
||||||
this->address.type = type;
|
this->address.type = type;
|
||||||
}
|
}
|
||||||
Game::netadrtype_t Network::Address::GetType()
|
Game::netadrtype_t Network::Address::GetType()
|
||||||
{
|
{
|
||||||
return this->address.type;
|
return this->address.type;
|
||||||
}
|
}
|
||||||
sockaddr Network::Address::GetSockAddr()
|
sockaddr Network::Address::GetSockAddr()
|
||||||
{
|
{
|
||||||
sockaddr addr;
|
sockaddr addr;
|
||||||
this->ToSockAddr(&addr);
|
this->ToSockAddr(&addr);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
void Network::Address::ToSockAddr(sockaddr* addr)
|
void Network::Address::ToSockAddr(sockaddr* addr)
|
||||||
{
|
{
|
||||||
if (addr)
|
if (addr)
|
||||||
{
|
{
|
||||||
Game::NetadrToSockadr(&this->address, addr);
|
Game::NetadrToSockadr(&this->address, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Network::Address::ToSockAddr(sockaddr_in* addr)
|
void Network::Address::ToSockAddr(sockaddr_in* addr)
|
||||||
{
|
{
|
||||||
this->ToSockAddr(reinterpret_cast<sockaddr*>(addr));
|
this->ToSockAddr(reinterpret_cast<sockaddr*>(addr));
|
||||||
}
|
}
|
||||||
Game::netadr_t* Network::Address::Get()
|
Game::netadr_t* Network::Address::Get()
|
||||||
{
|
{
|
||||||
return &this->address;
|
return &this->address;
|
||||||
}
|
}
|
||||||
const char* Network::Address::GetCString()
|
const char* Network::Address::GetCString()
|
||||||
{
|
{
|
||||||
return Game::NET_AdrToString(this->address);
|
return Game::NET_AdrToString(this->address);
|
||||||
}
|
}
|
||||||
std::string Network::Address::GetString()
|
std::string Network::Address::GetString()
|
||||||
{
|
{
|
||||||
return this->GetCString();
|
return this->GetCString();
|
||||||
}
|
}
|
||||||
bool Network::Address::IsLocal()
|
bool Network::Address::IsLocal()
|
||||||
{
|
{
|
||||||
// According to: https://en.wikipedia.org/wiki/Private_network
|
// According to: https://en.wikipedia.org/wiki/Private_network
|
||||||
|
|
||||||
// 10.X.X.X
|
// 10.X.X.X
|
||||||
if (this->GetIP().bytes[0] == 10) return true;
|
if (this->GetIP().bytes[0] == 10) return true;
|
||||||
|
|
||||||
// 192.168.X.X
|
// 192.168.X.X
|
||||||
if (this->GetIP().bytes[0] == 192 && this->GetIP().bytes[1] == 168) return true;
|
if (this->GetIP().bytes[0] == 192 && this->GetIP().bytes[1] == 168) return true;
|
||||||
|
|
||||||
// 172.16.X.X - 172.31.X.X
|
// 172.16.X.X - 172.31.X.X
|
||||||
if (this->GetIP().bytes[0] == 172 && (this->GetIP().bytes[1] >= 16) && (this->GetIP().bytes[1] < 32)) return true;
|
if (this->GetIP().bytes[0] == 172 && (this->GetIP().bytes[1] >= 16) && (this->GetIP().bytes[1] < 32)) return true;
|
||||||
|
|
||||||
// TODO: Maybe check for matching localIPs and subnet mask
|
// TODO: Maybe check for matching localIPs and subnet mask
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool Network::Address::IsSelf()
|
bool Network::Address::IsSelf()
|
||||||
{
|
{
|
||||||
if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback
|
if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback
|
||||||
if (this->GetPort() != (Dvar::Var("net_port").Get<int>() & 0xFFFF)) return false; // Port not equal
|
if (this->GetPort() != (Dvar::Var("net_port").Get<int>() & 0xFFFF)) return false; // Port not equal
|
||||||
|
|
||||||
for (int i = 0; i < *Game::numIP; ++i)
|
for (int i = 0; i < *Game::numIP; ++i)
|
||||||
{
|
{
|
||||||
if (this->GetIP().full == Game::localIP[i].full)
|
if (this->GetIP().full == Game::localIP[i].full)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool Network::Address::IsValid()
|
bool Network::Address::IsValid()
|
||||||
{
|
{
|
||||||
return (this->GetType() != Game::netadrtype_t::NA_BAD);
|
return (this->GetType() != Game::netadrtype_t::NA_BAD);
|
||||||
}
|
}
|
||||||
void Network::Address::Serialize(Proto::Network::Address* protoAddress)
|
void Network::Address::Serialize(Proto::Network::Address* protoAddress)
|
||||||
{
|
{
|
||||||
protoAddress->set_ip(this->GetIP().full);
|
protoAddress->set_ip(this->GetIP().full);
|
||||||
protoAddress->set_port(this->GetPort() & 0xFFFF);
|
protoAddress->set_port(this->GetPort() & 0xFFFF);
|
||||||
}
|
}
|
||||||
void Network::Address::Deserialize(const Proto::Network::Address& protoAddress)
|
void Network::Address::Deserialize(const Proto::Network::Address& protoAddress)
|
||||||
{
|
{
|
||||||
this->SetIP(protoAddress.ip());
|
this->SetIP(protoAddress.ip());
|
||||||
this->SetPort(static_cast<uint16_t>(protoAddress.port()));
|
this->SetPort(static_cast<uint16_t>(protoAddress.port()));
|
||||||
this->SetType(Game::netadrtype_t::NA_IP);
|
this->SetType(Game::netadrtype_t::NA_IP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::Handle(std::string packet, Network::Callback* callback)
|
void Network::Handle(std::string packet, Network::Callback* callback)
|
||||||
{
|
{
|
||||||
Network::PacketHandlers[Utils::StrToLower(packet)] = callback;
|
Network::PacketHandlers[Utils::String::StrToLower(packet)] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::OnStart(Network::CallbackRaw* callback)
|
void Network::OnStart(Network::CallbackRaw* callback)
|
||||||
{
|
{
|
||||||
Network::StartupSignal.connect(callback);
|
Network::StartupSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::Send(Game::netsrc_t type, Network::Address target, std::string data)
|
void Network::Send(Game::netsrc_t type, Network::Address target, std::string data)
|
||||||
{
|
{
|
||||||
// NET_OutOfBandPrint only supports non-binary data!
|
// NET_OutOfBandPrint only supports non-binary data!
|
||||||
//Game::NET_OutOfBandPrint(type, *target.Get(), data.data());
|
//Game::NET_OutOfBandPrint(type, *target.Get(), data.data());
|
||||||
|
|
||||||
std::string rawData;
|
std::string rawData;
|
||||||
rawData.append("\xFF\xFF\xFF\xFF", 4);
|
rawData.append("\xFF\xFF\xFF\xFF", 4);
|
||||||
rawData.append(data);
|
rawData.append(data);
|
||||||
//rawData.append("\0", 1);
|
//rawData.append("\0", 1);
|
||||||
|
|
||||||
Network::SendRaw(type, target, rawData);
|
Network::SendRaw(type, target, rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::Send(Network::Address target, std::string data)
|
void Network::Send(Network::Address target, std::string data)
|
||||||
{
|
{
|
||||||
Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
|
Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::SendRaw(Game::netsrc_t type, Network::Address target, std::string data)
|
void Network::SendRaw(Game::netsrc_t type, Network::Address target, std::string data)
|
||||||
{
|
{
|
||||||
// NET_OutOfBandData doesn't seem to work properly
|
// NET_OutOfBandData doesn't seem to work properly
|
||||||
//Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size());
|
//Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size());
|
||||||
Game::Sys_SendPacket(type, data.size(), data.data(), *target.Get());
|
Game::Sys_SendPacket(type, data.size(), data.data(), *target.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::SendRaw(Network::Address target, std::string data)
|
void Network::SendRaw(Network::Address target, std::string data)
|
||||||
{
|
{
|
||||||
Network::SendRaw(Game::netsrc_t::NS_CLIENT, target, data);
|
Network::SendRaw(Game::netsrc_t::NS_CLIENT, target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::SendCommand(Game::netsrc_t type, Network::Address target, std::string command, std::string data)
|
void Network::SendCommand(Game::netsrc_t type, Network::Address target, std::string command, std::string data)
|
||||||
{
|
{
|
||||||
// Use space as separator (possible separators are '\n', ' ').
|
// Use space as separator (possible separators are '\n', ' ').
|
||||||
// Though, our handler only needs exactly 1 char as separator and doesn't which char it is
|
// Though, our handler only needs exactly 1 char as separator and doesn't which char it is
|
||||||
std::string packet;
|
std::string packet;
|
||||||
packet.append(command);
|
packet.append(command);
|
||||||
packet.append(" ", 1);
|
packet.append(" ", 1);
|
||||||
packet.append(data);
|
packet.append(data);
|
||||||
|
|
||||||
Network::Send(type, target, packet);
|
Network::Send(type, target, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::SendCommand(Network::Address target, std::string command, std::string data)
|
void Network::SendCommand(Network::Address target, std::string command, std::string data)
|
||||||
{
|
{
|
||||||
Network::SendCommand(Game::netsrc_t::NS_CLIENT, target, command, data);
|
Network::SendCommand(Game::netsrc_t::NS_CLIENT, target, command, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::Broadcast(unsigned short port, std::string data)
|
void Network::Broadcast(unsigned short port, std::string data)
|
||||||
{
|
{
|
||||||
Address target;
|
Address target;
|
||||||
|
|
||||||
target.SetPort(port);
|
target.SetPort(port);
|
||||||
target.SetIP(INADDR_BROADCAST);
|
target.SetIP(INADDR_BROADCAST);
|
||||||
target.SetType(Game::netadrtype_t::NA_BROADCAST);
|
target.SetType(Game::netadrtype_t::NA_BROADCAST);
|
||||||
|
|
||||||
Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
|
Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::BroadcastRange(unsigned int min, unsigned int max, std::string data)
|
void Network::BroadcastRange(unsigned int min, unsigned int max, std::string data)
|
||||||
{
|
{
|
||||||
for (unsigned int i = min; i < max; ++i)
|
for (unsigned int i = min; i < max; ++i)
|
||||||
{
|
{
|
||||||
Network::Broadcast(static_cast<unsigned short>(i & 0xFFFF), data);
|
Network::Broadcast(static_cast<unsigned short>(i & 0xFFFF), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::BroadcastAll(std::string data)
|
void Network::BroadcastAll(std::string data)
|
||||||
{
|
{
|
||||||
Network::BroadcastRange(100, 65536, data);
|
Network::BroadcastRange(100, 65536, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Network::PacketInterceptionHandler(const char* packet)
|
int Network::PacketInterceptionHandler(const char* packet)
|
||||||
{
|
{
|
||||||
// Packet rate limit.
|
// Packet rate limit.
|
||||||
static uint32_t packets = 0;
|
static uint32_t packets = 0;
|
||||||
static int lastClean = 0;
|
static int lastClean = 0;
|
||||||
|
|
||||||
if ((Game::Sys_Milliseconds() - lastClean) > 1'000)
|
if ((Game::Sys_Milliseconds() - lastClean) > 1'000)
|
||||||
{
|
{
|
||||||
packets = 0;
|
packets = 0;
|
||||||
lastClean = Game::Sys_Milliseconds();
|
lastClean = Game::Sys_Milliseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((++packets) > NETWORK_MAX_PACKETS_PER_SECOND)
|
if ((++packets) > NETWORK_MAX_PACKETS_PER_SECOND)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string packetCommand = packet;
|
std::string packetCommand = packet;
|
||||||
auto pos = packetCommand.find_first_of("\\\n ");
|
auto pos = packetCommand.find_first_of("\\\n ");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
packetCommand = packetCommand.substr(0, pos);
|
packetCommand = packetCommand.substr(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
packetCommand = Utils::StrToLower(packetCommand);
|
packetCommand = Utils::String::StrToLower(packetCommand);
|
||||||
|
|
||||||
// Check if custom handler exists
|
// Check if custom handler exists
|
||||||
for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); ++i)
|
for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); ++i)
|
||||||
{
|
{
|
||||||
if (Utils::StrToLower(i->first) == packetCommand)
|
if (Utils::String::StrToLower(i->first) == packetCommand)
|
||||||
{
|
{
|
||||||
Network::SelectedPacket = i->first;
|
Network::SelectedPacket = i->first;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No interception
|
// No interception
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::DeployPacket(Game::netadr_t* from, Game::msg_t* msg)
|
void Network::DeployPacket(Game::netadr_t* from, Game::msg_t* msg)
|
||||||
{
|
{
|
||||||
if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end())
|
if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end())
|
||||||
{
|
{
|
||||||
std::string data;
|
std::string data;
|
||||||
|
|
||||||
size_t offset = Network::SelectedPacket.size() + 4 + 1;
|
size_t offset = Network::SelectedPacket.size() + 4 + 1;
|
||||||
|
|
||||||
if (static_cast<size_t>(msg->cursize) > offset)
|
if (static_cast<size_t>(msg->cursize) > offset)
|
||||||
{
|
{
|
||||||
data.append(msg->data + offset, msg->cursize - offset);
|
data.append(msg->data + offset, msg->cursize - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove trailing 0x00 byte
|
// Remove trailing 0x00 byte
|
||||||
// Actually, don't remove it, it might be part of the packet. Send correctly formatted packets instead!
|
// Actually, don't remove it, it might be part of the packet. Send correctly formatted packets instead!
|
||||||
//if (data.size() && !data[data.size() - 1]) data.pop_back();
|
//if (data.size() && !data[data.size() - 1]) data.pop_back();
|
||||||
|
|
||||||
Network::PacketHandlers[Network::SelectedPacket](from, data);
|
Network::PacketHandlers[Network::SelectedPacket](from, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Error: Network packet intercepted, but handler is missing!\n");
|
Logger::Print("Error: Network packet intercepted, but handler is missing!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::NetworkStart()
|
void Network::NetworkStart()
|
||||||
{
|
{
|
||||||
Network::StartupSignal();
|
Network::StartupSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Network::NetworkStartStub()
|
void __declspec(naked) Network::NetworkStartStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, 64D900h
|
mov eax, 64D900h
|
||||||
call eax
|
call eax
|
||||||
jmp Network::NetworkStart
|
jmp Network::NetworkStart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Network::DeployPacketStub()
|
void __declspec(naked) Network::DeployPacketStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
lea eax, [esp + 0C54h]
|
lea eax, [esp + 0C54h]
|
||||||
push ebp // Command
|
push ebp // Command
|
||||||
push eax // Address pointer
|
push eax // Address pointer
|
||||||
call Network::DeployPacket
|
call Network::DeployPacket
|
||||||
add esp, 8h
|
add esp, 8h
|
||||||
mov al, 1
|
mov al, 1
|
||||||
pop edi
|
pop edi
|
||||||
pop esi
|
pop esi
|
||||||
pop ebp
|
pop ebp
|
||||||
pop ebx
|
pop ebx
|
||||||
add esp, 0C40h
|
add esp, 0C40h
|
||||||
retn
|
retn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Network()
|
Network::Network()
|
||||||
{
|
{
|
||||||
Assert_Size(Game::netadr_t, 20);
|
Assert_Size(Game::netadr_t, 20);
|
||||||
|
|
||||||
// maximum size in NET_OutOfBandPrint
|
// maximum size in NET_OutOfBandPrint
|
||||||
Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC);
|
Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC);
|
||||||
Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC);
|
Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC);
|
||||||
|
|
||||||
// increase max port binding attempts from 10 to 100
|
// increase max port binding attempts from 10 to 100
|
||||||
Utils::Hook::Set<BYTE>(0x4FD48A, 100);
|
Utils::Hook::Set<BYTE>(0x4FD48A, 100);
|
||||||
|
|
||||||
// Parse port as short in Net_AddrToString
|
// Parse port as short in Net_AddrToString
|
||||||
Utils::Hook::Set<char*>(0x4698E3, "%u.%u.%u.%u:%hu");
|
Utils::Hook::Set<char*>(0x4698E3, "%u.%u.%u.%u:%hu");
|
||||||
|
|
||||||
// Install startup handler
|
// Install startup handler
|
||||||
Utils::Hook(0x4FD4D4, Network::NetworkStartStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x4FD4D4, Network::NetworkStartStub, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// Install interception handler
|
// Install interception handler
|
||||||
Utils::Hook(0x5AA709, Network::PacketInterceptionHandler, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5AA709, Network::PacketInterceptionHandler, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Install packet deploy hook
|
// Install packet deploy hook
|
||||||
Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub);
|
Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub);
|
||||||
|
|
||||||
// For /dev/urandom :P
|
// For /dev/urandom :P
|
||||||
Network::Handle("resolveAddress", [] (Address address, std::string data)
|
Network::Handle("resolveAddress", [] (Address address, std::string data)
|
||||||
{
|
{
|
||||||
Network::SendRaw(address, address.GetString());
|
Network::SendRaw(address, address.GetString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::~Network()
|
Network::~Network()
|
||||||
{
|
{
|
||||||
Network::SelectedPacket.clear();
|
Network::SelectedPacket.clear();
|
||||||
Network::PacketHandlers.clear();
|
Network::PacketHandlers.clear();
|
||||||
Network::StartupSignal.clear();
|
Network::StartupSignal.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,69 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
#define NEWS_MOTD_DEFUALT "Welcome to IW4x Multiplayer!"
|
#define NEWS_MOTD_DEFUALT "Welcome to IW4x Multiplayer!"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::thread News::Thread;
|
std::thread News::Thread;
|
||||||
|
|
||||||
bool News::UnitTest()
|
bool News::UnitTest()
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
if (News::Thread.joinable())
|
if (News::Thread.joinable())
|
||||||
{
|
{
|
||||||
Logger::Print("Awaiting thread termination...\n");
|
Logger::Print("Awaiting thread termination...\n");
|
||||||
News::Thread.join();
|
News::Thread.join();
|
||||||
|
|
||||||
if (!strlen(Localization::Get("MPUI_CHANGELOG_TEXT")) || Localization::Get("MPUI_CHANGELOG_TEXT") == "Loading..."s)
|
if (!strlen(Localization::Get("MPUI_CHANGELOG_TEXT")) || Localization::Get("MPUI_CHANGELOG_TEXT") == "Loading..."s)
|
||||||
{
|
{
|
||||||
Logger::Print("Failed to fetch changelog!\n");
|
Logger::Print("Failed to fetch changelog!\n");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Successfully fetched changelog.\n");
|
Logger::Print("Successfully fetched changelog.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFUALT))
|
if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFUALT))
|
||||||
{
|
{
|
||||||
Logger::Print("Failed to fetch motd!\n");
|
Logger::Print("Failed to fetch motd!\n");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Successfully fetched motd.\n");
|
Logger::Print("Successfully fetched motd.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
News::News()
|
News::News()
|
||||||
{
|
{
|
||||||
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
|
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
|
||||||
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT);
|
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT);
|
||||||
|
|
||||||
News::Thread = std::thread([] ()
|
News::Thread = std::thread([] ()
|
||||||
{
|
{
|
||||||
Localization::Set("MPUI_CHANGELOG_TEXT", Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/changelog.txt").SetTimeout(5000)->Get().data());
|
Localization::Set("MPUI_CHANGELOG_TEXT", Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/changelog.txt").SetTimeout(5000)->Get());
|
||||||
|
|
||||||
std::string data = Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/motd.txt").SetTimeout(5000)->Get();
|
std::string data = Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/motd.txt").SetTimeout(5000)->Get();
|
||||||
|
|
||||||
if (!data.empty())
|
if (!data.empty())
|
||||||
{
|
{
|
||||||
Localization::Set("MPUI_MOTD_TEXT", data.data());
|
Localization::Set("MPUI_MOTD_TEXT", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement update checks here!
|
// TODO: Implement update checks here!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
News::~News()
|
News::~News()
|
||||||
{
|
{
|
||||||
if (News::Thread.joinable())
|
if (News::Thread.joinable())
|
||||||
{
|
{
|
||||||
News::Thread.join();
|
News::Thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,404 +1,404 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Party::JoinContainer Party::Container;
|
Party::JoinContainer Party::Container;
|
||||||
std::map<uint64_t, Network::Address> Party::LobbyMap;
|
std::map<uint64_t, Network::Address> Party::LobbyMap;
|
||||||
|
|
||||||
SteamID Party::GenerateLobbyId()
|
SteamID Party::GenerateLobbyId()
|
||||||
{
|
{
|
||||||
SteamID id;
|
SteamID id;
|
||||||
|
|
||||||
id.AccountID = Game::Sys_Milliseconds();
|
id.AccountID = Game::Sys_Milliseconds();
|
||||||
id.Universe = 1;
|
id.Universe = 1;
|
||||||
id.AccountType = 8;
|
id.AccountType = 8;
|
||||||
id.AccountInstance = 0x40000;
|
id.AccountInstance = 0x40000;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Address Party::Target()
|
Network::Address Party::Target()
|
||||||
{
|
{
|
||||||
return Party::Container.Target;
|
return Party::Container.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Party::Connect(Network::Address target)
|
void Party::Connect(Network::Address target)
|
||||||
{
|
{
|
||||||
Party::Container.Valid = true;
|
Party::Container.Valid = true;
|
||||||
Party::Container.AwaitingPlaylist = false;
|
Party::Container.AwaitingPlaylist = false;
|
||||||
Party::Container.JoinTime = Game::Sys_Milliseconds();
|
Party::Container.JoinTime = Game::Sys_Milliseconds();
|
||||||
Party::Container.Target = target;
|
Party::Container.Target = target;
|
||||||
Party::Container.Challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
|
Party::Container.Challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
|
||||||
|
|
||||||
Network::SendCommand(Party::Container.Target, "getinfo", Party::Container.Challenge);
|
Network::SendCommand(Party::Container.Target, "getinfo", Party::Container.Challenge);
|
||||||
|
|
||||||
Command::Execute("openmenu popup_reconnectingtoparty");
|
Command::Execute("openmenu popup_reconnectingtoparty");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Party::GetLobbyInfo(SteamID lobby, std::string key)
|
const char* Party::GetLobbyInfo(SteamID lobby, std::string key)
|
||||||
{
|
{
|
||||||
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
|
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
|
||||||
{
|
{
|
||||||
Network::Address address = Party::LobbyMap[lobby.Bits];
|
Network::Address address = Party::LobbyMap[lobby.Bits];
|
||||||
|
|
||||||
if (key == "addr")
|
if (key == "addr")
|
||||||
{
|
{
|
||||||
return Utils::VA("%d", address.GetIP().full);
|
return Utils::String::VA("%d", address.GetIP().full);
|
||||||
}
|
}
|
||||||
else if (key =="port")
|
else if (key =="port")
|
||||||
{
|
{
|
||||||
return Utils::VA("%d", address.GetPort());
|
return Utils::String::VA("%d", address.GetPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "212";
|
return "212";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Party::RemoveLobby(SteamID lobby)
|
void Party::RemoveLobby(SteamID lobby)
|
||||||
{
|
{
|
||||||
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
|
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
|
||||||
{
|
{
|
||||||
Party::LobbyMap.erase(Party::LobbyMap.find(lobby.Bits));
|
Party::LobbyMap.erase(Party::LobbyMap.find(lobby.Bits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Party::ConnectError(std::string message)
|
void Party::ConnectError(std::string message)
|
||||||
{
|
{
|
||||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||||
Dvar::Var("partyend_reason").Set(message);
|
Dvar::Var("partyend_reason").Set(message);
|
||||||
Command::Execute("openmenu menu_xboxlive_partyended");
|
Command::Execute("openmenu menu_xboxlive_partyended");
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description)
|
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description)
|
||||||
{
|
{
|
||||||
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).Get<Game::dvar_t*>();
|
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).Get<Game::dvar_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Party::PlaylistAwaiting()
|
bool Party::PlaylistAwaiting()
|
||||||
{
|
{
|
||||||
return Party::Container.AwaitingPlaylist;
|
return Party::Container.AwaitingPlaylist;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Party::PlaylistContinue()
|
void Party::PlaylistContinue()
|
||||||
{
|
{
|
||||||
Dvar::Var("xblive_privateserver").Set(false);
|
Dvar::Var("xblive_privateserver").Set(false);
|
||||||
|
|
||||||
// Ensure we can join
|
// Ensure we can join
|
||||||
*Game::g_lobbyCreateInProgress = false;
|
*Game::g_lobbyCreateInProgress = false;
|
||||||
|
|
||||||
Party::Container.AwaitingPlaylist = false;
|
Party::Container.AwaitingPlaylist = false;
|
||||||
|
|
||||||
SteamID id = Party::GenerateLobbyId();
|
SteamID id = Party::GenerateLobbyId();
|
||||||
|
|
||||||
Party::LobbyMap[id.Bits] = Party::Container.Target;
|
Party::LobbyMap[id.Bits] = Party::Container.Target;
|
||||||
|
|
||||||
Game::Steam_JoinLobby(id, 0);
|
Game::Steam_JoinLobby(id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Party::PlaylistError(std::string error)
|
void Party::PlaylistError(std::string error)
|
||||||
{
|
{
|
||||||
Party::Container.Valid = false;
|
Party::Container.Valid = false;
|
||||||
Party::Container.AwaitingPlaylist = false;
|
Party::Container.AwaitingPlaylist = false;
|
||||||
|
|
||||||
Party::ConnectError(error);
|
Party::ConnectError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Party::UIDvarIntStub(char* dvar)
|
DWORD Party::UIDvarIntStub(char* dvar)
|
||||||
{
|
{
|
||||||
if (!_stricmp(dvar, "onlinegame"))
|
if (!_stricmp(dvar, "onlinegame"))
|
||||||
{
|
{
|
||||||
return 0x649E660;
|
return 0x649E660;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::Hook::Call<DWORD(char*)>(0x4D5390)(dvar);
|
return Utils::Hook::Call<DWORD(char*)>(0x4D5390)(dvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Party::Party()
|
Party::Party()
|
||||||
{
|
{
|
||||||
static Game::dvar_t* partyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsDedicated(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").Get<Game::dvar_t*>();
|
static Game::dvar_t* partyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsDedicated(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").Get<Game::dvar_t*>();
|
||||||
Dvar::Register<bool>("xblive_privatematch", true, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "").Get<Game::dvar_t*>();
|
Dvar::Register<bool>("xblive_privatematch", true, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "").Get<Game::dvar_t*>();
|
||||||
|
|
||||||
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
||||||
Utils::Hook::Set<WORD>(0x460D96, 0x90E9);
|
Utils::Hook::Set<WORD>(0x460D96, 0x90E9);
|
||||||
Utils::Hook::Set<BYTE>(0x460F0A, 0xEB);
|
Utils::Hook::Set<BYTE>(0x460F0A, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x401CA4, 0xEB);
|
Utils::Hook::Set<BYTE>(0x401CA4, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x401C15, 0xEB);
|
Utils::Hook::Set<BYTE>(0x401C15, 0xEB);
|
||||||
|
|
||||||
// disable configstring checksum matching (it's unreliable at most)
|
// disable configstring checksum matching (it's unreliable at most)
|
||||||
Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer
|
Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer
|
||||||
Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate
|
Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate
|
||||||
Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate
|
Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate
|
||||||
|
|
||||||
// AnonymousAddRequest
|
// AnonymousAddRequest
|
||||||
Utils::Hook::Set<BYTE>(0x5B5E18, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5B5E18, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x5B5E64, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5B5E64, 0xEB);
|
||||||
Utils::Hook::Nop(0x5B5E5C, 2);
|
Utils::Hook::Nop(0x5B5E5C, 2);
|
||||||
|
|
||||||
// HandleClientHandshake
|
// HandleClientHandshake
|
||||||
Utils::Hook::Set<BYTE>(0x5B6EA5, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5B6EA5, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x5B6EF3, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5B6EF3, 0xEB);
|
||||||
Utils::Hook::Nop(0x5B6EEB, 2);
|
Utils::Hook::Nop(0x5B6EEB, 2);
|
||||||
|
|
||||||
// Allow local connections
|
// Allow local connections
|
||||||
Utils::Hook::Set<BYTE>(0x4D43DA, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4D43DA, 0xEB);
|
||||||
|
|
||||||
// LobbyID mismatch
|
// LobbyID mismatch
|
||||||
Utils::Hook::Nop(0x4E50D6, 2);
|
Utils::Hook::Nop(0x4E50D6, 2);
|
||||||
Utils::Hook::Set<BYTE>(0x4E50DA, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4E50DA, 0xEB);
|
||||||
|
|
||||||
// causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored
|
// causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored
|
||||||
Utils::Hook::Set<BYTE>(0x49D007, 0xEB);
|
Utils::Hook::Set<BYTE>(0x49D007, 0xEB);
|
||||||
|
|
||||||
// functions checking party heartbeat timeouts, cause random issues
|
// functions checking party heartbeat timeouts, cause random issues
|
||||||
Utils::Hook::Nop(0x4E532D, 5);
|
Utils::Hook::Nop(0x4E532D, 5);
|
||||||
|
|
||||||
// Steam_JoinLobby call causes migration
|
// Steam_JoinLobby call causes migration
|
||||||
Utils::Hook::Nop(0x5AF851, 5);
|
Utils::Hook::Nop(0x5AF851, 5);
|
||||||
Utils::Hook::Set<BYTE>(0x5AF85B, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5AF85B, 0xEB);
|
||||||
|
|
||||||
// Allow xpartygo in public lobbies
|
// Allow xpartygo in public lobbies
|
||||||
Utils::Hook::Set<BYTE>(0x5A969E, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5A969E, 0xEB);
|
||||||
Utils::Hook::Nop(0x5A96BE, 2);
|
Utils::Hook::Nop(0x5A96BE, 2);
|
||||||
|
|
||||||
// Always open lobby menu when connecting
|
// Always open lobby menu when connecting
|
||||||
// It's not possible to entirely patch it via code
|
// It's not possible to entirely patch it via code
|
||||||
//Utils::Hook::Set<BYTE>(0x5B1698, 0xEB);
|
//Utils::Hook::Set<BYTE>(0x5B1698, 0xEB);
|
||||||
//Utils::Hook::Nop(0x5029F2, 6);
|
//Utils::Hook::Nop(0x5029F2, 6);
|
||||||
//Utils::Hook::SetString(0x70573C, "menu_xboxlive_lobby");
|
//Utils::Hook::SetString(0x70573C, "menu_xboxlive_lobby");
|
||||||
|
|
||||||
// Disallow selecting team in private match
|
// Disallow selecting team in private match
|
||||||
//Utils::Hook::Nop(0x5B2BD8, 6);
|
//Utils::Hook::Nop(0x5B2BD8, 6);
|
||||||
|
|
||||||
// Force teams, even if not private match
|
// Force teams, even if not private match
|
||||||
Utils::Hook::Set<BYTE>(0x487BB2, 0xEB);
|
Utils::Hook::Set<BYTE>(0x487BB2, 0xEB);
|
||||||
|
|
||||||
// Force xblive_privatematch 0 and rename it
|
// Force xblive_privatematch 0 and rename it
|
||||||
//Utils::Hook::Set<BYTE>(0x420A6A, 4);
|
//Utils::Hook::Set<BYTE>(0x420A6A, 4);
|
||||||
Utils::Hook::Set<BYTE>(0x420A6C, 0);
|
Utils::Hook::Set<BYTE>(0x420A6C, 0);
|
||||||
Utils::Hook::Set<char*>(0x420A6E, "xblive_privateserver");
|
Utils::Hook::Set<char*>(0x420A6E, "xblive_privateserver");
|
||||||
|
|
||||||
// Remove migration shutdown, it causes crashes and will be destroyed when erroring anyways
|
// Remove migration shutdown, it causes crashes and will be destroyed when erroring anyways
|
||||||
Utils::Hook::Nop(0x5A8E1C, 12);
|
Utils::Hook::Nop(0x5A8E1C, 12);
|
||||||
Utils::Hook::Nop(0x5A8E33, 11);
|
Utils::Hook::Nop(0x5A8E33, 11);
|
||||||
|
|
||||||
// Enable XP Bar
|
// Enable XP Bar
|
||||||
Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Set NAT to open
|
// Set NAT to open
|
||||||
Utils::Hook::Set<int>(0x79D898, 1);
|
Utils::Hook::Set<int>(0x79D898, 1);
|
||||||
|
|
||||||
// Disable host migration
|
// Disable host migration
|
||||||
Utils::Hook::Set<BYTE>(0x5B58B2, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5B58B2, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x4D6171, 0);
|
Utils::Hook::Set<BYTE>(0x4D6171, 0);
|
||||||
|
|
||||||
// Patch playlist stuff for non-party behavior
|
// Patch playlist stuff for non-party behavior
|
||||||
Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable);
|
Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable);
|
||||||
Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable);
|
Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable);
|
||||||
Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable);
|
Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable);
|
||||||
|
|
||||||
// Invert corresponding jumps
|
// Invert corresponding jumps
|
||||||
Utils::Hook::Xor<BYTE>(0x4A409B, 1);
|
Utils::Hook::Xor<BYTE>(0x4A409B, 1);
|
||||||
Utils::Hook::Xor<BYTE>(0x4573FA, 1);
|
Utils::Hook::Xor<BYTE>(0x4573FA, 1);
|
||||||
Utils::Hook::Xor<BYTE>(0x5B1A17, 1);
|
Utils::Hook::Xor<BYTE>(0x5B1A17, 1);
|
||||||
|
|
||||||
// Fix xstartlobby
|
// Fix xstartlobby
|
||||||
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
|
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
|
||||||
|
|
||||||
// Patch party_minplayers to 1 and protect it
|
// Patch party_minplayers to 1 and protect it
|
||||||
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).Install()->Quick();
|
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Set ui_maxclients to sv_maxclients
|
// Set ui_maxclients to sv_maxclients
|
||||||
Utils::Hook::Set<char*>(0x42618F, "sv_maxclients");
|
Utils::Hook::Set<char*>(0x42618F, "sv_maxclients");
|
||||||
Utils::Hook::Set<char*>(0x4D3756, "sv_maxclients");
|
Utils::Hook::Set<char*>(0x4D3756, "sv_maxclients");
|
||||||
Utils::Hook::Set<char*>(0x5E3772, "sv_maxclients");
|
Utils::Hook::Set<char*>(0x5E3772, "sv_maxclients");
|
||||||
|
|
||||||
// Unlatch maxclient dvars
|
// Unlatch maxclient dvars
|
||||||
Utils::Hook::Xor<BYTE>(0x426187, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<BYTE>(0x426187, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
Utils::Hook::Xor<BYTE>(0x4D374E, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<BYTE>(0x4D374E, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
Utils::Hook::Xor<BYTE>(0x5E376A, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<BYTE>(0x5E376A, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
Utils::Hook::Xor<DWORD>(0x4261A1, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<DWORD>(0x4261A1, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
Utils::Hook::Xor<DWORD>(0x4D376D, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<DWORD>(0x4D376D, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
Utils::Hook::Xor<DWORD>(0x5E3789, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
Utils::Hook::Xor<DWORD>(0x5E3789, Game::dvar_flag::DVAR_FLAG_LATCHED);
|
||||||
|
|
||||||
Command::Add("connect", [] (Command::Params params)
|
Command::Add("connect", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2)
|
if (params.Length() < 2)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Party::Connect(Network::Address(params[1]));
|
Party::Connect(Network::Address(params[1]));
|
||||||
});
|
});
|
||||||
Command::Add("reconnect", [] (Command::Params params)
|
Command::Add("reconnect", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
Party::Connect(Party::Container.Target);
|
Party::Connect(Party::Container.Target);
|
||||||
});
|
});
|
||||||
|
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
if (Party::Container.Valid)
|
if (Party::Container.Valid)
|
||||||
{
|
{
|
||||||
if ((Game::Sys_Milliseconds() - Party::Container.JoinTime) > 5000)
|
if ((Game::Sys_Milliseconds() - Party::Container.JoinTime) > 5000)
|
||||||
{
|
{
|
||||||
Party::Container.Valid = false;
|
Party::Container.Valid = false;
|
||||||
Party::ConnectError("Server connection timed out.");
|
Party::ConnectError("Server connection timed out.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Party::Container.AwaitingPlaylist)
|
if (Party::Container.AwaitingPlaylist)
|
||||||
{
|
{
|
||||||
if ((Game::Sys_Milliseconds() - Party::Container.RequestTime) > 5000)
|
if ((Game::Sys_Milliseconds() - Party::Container.RequestTime) > 5000)
|
||||||
{
|
{
|
||||||
Party::Container.AwaitingPlaylist = false;
|
Party::Container.AwaitingPlaylist = false;
|
||||||
Party::ConnectError("Playlist request timed out.");
|
Party::ConnectError("Playlist request timed out.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Basic info handler
|
// Basic info handler
|
||||||
Network::Handle("getInfo", [] (Network::Address address, std::string data)
|
Network::Handle("getInfo", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
int clientCount = 0;
|
int clientCount = 0;
|
||||||
int maxclientCount = *Game::svs_numclients;
|
int maxclientCount = *Game::svs_numclients;
|
||||||
|
|
||||||
if (maxclientCount)
|
if (maxclientCount)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < maxclientCount; ++i)
|
for (int i = 0; i < maxclientCount; ++i)
|
||||||
{
|
{
|
||||||
if (Game::svs_clients[i].state >= 3)
|
if (Game::svs_clients[i].state >= 3)
|
||||||
{
|
{
|
||||||
++clientCount;
|
++clientCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
||||||
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
||||||
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00));
|
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00));
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::InfoString info;
|
Utils::InfoString info;
|
||||||
info.Set("challenge", Utils::ParseChallenge(data));
|
info.Set("challenge", Utils::ParseChallenge(data));
|
||||||
info.Set("gamename", "IW4");
|
info.Set("gamename", "IW4");
|
||||||
info.Set("hostname", Dvar::Var("sv_hostname").Get<const char*>());
|
info.Set("hostname", Dvar::Var("sv_hostname").Get<const char*>());
|
||||||
info.Set("gametype", Dvar::Var("g_gametype").Get<const char*>());
|
info.Set("gametype", Dvar::Var("g_gametype").Get<const char*>());
|
||||||
info.Set("fs_game", Dvar::Var("fs_game").Get<const char*>());
|
info.Set("fs_game", Dvar::Var("fs_game").Get<const char*>());
|
||||||
info.Set("xuid", Utils::VA("%llX", Steam::SteamUser()->GetSteamID().Bits));
|
info.Set("xuid", fmt::sprintf("%llX", Steam::SteamUser()->GetSteamID().Bits));
|
||||||
info.Set("clients", Utils::VA("%i", clientCount));
|
info.Set("clients", fmt::sprintf("%i", clientCount));
|
||||||
info.Set("sv_maxclients", Utils::VA("%i", maxclientCount));
|
info.Set("sv_maxclients", fmt::sprintf("%i", maxclientCount));
|
||||||
info.Set("protocol", Utils::VA("%i", PROTOCOL));
|
info.Set("protocol", fmt::sprintf("%i", PROTOCOL));
|
||||||
info.Set("shortversion", VERSION_STR);
|
info.Set("shortversion", VERSION_STR);
|
||||||
info.Set("checksum", Utils::VA("%d", Game::Sys_Milliseconds()));
|
info.Set("checksum", fmt::sprintf("%d", Game::Sys_Milliseconds()));
|
||||||
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
||||||
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().size() ? "1" : "0"));
|
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().size() ? "1" : "0"));
|
||||||
info.Set("hc", (Dvar::Var("g_hardcore").Get<bool>() ? "1" : "0"));
|
info.Set("hc", (Dvar::Var("g_hardcore").Get<bool>() ? "1" : "0"));
|
||||||
info.Set("securityLevel", Utils::VA("%i", Dvar::Var("sv_securityLevel").Get<int>()));
|
info.Set("securityLevel", fmt::sprintf("%i", Dvar::Var("sv_securityLevel").Get<int>()));
|
||||||
|
|
||||||
// Ensure mapname is set
|
// Ensure mapname is set
|
||||||
if (info.Get("mapname").empty())
|
if (info.Get("mapname").empty())
|
||||||
{
|
{
|
||||||
info.Set("mapname", Dvar::Var("ui_mapname").Get<const char*>());
|
info.Set("mapname", Dvar::Var("ui_mapname").Get<const char*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set matchtype
|
// Set matchtype
|
||||||
// 0 - No match, connecting not possible
|
// 0 - No match, connecting not possible
|
||||||
// 1 - Party, use Steam_JoinLobby to connect
|
// 1 - Party, use Steam_JoinLobby to connect
|
||||||
// 2 - Match, use CL_ConnectFromParty to connect
|
// 2 - Match, use CL_ConnectFromParty to connect
|
||||||
|
|
||||||
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>()) // Party hosting
|
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>()) // Party hosting
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "1");
|
info.Set("matchtype", "1");
|
||||||
}
|
}
|
||||||
else if (Dvar::Var("sv_running").Get<bool>()) // Match hosting
|
else if (Dvar::Var("sv_running").Get<bool>()) // Match hosting
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "2");
|
info.Set("matchtype", "2");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "0");
|
info.Set("matchtype", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::SendCommand(address, "infoResponse", "\\" + info.Build());
|
Network::SendCommand(address, "infoResponse", "\\" + info.Build());
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("infoResponse", [] (Network::Address address, std::string data)
|
Network::Handle("infoResponse", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
Utils::InfoString info(data);
|
Utils::InfoString info(data);
|
||||||
|
|
||||||
// Handle connection
|
// Handle connection
|
||||||
if (Party::Container.Valid)
|
if (Party::Container.Valid)
|
||||||
{
|
{
|
||||||
if (Party::Container.Target == address)
|
if (Party::Container.Target == address)
|
||||||
{
|
{
|
||||||
// Invalidate handler for future packets
|
// Invalidate handler for future packets
|
||||||
Party::Container.Valid = false;
|
Party::Container.Valid = false;
|
||||||
|
|
||||||
int matchType = atoi(info.Get("matchtype").data());
|
int matchType = atoi(info.Get("matchtype").data());
|
||||||
uint32_t securityLevel = static_cast<uint32_t>(atoi(info.Get("securityLevel").data()));
|
uint32_t securityLevel = static_cast<uint32_t>(atoi(info.Get("securityLevel").data()));
|
||||||
|
|
||||||
if (info.Get("challenge") != Party::Container.Challenge)
|
if (info.Get("challenge") != Party::Container.Challenge)
|
||||||
{
|
{
|
||||||
Party::ConnectError("Invalid join response: Challenge mismatch.");
|
Party::ConnectError("Invalid join response: Challenge mismatch.");
|
||||||
}
|
}
|
||||||
else if (securityLevel > Auth::GetSecurityLevel())
|
else if (securityLevel > Auth::GetSecurityLevel())
|
||||||
{
|
{
|
||||||
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
|
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
|
||||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||||
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
|
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
|
||||||
}
|
}
|
||||||
else if (!matchType)
|
else if (!matchType)
|
||||||
{
|
{
|
||||||
Party::ConnectError("Server is not hosting a match.");
|
Party::ConnectError("Server is not hosting a match.");
|
||||||
}
|
}
|
||||||
// Connect
|
// Connect
|
||||||
else if (matchType == 1) // Party
|
else if (matchType == 1) // Party
|
||||||
{
|
{
|
||||||
// Send playlist request
|
// Send playlist request
|
||||||
Party::Container.RequestTime = Game::Sys_Milliseconds();
|
Party::Container.RequestTime = Game::Sys_Milliseconds();
|
||||||
Party::Container.AwaitingPlaylist = true;
|
Party::Container.AwaitingPlaylist = true;
|
||||||
Network::SendCommand(address, "getplaylist");
|
Network::SendCommand(address, "getplaylist");
|
||||||
|
|
||||||
// This is not a safe method
|
// This is not a safe method
|
||||||
// TODO: Fix actual error!
|
// TODO: Fix actual error!
|
||||||
if (Game::CL_IsCgameInitialized())
|
if (Game::CL_IsCgameInitialized())
|
||||||
{
|
{
|
||||||
Command::Execute("disconnect", true);
|
Command::Execute("disconnect", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchType == 2) // Match
|
else if (matchType == 2) // Match
|
||||||
{
|
{
|
||||||
if (atoi(info.Get("clients").data()) >= atoi(info.Get("sv_maxclients").data()))
|
if (atoi(info.Get("clients").data()) >= atoi(info.Get("sv_maxclients").data()))
|
||||||
{
|
{
|
||||||
Party::ConnectError("@EXE_SERVERISFULL");
|
Party::ConnectError("@EXE_SERVERISFULL");
|
||||||
}
|
}
|
||||||
if (info.Get("mapname") == "" || info.Get("gametype") == "")
|
if (info.Get("mapname") == "" || info.Get("gametype") == "")
|
||||||
{
|
{
|
||||||
Party::ConnectError("Invalid map or gametype.");
|
Party::ConnectError("Invalid map or gametype.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dvar::Var("xblive_privateserver").Set(true);
|
Dvar::Var("xblive_privateserver").Set(true);
|
||||||
|
|
||||||
Game::Menus_CloseAll(Game::uiContext);
|
Game::Menus_CloseAll(Game::uiContext);
|
||||||
|
|
||||||
Game::_XSESSION_INFO hostInfo;
|
Game::_XSESSION_INFO hostInfo;
|
||||||
Game::CL_ConnectFromParty(0, &hostInfo, *address.Get(), 0, 0, info.Get("mapname").data(), info.Get("gametype").data());
|
Game::CL_ConnectFromParty(0, &hostInfo, *address.Get(), 0, 0, info.Get("mapname").data(), info.Get("gametype").data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Party::ConnectError("Invalid join response: Unknown matchtype");
|
Party::ConnectError("Invalid join response: Unknown matchtype");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerList::Insert(address, info);
|
ServerList::Insert(address, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Party::~Party()
|
Party::~Party()
|
||||||
{
|
{
|
||||||
Party::LobbyMap.clear();
|
Party::LobbyMap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,149 +1,149 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::string Playlist::CurrentPlaylistBuffer;
|
std::string Playlist::CurrentPlaylistBuffer;
|
||||||
std::string Playlist::ReceivedPlaylistBuffer;
|
std::string Playlist::ReceivedPlaylistBuffer;
|
||||||
|
|
||||||
void Playlist::LoadPlaylist()
|
void Playlist::LoadPlaylist()
|
||||||
{
|
{
|
||||||
// Check if playlist already loaded
|
// Check if playlist already loaded
|
||||||
if (Utils::Hook::Get<bool>(0x1AD3680)) return;
|
if (Utils::Hook::Get<bool>(0x1AD3680)) return;
|
||||||
|
|
||||||
// Don't load playlists when dedi and no party
|
// Don't load playlists when dedi and no party
|
||||||
if (Dedicated::IsDedicated() && !Dvar::Var("party_enable").Get<bool>())
|
if (Dedicated::IsDedicated() && !Dvar::Var("party_enable").Get<bool>())
|
||||||
{
|
{
|
||||||
Utils::Hook::Set<bool>(0x1AD3680, true); // Set received to true
|
Utils::Hook::Set<bool>(0x1AD3680, true); // Set received to true
|
||||||
Dvar::Var("xblive_privateserver").Set(true);
|
Dvar::Var("xblive_privateserver").Set(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dvar::Var("xblive_privateserver").Set(false);
|
Dvar::Var("xblive_privateserver").Set(false);
|
||||||
|
|
||||||
std::string playlistFilename = Dvar::Var("playlistFilename").Get<char*>();
|
std::string playlistFilename = Dvar::Var("playlistFilename").Get<char*>();
|
||||||
FileSystem::File playlist(playlistFilename);
|
FileSystem::File playlist(playlistFilename);
|
||||||
|
|
||||||
if (playlist.Exists())
|
if (playlist.Exists())
|
||||||
{
|
{
|
||||||
Logger::Print("Parsing playlist '%s'...\n", playlist.GetName().data());
|
Logger::Print("Parsing playlist '%s'...\n", playlist.GetName().data());
|
||||||
Game::Live_ParsePlaylists(playlist.GetBuffer().data());
|
Game::Live_ParsePlaylists(playlist.GetBuffer().data());
|
||||||
Utils::Hook::Set<bool>(0x1AD3680, true); // Playlist loaded
|
Utils::Hook::Set<bool>(0x1AD3680, true); // Playlist loaded
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Unable to load playlist '%s'!\n", playlist.GetName().data());
|
Logger::Print("Unable to load playlist '%s'!\n", playlist.GetName().data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Playlist::StorePlaylistStub(const char** buffer)
|
DWORD Playlist::StorePlaylistStub(const char** buffer)
|
||||||
{
|
{
|
||||||
Playlist::CurrentPlaylistBuffer = *buffer;
|
Playlist::CurrentPlaylistBuffer = *buffer;
|
||||||
return Utils::Hook::Call<DWORD(const char**)>(0x4C0350)(buffer);
|
return Utils::Hook::Call<DWORD(const char**)>(0x4C0350)(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::PlaylistRequest(Network::Address address, std::string data)
|
void Playlist::PlaylistRequest(Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
Logger::Print("Received playlist request, sending currently stored buffer.\n");
|
Logger::Print("Received playlist request, sending currently stored buffer.\n");
|
||||||
|
|
||||||
std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer);
|
std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer);
|
||||||
|
|
||||||
Proto::Party::Playlist list;
|
Proto::Party::Playlist list;
|
||||||
list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList));
|
list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList));
|
||||||
list.set_buffer(compressedList);
|
list.set_buffer(compressedList);
|
||||||
|
|
||||||
Network::SendCommand(address, "playlistResponse", list.SerializeAsString());
|
Network::SendCommand(address, "playlistResponse", list.SerializeAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::PlaylistReponse(Network::Address address, std::string data)
|
void Playlist::PlaylistReponse(Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
if (Party::PlaylistAwaiting())
|
if (Party::PlaylistAwaiting())
|
||||||
{
|
{
|
||||||
if (address == Party::Target())
|
if (address == Party::Target())
|
||||||
{
|
{
|
||||||
Proto::Party::Playlist list;
|
Proto::Party::Playlist list;
|
||||||
|
|
||||||
if (!list.ParseFromString(data))
|
if (!list.ParseFromString(data))
|
||||||
{
|
{
|
||||||
Party::PlaylistError(Utils::VA("Received playlist response from %s, but it is invalid.", address.GetCString()));
|
Party::PlaylistError(fmt::sprintf("Received playlist response from %s, but it is invalid.", address.GetCString()));
|
||||||
Playlist::ReceivedPlaylistBuffer.clear();
|
Playlist::ReceivedPlaylistBuffer.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Generate buffer and hash
|
// Generate buffer and hash
|
||||||
std::string compressedData(list.buffer());
|
std::string compressedData(list.buffer());
|
||||||
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData);
|
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData);
|
||||||
|
|
||||||
//Validate hashes
|
//Validate hashes
|
||||||
if (hash != list.hash())
|
if (hash != list.hash())
|
||||||
{
|
{
|
||||||
Party::PlaylistError(Utils::VA("Received playlist response from %s, but the checksum did not match (%X != %X).", address.GetCString(), list.hash(), hash));
|
Party::PlaylistError(fmt::sprintf("Received playlist response from %s, but the checksum did not match (%X != %X).", address.GetCString(), list.hash(), hash));
|
||||||
Playlist::ReceivedPlaylistBuffer.clear();
|
Playlist::ReceivedPlaylistBuffer.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress buffer
|
// Decompress buffer
|
||||||
Playlist::ReceivedPlaylistBuffer = Utils::Compression::ZLib::Decompress(compressedData);
|
Playlist::ReceivedPlaylistBuffer = Utils::Compression::ZLib::Decompress(compressedData);
|
||||||
|
|
||||||
// Load and continue connection
|
// Load and continue connection
|
||||||
Logger::Print("Received playlist, loading and continuing connection...\n");
|
Logger::Print("Received playlist, loading and continuing connection...\n");
|
||||||
Game::Live_ParsePlaylists(Playlist::ReceivedPlaylistBuffer.data());
|
Game::Live_ParsePlaylists(Playlist::ReceivedPlaylistBuffer.data());
|
||||||
Party::PlaylistContinue();
|
Party::PlaylistContinue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Received playlist from someone else than our target host, ignoring it.\n");
|
Logger::Print("Received playlist from someone else than our target host, ignoring it.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Received stray playlist response, ignoring it.\n");
|
Logger::Print("Received stray playlist response, ignoring it.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Playlist::Playlist()
|
Playlist::Playlist()
|
||||||
{
|
{
|
||||||
// Default playlists
|
// Default playlists
|
||||||
Utils::Hook::Set<char*>(0x60B06E, "playlists_default.info");
|
Utils::Hook::Set<char*>(0x60B06E, "playlists_default.info");
|
||||||
|
|
||||||
// disable playlist download function
|
// disable playlist download function
|
||||||
Utils::Hook::Set<BYTE>(0x4D4790, 0xC3);
|
Utils::Hook::Set<BYTE>(0x4D4790, 0xC3);
|
||||||
|
|
||||||
// Load playlist, but don't delete it
|
// Load playlist, but don't delete it
|
||||||
Utils::Hook::Nop(0x4D6EBB, 5);
|
Utils::Hook::Nop(0x4D6EBB, 5);
|
||||||
Utils::Hook::Nop(0x4D6E67, 5);
|
Utils::Hook::Nop(0x4D6E67, 5);
|
||||||
Utils::Hook::Nop(0x4D6E71, 2);
|
Utils::Hook::Nop(0x4D6E71, 2);
|
||||||
|
|
||||||
// playlist dvar 'validity check'
|
// playlist dvar 'validity check'
|
||||||
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
|
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
|
||||||
|
|
||||||
// disable playlist checking
|
// disable playlist checking
|
||||||
Utils::Hook::Set<BYTE>(0x5B69E9, 0xEB); // too new
|
Utils::Hook::Set<BYTE>(0x5B69E9, 0xEB); // too new
|
||||||
Utils::Hook::Set<BYTE>(0x5B696E, 0xEB); // too old
|
Utils::Hook::Set<BYTE>(0x5B696E, 0xEB); // too old
|
||||||
|
|
||||||
//Got playlists is true
|
//Got playlists is true
|
||||||
//Utils::Hook::Set<bool>(0x1AD3680, true);
|
//Utils::Hook::Set<bool>(0x1AD3680, true);
|
||||||
|
|
||||||
// Store playlist buffer on load
|
// Store playlist buffer on load
|
||||||
Utils::Hook(0x42961C, Playlist::StorePlaylistStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x42961C, Playlist::StorePlaylistStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
//if (Dedicated::IsDedicated())
|
//if (Dedicated::IsDedicated())
|
||||||
{
|
{
|
||||||
// Custom playlist loading
|
// Custom playlist loading
|
||||||
Utils::Hook(0x420B5A, Playlist::LoadPlaylist, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x420B5A, Playlist::LoadPlaylist, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// disable playlist.ff loading function
|
// disable playlist.ff loading function
|
||||||
Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
|
Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Handle("getPlaylist", PlaylistRequest);
|
Network::Handle("getPlaylist", PlaylistRequest);
|
||||||
Network::Handle("playlistResponse", PlaylistReponse);
|
Network::Handle("playlistResponse", PlaylistReponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
Playlist::~Playlist()
|
Playlist::~Playlist()
|
||||||
{
|
{
|
||||||
Playlist::CurrentPlaylistBuffer.clear();
|
Playlist::CurrentPlaylistBuffer.clear();
|
||||||
Playlist::ReceivedPlaylistBuffer.clear();
|
Playlist::ReceivedPlaylistBuffer.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,354 +1,354 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
wink::signal<wink::slot<QuickPatch::Callback>> QuickPatch::ShutdownSignal;
|
wink::signal<wink::slot<QuickPatch::Callback>> QuickPatch::ShutdownSignal;
|
||||||
|
|
||||||
int64_t* QuickPatch::GetStatsID()
|
int64_t* QuickPatch::GetStatsID()
|
||||||
{
|
{
|
||||||
static int64_t id = 0x110000100001337;
|
static int64_t id = 0x110000100001337;
|
||||||
return &id;
|
return &id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickPatch::OnShutdown(QuickPatch::Callback callback)
|
void QuickPatch::OnShutdown(QuickPatch::Callback callback)
|
||||||
{
|
{
|
||||||
QuickPatch::ShutdownSignal.connect(callback);
|
QuickPatch::ShutdownSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickPatch::ShutdownStub(int channel, const char* message)
|
void QuickPatch::ShutdownStub(int channel, const char* message)
|
||||||
{
|
{
|
||||||
Game::Com_Printf(0, message);
|
Game::Com_Printf(0, message);
|
||||||
QuickPatch::ShutdownSignal();
|
QuickPatch::ShutdownSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickPatch::OnFrame(QuickPatch::Callback* callback)
|
void QuickPatch::OnFrame(QuickPatch::Callback* callback)
|
||||||
{
|
{
|
||||||
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled())
|
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
Dedicated::OnFrame(callback);
|
Dedicated::OnFrame(callback);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Renderer::OnFrame(callback);
|
Renderer::OnFrame(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickPatch::Once(QuickPatch::Callback* callback)
|
void QuickPatch::Once(QuickPatch::Callback* callback)
|
||||||
{
|
{
|
||||||
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled())
|
if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
Dedicated::Once(callback);
|
Dedicated::Once(callback);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Renderer::Once(callback);
|
Renderer::Once(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickPatch::UnlockStats()
|
void QuickPatch::UnlockStats()
|
||||||
{
|
{
|
||||||
Command::Execute("setPlayerData prestige 10");
|
Command::Execute("setPlayerData prestige 10");
|
||||||
Command::Execute("setPlayerData experience 2516000");
|
Command::Execute("setPlayerData experience 2516000");
|
||||||
Command::Execute("setPlayerData iconUnlocked cardicon_prestige10_02 1");
|
Command::Execute("setPlayerData iconUnlocked cardicon_prestige10_02 1");
|
||||||
|
|
||||||
// Unlock challenges
|
// Unlock challenges
|
||||||
Game::StringTable* challengeTable = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_STRINGTABLE, "mp/allchallengestable.csv").stringTable;
|
Game::StringTable* challengeTable = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_STRINGTABLE, "mp/allchallengestable.csv").stringTable;
|
||||||
|
|
||||||
if (challengeTable)
|
if (challengeTable)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < challengeTable->rowCount; ++i)
|
for (int i = 0; i < challengeTable->rowCount; ++i)
|
||||||
{
|
{
|
||||||
// Find challenge
|
// Find challenge
|
||||||
const char* challenge = Game::TableLookup(challengeTable, i, 0);
|
const char* challenge = Game::TableLookup(challengeTable, i, 0);
|
||||||
|
|
||||||
int maxState = 0;
|
int maxState = 0;
|
||||||
int maxProgress = 0;
|
int maxProgress = 0;
|
||||||
|
|
||||||
// Find correct tier and progress
|
// Find correct tier and progress
|
||||||
for (int j = 0; j < 10; ++j)
|
for (int j = 0; j < 10; ++j)
|
||||||
{
|
{
|
||||||
int progress = atoi(Game::TableLookup(challengeTable, i, 6 + j * 2));
|
int progress = atoi(Game::TableLookup(challengeTable, i, 6 + j * 2));
|
||||||
if (!progress) break;
|
if (!progress) break;
|
||||||
|
|
||||||
maxState = j + 2;
|
maxState = j + 2;
|
||||||
maxProgress = progress;
|
maxProgress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Execute(Utils::VA("setPlayerData challengeState %s %d", challenge, maxState));
|
Command::Execute(fmt::sprintf("setPlayerData challengeState %s %d", challenge, maxState));
|
||||||
Command::Execute(Utils::VA("setPlayerData challengeProgress %s %d", challenge, maxProgress));
|
Command::Execute(fmt::sprintf("setPlayerData challengeProgress %s %d", challenge, maxProgress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int QuickPatch::MsgReadBitsCompressCheckSV(const char *from, char *to, int size)
|
int QuickPatch::MsgReadBitsCompressCheckSV(const char *from, char *to, int size)
|
||||||
{
|
{
|
||||||
if (size > 0x800) return 0;
|
if (size > 0x800) return 0;
|
||||||
return Game::MSG_ReadBitsCompress(from, to, size);
|
return Game::MSG_ReadBitsCompress(from, to, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int QuickPatch::MsgReadBitsCompressCheckCL(const char *from, char *to, int size)
|
int QuickPatch::MsgReadBitsCompressCheckCL(const char *from, char *to, int size)
|
||||||
{
|
{
|
||||||
if (size > 0x20000) return 0;
|
if (size > 0x20000) return 0;
|
||||||
return Game::MSG_ReadBitsCompress(from, to, size);
|
return Game::MSG_ReadBitsCompress(from, to, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickPatch::QuickPatch()
|
QuickPatch::QuickPatch()
|
||||||
{
|
{
|
||||||
// protocol version (workaround for hacks)
|
// protocol version (workaround for hacks)
|
||||||
Utils::Hook::Set<int>(0x4FB501, PROTOCOL);
|
Utils::Hook::Set<int>(0x4FB501, PROTOCOL);
|
||||||
|
|
||||||
// protocol command
|
// protocol command
|
||||||
Utils::Hook::Set<int>(0x4D36A9, PROTOCOL);
|
Utils::Hook::Set<int>(0x4D36A9, PROTOCOL);
|
||||||
Utils::Hook::Set<int>(0x4D36AE, PROTOCOL);
|
Utils::Hook::Set<int>(0x4D36AE, PROTOCOL);
|
||||||
Utils::Hook::Set<int>(0x4D36B3, PROTOCOL);
|
Utils::Hook::Set<int>(0x4D36B3, PROTOCOL);
|
||||||
|
|
||||||
// internal version is 99, most servers should accept it
|
// internal version is 99, most servers should accept it
|
||||||
Utils::Hook::Set<int>(0x463C61, 208);
|
Utils::Hook::Set<int>(0x463C61, 208);
|
||||||
|
|
||||||
// remove system pre-init stuff (improper quit, disk full)
|
// remove system pre-init stuff (improper quit, disk full)
|
||||||
Utils::Hook::Set<BYTE>(0x411350, 0xC3);
|
Utils::Hook::Set<BYTE>(0x411350, 0xC3);
|
||||||
|
|
||||||
// remove STEAMSTART checking for DRM IPC
|
// remove STEAMSTART checking for DRM IPC
|
||||||
Utils::Hook::Nop(0x451145, 5);
|
Utils::Hook::Nop(0x451145, 5);
|
||||||
Utils::Hook::Set<BYTE>(0x45114C, 0xEB);
|
Utils::Hook::Set<BYTE>(0x45114C, 0xEB);
|
||||||
|
|
||||||
// LSP disabled
|
// LSP disabled
|
||||||
Utils::Hook::Set<BYTE>(0x435950, 0xC3); // LSP HELLO
|
Utils::Hook::Set<BYTE>(0x435950, 0xC3); // LSP HELLO
|
||||||
Utils::Hook::Set<BYTE>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
|
Utils::Hook::Set<BYTE>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
|
||||||
Utils::Hook::Set<BYTE>(0x4BD900, 0xC3); // main LSP response func
|
Utils::Hook::Set<BYTE>(0x4BD900, 0xC3); // main LSP response func
|
||||||
Utils::Hook::Set<BYTE>(0x682170, 0xC3); // Telling LSP that we're playing a private match
|
Utils::Hook::Set<BYTE>(0x682170, 0xC3); // Telling LSP that we're playing a private match
|
||||||
Utils::Hook::Nop(0x4FD448, 5); // Don't create lsp_socket
|
Utils::Hook::Nop(0x4FD448, 5); // Don't create lsp_socket
|
||||||
|
|
||||||
// Don't delete config files if corrupted
|
// Don't delete config files if corrupted
|
||||||
Utils::Hook::Set<BYTE>(0x47DCB3, 0xEB);
|
Utils::Hook::Set<BYTE>(0x47DCB3, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x4402B6, 0);
|
Utils::Hook::Set<BYTE>(0x4402B6, 0);
|
||||||
|
|
||||||
// hopefully allow alt-tab during game, used at least in alt-enter handling
|
// hopefully allow alt-tab during game, used at least in alt-enter handling
|
||||||
Utils::Hook::Set<DWORD>(0x45ACE0, 0xC301B0);
|
Utils::Hook::Set<DWORD>(0x45ACE0, 0xC301B0);
|
||||||
|
|
||||||
// fs_basegame
|
// fs_basegame
|
||||||
Utils::Hook::Set<char*>(0x6431D1, BASEGAME);
|
Utils::Hook::Set<char*>(0x6431D1, BASEGAME);
|
||||||
|
|
||||||
// UI version string
|
// UI version string
|
||||||
Utils::Hook::Set<char*>(0x43F73B, "IW4x: r" REVISION_STR REVISION_SUFFIX "-" MILESTONE);
|
Utils::Hook::Set<char*>(0x43F73B, "IW4x: r" REVISION_STR REVISION_SUFFIX "-" MILESTONE);
|
||||||
|
|
||||||
// console version string
|
// console version string
|
||||||
Utils::Hook::Set<char*>(0x4B12BB, "IW4x r" REVISION_STR REVISION_SUFFIX "-" MILESTONE " (built " __DATE__ " " __TIME__ ")");
|
Utils::Hook::Set<char*>(0x4B12BB, "IW4x r" REVISION_STR REVISION_SUFFIX "-" MILESTONE " (built " __DATE__ " " __TIME__ ")");
|
||||||
|
|
||||||
// version string
|
// version string
|
||||||
Utils::Hook::Set<char*>(0x60BD56, "IW4x (r" REVISION_STR REVISION_SUFFIX ")");
|
Utils::Hook::Set<char*>(0x60BD56, "IW4x (r" REVISION_STR REVISION_SUFFIX ")");
|
||||||
|
|
||||||
// console title
|
// console title
|
||||||
if (ZoneBuilder::IsEnabled())
|
if (ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): ZoneBuilder");
|
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): ZoneBuilder");
|
||||||
}
|
}
|
||||||
else if (Dedicated::IsDedicated())
|
else if (Dedicated::IsDedicated())
|
||||||
{
|
{
|
||||||
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Dedicated");
|
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Dedicated");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Console");
|
Utils::Hook::Set<char*>(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Console");
|
||||||
}
|
}
|
||||||
|
|
||||||
// window title
|
// window title
|
||||||
Utils::Hook::Set<char*>(0x5076A0, "IW4x: Multiplayer");
|
Utils::Hook::Set<char*>(0x5076A0, "IW4x: Multiplayer");
|
||||||
|
|
||||||
// sv_hostname
|
// sv_hostname
|
||||||
Utils::Hook::Set<char*>(0x4D378B, "IW4Host");
|
Utils::Hook::Set<char*>(0x4D378B, "IW4Host");
|
||||||
|
|
||||||
// shortversion
|
// shortversion
|
||||||
Utils::Hook::Set<char*>(0x60BD91, VERSION_STR);
|
Utils::Hook::Set<char*>(0x60BD91, VERSION_STR);
|
||||||
|
|
||||||
// console logo
|
// console logo
|
||||||
Utils::Hook::Set<char*>(0x428A66, BASEGAME "/images/logo.bmp");
|
Utils::Hook::Set<char*>(0x428A66, BASEGAME "/images/logo.bmp");
|
||||||
|
|
||||||
// splash logo
|
// splash logo
|
||||||
Utils::Hook::Set<char*>(0x475F9E, BASEGAME "/images/splash.bmp");
|
Utils::Hook::Set<char*>(0x475F9E, BASEGAME "/images/splash.bmp");
|
||||||
|
|
||||||
// Numerical ping (cg_scoreboardPingText 1)
|
// Numerical ping (cg_scoreboardPingText 1)
|
||||||
Utils::Hook::Set<BYTE>(0x45888E, 1);
|
Utils::Hook::Set<BYTE>(0x45888E, 1);
|
||||||
Utils::Hook::Set<BYTE>(0x45888C, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
Utils::Hook::Set<BYTE>(0x45888C, Game::dvar_flag::DVAR_FLAG_CHEAT);
|
||||||
|
|
||||||
// increase font sizes for chat on higher resolutions
|
// increase font sizes for chat on higher resolutions
|
||||||
static float float13 = 13.0f;
|
static float float13 = 13.0f;
|
||||||
static float float10 = 10.0f;
|
static float float10 = 10.0f;
|
||||||
Utils::Hook::Set<float*>(0x5814AE, &float13);
|
Utils::Hook::Set<float*>(0x5814AE, &float13);
|
||||||
Utils::Hook::Set<float*>(0x5814C8, &float10);
|
Utils::Hook::Set<float*>(0x5814C8, &float10);
|
||||||
|
|
||||||
// Enable commandline arguments
|
// Enable commandline arguments
|
||||||
Utils::Hook::Set<BYTE>(0x464AE4, 0xEB);
|
Utils::Hook::Set<BYTE>(0x464AE4, 0xEB);
|
||||||
|
|
||||||
// remove limit on IWD file loading
|
// remove limit on IWD file loading
|
||||||
Utils::Hook::Set<BYTE>(0x642BF3, 0xEB);
|
Utils::Hook::Set<BYTE>(0x642BF3, 0xEB);
|
||||||
|
|
||||||
// Disable UPNP
|
// Disable UPNP
|
||||||
Utils::Hook::Nop(0x60BE24, 5);
|
Utils::Hook::Nop(0x60BE24, 5);
|
||||||
|
|
||||||
// disable the IWNet IP detection (default 'got ipdetect' flag to 1)
|
// disable the IWNet IP detection (default 'got ipdetect' flag to 1)
|
||||||
Utils::Hook::Set<BYTE>(0x649D6F0, 1);
|
Utils::Hook::Set<BYTE>(0x649D6F0, 1);
|
||||||
|
|
||||||
// Fix stats sleeping
|
// Fix stats sleeping
|
||||||
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);
|
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);
|
||||||
Utils::Hook::Set<BYTE>(0x4BD190, 0xC3);
|
Utils::Hook::Set<BYTE>(0x4BD190, 0xC3);
|
||||||
|
|
||||||
// default sv_pure to 0
|
// default sv_pure to 0
|
||||||
Utils::Hook::Set<BYTE>(0x4D3A74, 0);
|
Utils::Hook::Set<BYTE>(0x4D3A74, 0);
|
||||||
|
|
||||||
// Force debug logging
|
// Force debug logging
|
||||||
Utils::Hook::Nop(0x4AA89F, 2);
|
Utils::Hook::Nop(0x4AA89F, 2);
|
||||||
Utils::Hook::Nop(0x4AA8A1, 6);
|
Utils::Hook::Nop(0x4AA8A1, 6);
|
||||||
|
|
||||||
// remove activeAction execution (exploit in mods)
|
// remove activeAction execution (exploit in mods)
|
||||||
Utils::Hook::Set<BYTE>(0x5A1D43, 0xEB);
|
Utils::Hook::Set<BYTE>(0x5A1D43, 0xEB);
|
||||||
|
|
||||||
// disable bind protection
|
// disable bind protection
|
||||||
Utils::Hook::Set<BYTE>(0x4DACA2, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4DACA2, 0xEB);
|
||||||
|
|
||||||
// require Windows 5
|
// require Windows 5
|
||||||
Utils::Hook::Set<BYTE>(0x467ADF, 5);
|
Utils::Hook::Set<BYTE>(0x467ADF, 5);
|
||||||
Utils::Hook::Set<char>(0x6DF5D6, '5');
|
Utils::Hook::Set<char>(0x6DF5D6, '5');
|
||||||
|
|
||||||
// disable 'ignoring asset' notices
|
// disable 'ignoring asset' notices
|
||||||
Utils::Hook::Nop(0x5BB902, 5);
|
Utils::Hook::Nop(0x5BB902, 5);
|
||||||
|
|
||||||
// disable migration_dvarErrors
|
// disable migration_dvarErrors
|
||||||
Utils::Hook::Set<BYTE>(0x60BDA7, 0);
|
Utils::Hook::Set<BYTE>(0x60BDA7, 0);
|
||||||
|
|
||||||
// allow joining 'developer 1' servers
|
// allow joining 'developer 1' servers
|
||||||
Utils::Hook::Set<BYTE>(0x478BA2, 0xEB);
|
Utils::Hook::Set<BYTE>(0x478BA2, 0xEB);
|
||||||
|
|
||||||
// fs_game fixes
|
// fs_game fixes
|
||||||
Utils::Hook::Nop(0x4A5D74, 2); // remove fs_game profiles
|
Utils::Hook::Nop(0x4A5D74, 2); // remove fs_game profiles
|
||||||
Utils::Hook::Set<BYTE>(0x4081FD, 0xEB); // defaultweapon
|
Utils::Hook::Set<BYTE>(0x4081FD, 0xEB); // defaultweapon
|
||||||
Utils::Hook::Set<BYTE>(0x452C1D, 0xEB); // LoadObj weaponDefs
|
Utils::Hook::Set<BYTE>(0x452C1D, 0xEB); // LoadObj weaponDefs
|
||||||
|
|
||||||
// filesystem init default_mp.cfg check
|
// filesystem init default_mp.cfg check
|
||||||
Utils::Hook::Nop(0x461A9E, 5);
|
Utils::Hook::Nop(0x461A9E, 5);
|
||||||
Utils::Hook::Nop(0x461AAA, 5);
|
Utils::Hook::Nop(0x461AAA, 5);
|
||||||
Utils::Hook::Set<BYTE>(0x461AB4, 0xEB);
|
Utils::Hook::Set<BYTE>(0x461AB4, 0xEB);
|
||||||
|
|
||||||
// vid_restart when ingame
|
// vid_restart when ingame
|
||||||
Utils::Hook::Nop(0x4CA1FA, 6);
|
Utils::Hook::Nop(0x4CA1FA, 6);
|
||||||
|
|
||||||
// Filter log (initially com_logFilter, but I don't see why that dvar is needed)
|
// Filter log (initially com_logFilter, but I don't see why that dvar is needed)
|
||||||
Utils::Hook::Nop(0x647466, 5); // 'dvar set' lines
|
Utils::Hook::Nop(0x647466, 5); // 'dvar set' lines
|
||||||
Utils::Hook::Nop(0x5DF4F2, 5); // 'sending splash open' lines
|
Utils::Hook::Nop(0x5DF4F2, 5); // 'sending splash open' lines
|
||||||
|
|
||||||
// intro stuff
|
// intro stuff
|
||||||
Utils::Hook::Nop(0x60BEE9, 5); // Don't show legals
|
Utils::Hook::Nop(0x60BEE9, 5); // Don't show legals
|
||||||
Utils::Hook::Nop(0x60BEF6, 5); // Don't reset the intro dvar
|
Utils::Hook::Nop(0x60BEF6, 5); // Don't reset the intro dvar
|
||||||
Utils::Hook::Set<char*>(0x60BED2, "unskippablecinematic IW_logo\n");
|
Utils::Hook::Set<char*>(0x60BED2, "unskippablecinematic IW_logo\n");
|
||||||
|
|
||||||
// Redirect logs
|
// Redirect logs
|
||||||
Utils::Hook::Set<char*>(0x5E44D8, "logs/games_mp.log");
|
Utils::Hook::Set<char*>(0x5E44D8, "logs/games_mp.log");
|
||||||
Utils::Hook::Set<char*>(0x60A90C, "logs/console_mp.log");
|
Utils::Hook::Set<char*>(0x60A90C, "logs/console_mp.log");
|
||||||
Utils::Hook::Set<char*>(0x60A918, "logs/console_mp.log");
|
Utils::Hook::Set<char*>(0x60A918, "logs/console_mp.log");
|
||||||
|
|
||||||
// Rename config
|
// Rename config
|
||||||
Utils::Hook::Set<char*>(0x461B4B, CLIENT_CONFIG);
|
Utils::Hook::Set<char*>(0x461B4B, CLIENT_CONFIG);
|
||||||
Utils::Hook::Set<char*>(0x47DCBB, CLIENT_CONFIG);
|
Utils::Hook::Set<char*>(0x47DCBB, CLIENT_CONFIG);
|
||||||
Utils::Hook::Set<char*>(0x6098F8, CLIENT_CONFIG);
|
Utils::Hook::Set<char*>(0x6098F8, CLIENT_CONFIG);
|
||||||
Utils::Hook::Set<char*>(0x60B279, CLIENT_CONFIG);
|
Utils::Hook::Set<char*>(0x60B279, CLIENT_CONFIG);
|
||||||
Utils::Hook::Set<char*>(0x60BBD4, CLIENT_CONFIG);
|
Utils::Hook::Set<char*>(0x60BBD4, CLIENT_CONFIG);
|
||||||
|
|
||||||
Utils::Hook(0x4D4007, QuickPatch::ShutdownStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4D4007, QuickPatch::ShutdownStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Disable profile system
|
// Disable profile system
|
||||||
Utils::Hook::Nop(0x60BEB1, 5); // GamerProfile_InitAllProfiles
|
Utils::Hook::Nop(0x60BEB1, 5); // GamerProfile_InitAllProfiles
|
||||||
Utils::Hook::Nop(0x60BEB8, 5); // GamerProfile_LogInProfile
|
Utils::Hook::Nop(0x60BEB8, 5); // GamerProfile_LogInProfile
|
||||||
// Utils::Hook::Nop(0x4059EA, 5); // GamerProfile_RegisterCommands
|
// Utils::Hook::Nop(0x4059EA, 5); // GamerProfile_RegisterCommands
|
||||||
Utils::Hook::Nop(0x4059EF, 5); // GamerProfile_RegisterDvars
|
Utils::Hook::Nop(0x4059EF, 5); // GamerProfile_RegisterDvars
|
||||||
Utils::Hook::Nop(0x47DF9A, 5); // GamerProfile_UpdateSystemDvars
|
Utils::Hook::Nop(0x47DF9A, 5); // GamerProfile_UpdateSystemDvars
|
||||||
Utils::Hook::Set<BYTE>(0x5AF0D0, 0xC3); // GamerProfile_SaveProfile
|
Utils::Hook::Set<BYTE>(0x5AF0D0, 0xC3); // GamerProfile_SaveProfile
|
||||||
Utils::Hook::Set<BYTE>(0x4E6870, 0xC3); // GamerProfile_UpdateSystemVarsFromProfile
|
Utils::Hook::Set<BYTE>(0x4E6870, 0xC3); // GamerProfile_UpdateSystemVarsFromProfile
|
||||||
Utils::Hook::Set<BYTE>(0x4C37F0, 0xC3); // GamerProfile_UpdateProfileAndSaveIfNeeded
|
Utils::Hook::Set<BYTE>(0x4C37F0, 0xC3); // GamerProfile_UpdateProfileAndSaveIfNeeded
|
||||||
Utils::Hook::Set<BYTE>(0x633CA0, 0xC3); // GamerProfile_SetPercentCompleteMP
|
Utils::Hook::Set<BYTE>(0x633CA0, 0xC3); // GamerProfile_SetPercentCompleteMP
|
||||||
|
|
||||||
// GamerProfile_RegisterCommands
|
// GamerProfile_RegisterCommands
|
||||||
// Some random function used as nullsub :P
|
// Some random function used as nullsub :P
|
||||||
Utils::Hook::Set<DWORD>(0x45B868, 0x5188FB); // profile_menuDvarsSetup
|
Utils::Hook::Set<DWORD>(0x45B868, 0x5188FB); // profile_menuDvarsSetup
|
||||||
Utils::Hook::Set<DWORD>(0x45B87E, 0x5188FB); // profile_menuDvarsFinish
|
Utils::Hook::Set<DWORD>(0x45B87E, 0x5188FB); // profile_menuDvarsFinish
|
||||||
Utils::Hook::Set<DWORD>(0x45B894, 0x5188FB); // profile_toggleInvertedPitch
|
Utils::Hook::Set<DWORD>(0x45B894, 0x5188FB); // profile_toggleInvertedPitch
|
||||||
Utils::Hook::Set<DWORD>(0x45B8AA, 0x5188FB); // profile_setViewSensitivity
|
Utils::Hook::Set<DWORD>(0x45B8AA, 0x5188FB); // profile_setViewSensitivity
|
||||||
Utils::Hook::Set<DWORD>(0x45B8C3, 0x5188FB); // profile_setButtonsConfig
|
Utils::Hook::Set<DWORD>(0x45B8C3, 0x5188FB); // profile_setButtonsConfig
|
||||||
Utils::Hook::Set<DWORD>(0x45B8D9, 0x5188FB); // profile_setSticksConfig
|
Utils::Hook::Set<DWORD>(0x45B8D9, 0x5188FB); // profile_setSticksConfig
|
||||||
Utils::Hook::Set<DWORD>(0x45B8EF, 0x5188FB); // profile_toggleAutoAim
|
Utils::Hook::Set<DWORD>(0x45B8EF, 0x5188FB); // profile_toggleAutoAim
|
||||||
Utils::Hook::Set<DWORD>(0x45B905, 0x5188FB); // profile_SetHasEverPlayed_MainMenu
|
Utils::Hook::Set<DWORD>(0x45B905, 0x5188FB); // profile_SetHasEverPlayed_MainMenu
|
||||||
Utils::Hook::Set<DWORD>(0x45B91E, 0x5188FB); // profile_SetHasEverPlayed_SP
|
Utils::Hook::Set<DWORD>(0x45B91E, 0x5188FB); // profile_SetHasEverPlayed_SP
|
||||||
Utils::Hook::Set<DWORD>(0x45B934, 0x5188FB); // profile_SetHasEverPlayed_SO
|
Utils::Hook::Set<DWORD>(0x45B934, 0x5188FB); // profile_SetHasEverPlayed_SO
|
||||||
Utils::Hook::Set<DWORD>(0x45B94A, 0x5188FB); // profile_SetHasEverPlayed_MP
|
Utils::Hook::Set<DWORD>(0x45B94A, 0x5188FB); // profile_SetHasEverPlayed_MP
|
||||||
Utils::Hook::Set<DWORD>(0x45B960, 0x5188FB); // profile_setVolume
|
Utils::Hook::Set<DWORD>(0x45B960, 0x5188FB); // profile_setVolume
|
||||||
Utils::Hook::Set<DWORD>(0x45B979, 0x5188FB); // profile_setGamma
|
Utils::Hook::Set<DWORD>(0x45B979, 0x5188FB); // profile_setGamma
|
||||||
Utils::Hook::Set<DWORD>(0x45B98F, 0x5188FB); // profile_setBlacklevel
|
Utils::Hook::Set<DWORD>(0x45B98F, 0x5188FB); // profile_setBlacklevel
|
||||||
Utils::Hook::Set<DWORD>(0x45B9A5, 0x5188FB); // profile_toggleCanSkipOffensiveMissions
|
Utils::Hook::Set<DWORD>(0x45B9A5, 0x5188FB); // profile_toggleCanSkipOffensiveMissions
|
||||||
|
|
||||||
// Fix mouse pitch adjustments
|
// Fix mouse pitch adjustments
|
||||||
UIScript::Add("updateui_mousePitch", [] ()
|
UIScript::Add("updateui_mousePitch", [] ()
|
||||||
{
|
{
|
||||||
if (Dvar::Var("ui_mousePitch").Get<bool>())
|
if (Dvar::Var("ui_mousePitch").Get<bool>())
|
||||||
{
|
{
|
||||||
Dvar::Var("m_pitch").Set(-0.022f);
|
Dvar::Var("m_pitch").Set(-0.022f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dvar::Var("m_pitch").Set(0.022f);
|
Dvar::Var("m_pitch").Set(0.022f);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rename stat file
|
// Rename stat file
|
||||||
Utils::Hook::SetString(0x71C048, "iw4x.stat");
|
Utils::Hook::SetString(0x71C048, "iw4x.stat");
|
||||||
|
|
||||||
// Patch stats steamid
|
// Patch stats steamid
|
||||||
Utils::Hook::Nop(0x682EBF, 20);
|
Utils::Hook::Nop(0x682EBF, 20);
|
||||||
Utils::Hook::Nop(0x6830B1, 20);
|
Utils::Hook::Nop(0x6830B1, 20);
|
||||||
Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Exploit fixes
|
// Exploit fixes
|
||||||
Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x4A9F56, QuickPatch::MsgReadBitsCompressCheckCL, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4A9F56, QuickPatch::MsgReadBitsCompressCheckCL, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
Command::Add("unlockstats", [] (Command::Params params)
|
Command::Add("unlockstats", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
QuickPatch::UnlockStats();
|
QuickPatch::UnlockStats();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Debug patches
|
// Debug patches
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// ui_debugMode 1
|
// ui_debugMode 1
|
||||||
//Utils::Hook::Set<bool>(0x6312E0, true);
|
//Utils::Hook::Set<bool>(0x6312E0, true);
|
||||||
|
|
||||||
// fs_debug 1
|
// fs_debug 1
|
||||||
Utils::Hook::Set<bool>(0x643172, true);
|
Utils::Hook::Set<bool>(0x643172, true);
|
||||||
|
|
||||||
// developer 2
|
// developer 2
|
||||||
Utils::Hook::Set<BYTE>(0x4FA425, 2);
|
Utils::Hook::Set<BYTE>(0x4FA425, 2);
|
||||||
Utils::Hook::Set<BYTE>(0x51B087, 2);
|
Utils::Hook::Set<BYTE>(0x51B087, 2);
|
||||||
Utils::Hook::Set<BYTE>(0x60AE13, 2);
|
Utils::Hook::Set<BYTE>(0x60AE13, 2);
|
||||||
|
|
||||||
// developer_Script 1
|
// developer_Script 1
|
||||||
Utils::Hook::Set<bool>(0x60AE2B, true);
|
Utils::Hook::Set<bool>(0x60AE2B, true);
|
||||||
|
|
||||||
// Disable cheat protection for dvars
|
// Disable cheat protection for dvars
|
||||||
Utils::Hook::Set<BYTE>(0x647682, 0xEB);
|
Utils::Hook::Set<BYTE>(0x647682, 0xEB);
|
||||||
|
|
||||||
// Constantly draw the mini console
|
// Constantly draw the mini console
|
||||||
Utils::Hook::Set<BYTE>(0x412A45, 0xEB);
|
Utils::Hook::Set<BYTE>(0x412A45, 0xEB);
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
if (*reinterpret_cast<Game::Font**>(0x62E4BAC))
|
if (*reinterpret_cast<Game::Font**>(0x62E4BAC))
|
||||||
{
|
{
|
||||||
Game::Con_DrawMiniConsole(0, 2, 4, (Game::CL_IsCgameInitialized() ? 1.0f : 0.4f));
|
Game::Con_DrawMiniConsole(0, 2, 4, (Game::CL_IsCgameInitialized() ? 1.0f : 0.4f));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickPatch::~QuickPatch()
|
QuickPatch::~QuickPatch()
|
||||||
{
|
{
|
||||||
QuickPatch::ShutdownSignal.clear();
|
QuickPatch::ShutdownSignal.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,170 +1,170 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
RCon::Container RCon::BackdoorContainer;
|
RCon::Container RCon::BackdoorContainer;
|
||||||
Utils::Cryptography::ECC::Key RCon::BackdoorKey;
|
Utils::Cryptography::ECC::Key RCon::BackdoorKey;
|
||||||
|
|
||||||
std::string RCon::Password;
|
std::string RCon::Password;
|
||||||
|
|
||||||
RCon::RCon()
|
RCon::RCon()
|
||||||
{
|
{
|
||||||
Command::Add("rcon", [] (Command::Params params)
|
Command::Add("rcon", [] (Command::Params params)
|
||||||
{
|
{
|
||||||
if (params.Length() < 2) return;
|
if (params.Length() < 2) return;
|
||||||
|
|
||||||
std::string operation = params[1];
|
std::string operation = params[1];
|
||||||
if (operation == "login")
|
if (operation == "login")
|
||||||
{
|
{
|
||||||
if (params.Length() < 3) return;
|
if (params.Length() < 3) return;
|
||||||
RCon::Password = params[2];
|
RCon::Password = params[2];
|
||||||
}
|
}
|
||||||
else if (operation == "logout")
|
else if (operation == "logout")
|
||||||
{
|
{
|
||||||
RCon::Password.clear();
|
RCon::Password.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!RCon::Password.empty() && *reinterpret_cast<int*>(0xB2C540) >= 5) // Get our state
|
if (!RCon::Password.empty() && *reinterpret_cast<int*>(0xB2C540) >= 5) // Get our state
|
||||||
{
|
{
|
||||||
Network::Address target(reinterpret_cast<Game::netadr_t*>(0xA5EA44));
|
Network::Address target(reinterpret_cast<Game::netadr_t*>(0xA5EA44));
|
||||||
|
|
||||||
if (target.IsValid())
|
if (target.IsValid())
|
||||||
{
|
{
|
||||||
Network::SendCommand(target, "rcon", RCon::Password + " " + params.Join(1));
|
Network::SendCommand(target, "rcon", RCon::Password + " " + params.Join(1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("You are connected to an invalid server\n");
|
Logger::Print("You are connected to an invalid server\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("You need to be logged in and connected to a server!\n");
|
Logger::Print("You need to be logged in and connected to a server!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Maybe execute that for clients as well, when we use triangular natting.
|
// TODO: Maybe execute that for clients as well, when we use triangular natting.
|
||||||
if (!Dedicated::IsDedicated()) return;
|
if (!Dedicated::IsDedicated()) return;
|
||||||
|
|
||||||
// Load public key
|
// Load public key
|
||||||
static uint8_t publicKey[] =
|
static uint8_t publicKey[] =
|
||||||
{
|
{
|
||||||
0x04, 0x01, 0x9D, 0x18, 0x7F, 0x57, 0xD8, 0x95, 0x4C, 0xEE, 0xD0, 0x21,
|
0x04, 0x01, 0x9D, 0x18, 0x7F, 0x57, 0xD8, 0x95, 0x4C, 0xEE, 0xD0, 0x21,
|
||||||
0xB5, 0x00, 0x53, 0xEC, 0xEB, 0x54, 0x7C, 0x4C, 0x37, 0x18, 0x53, 0x89,
|
0xB5, 0x00, 0x53, 0xEC, 0xEB, 0x54, 0x7C, 0x4C, 0x37, 0x18, 0x53, 0x89,
|
||||||
0x40, 0x12, 0xF7, 0x08, 0x8D, 0x9A, 0x8D, 0x99, 0x9C, 0x79, 0x79, 0x59,
|
0x40, 0x12, 0xF7, 0x08, 0x8D, 0x9A, 0x8D, 0x99, 0x9C, 0x79, 0x79, 0x59,
|
||||||
0x6E, 0x32, 0x06, 0xEB, 0x49, 0x1E, 0x00, 0x99, 0x71, 0xCB, 0x4A, 0xE1,
|
0x6E, 0x32, 0x06, 0xEB, 0x49, 0x1E, 0x00, 0x99, 0x71, 0xCB, 0x4A, 0xE1,
|
||||||
0x90, 0xF1, 0x7C, 0xB7, 0x4D, 0x60, 0x88, 0x0A, 0xB7, 0xF3, 0xD7, 0x0D,
|
0x90, 0xF1, 0x7C, 0xB7, 0x4D, 0x60, 0x88, 0x0A, 0xB7, 0xF3, 0xD7, 0x0D,
|
||||||
0x4F, 0x08, 0x13, 0x7C, 0xEB, 0x01, 0xFF, 0x00, 0x32, 0xEE, 0xE6, 0x23,
|
0x4F, 0x08, 0x13, 0x7C, 0xEB, 0x01, 0xFF, 0x00, 0x32, 0xEE, 0xE6, 0x23,
|
||||||
0x07, 0xB1, 0xC2, 0x9E, 0x45, 0xD6, 0xD7, 0xBD, 0xED, 0x05, 0x23, 0xB5,
|
0x07, 0xB1, 0xC2, 0x9E, 0x45, 0xD6, 0xD7, 0xBD, 0xED, 0x05, 0x23, 0xB5,
|
||||||
0xE7, 0x83, 0xEF, 0xD7, 0x8E, 0x36, 0xDC, 0x16, 0x79, 0x74, 0xD1, 0xD5,
|
0xE7, 0x83, 0xEF, 0xD7, 0x8E, 0x36, 0xDC, 0x16, 0x79, 0x74, 0xD1, 0xD5,
|
||||||
0xBA, 0x2C, 0x4C, 0x28, 0x61, 0x29, 0x5C, 0x49, 0x7D, 0xD4, 0xB6, 0x56,
|
0xBA, 0x2C, 0x4C, 0x28, 0x61, 0x29, 0x5C, 0x49, 0x7D, 0xD4, 0xB6, 0x56,
|
||||||
0x17, 0x75, 0xF5, 0x2B, 0x58, 0xCD, 0x0D, 0x76, 0x65, 0x10, 0xF7, 0x51,
|
0x17, 0x75, 0xF5, 0x2B, 0x58, 0xCD, 0x0D, 0x76, 0x65, 0x10, 0xF7, 0x51,
|
||||||
0x69, 0x1D, 0xB9, 0x0F, 0x38, 0xF6, 0x53, 0x3B, 0xF7, 0xCE, 0x76, 0x4F,
|
0x69, 0x1D, 0xB9, 0x0F, 0x38, 0xF6, 0x53, 0x3B, 0xF7, 0xCE, 0x76, 0x4F,
|
||||||
0x08
|
0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
RCon::BackdoorKey.Set(std::string(reinterpret_cast<char*>(publicKey), sizeof(publicKey)));
|
RCon::BackdoorKey.Set(std::string(reinterpret_cast<char*>(publicKey), sizeof(publicKey)));
|
||||||
|
|
||||||
RCon::BackdoorContainer.timestamp = 0;
|
RCon::BackdoorContainer.timestamp = 0;
|
||||||
|
|
||||||
Dvar::OnInit([] ()
|
Dvar::OnInit([] ()
|
||||||
{
|
{
|
||||||
Dvar::Register<const char*>("rcon_password", "", Game::dvar_flag::DVAR_FLAG_NONE, "The password for rcon");
|
Dvar::Register<const char*>("rcon_password", "", Game::dvar_flag::DVAR_FLAG_NONE, "The password for rcon");
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("rcon", [] (Network::Address address, std::string data)
|
Network::Handle("rcon", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
Utils::Trim(data);
|
Utils::String::Trim(data);
|
||||||
auto pos = data.find_first_of(" ");
|
auto pos = data.find_first_of(" ");
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
{
|
{
|
||||||
Logger::Print("Invalid RCon request from %s\n", address.GetCString());
|
Logger::Print("Invalid RCon request from %s\n", address.GetCString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string password = data.substr(0, pos);
|
std::string password = data.substr(0, pos);
|
||||||
std::string command = data.substr(pos + 1);
|
std::string command = data.substr(pos + 1);
|
||||||
|
|
||||||
// B3 sends the password inside quotes :S
|
// B3 sends the password inside quotes :S
|
||||||
if (!password.empty() && password[0] == '"' && password[password.size() - 1] == '"')
|
if (!password.empty() && password[0] == '"' && password[password.size() - 1] == '"')
|
||||||
{
|
{
|
||||||
password.pop_back();
|
password.pop_back();
|
||||||
password.erase(password.begin());
|
password.erase(password.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string svPassword = Dvar::Var("rcon_password").Get<std::string>();
|
std::string svPassword = Dvar::Var("rcon_password").Get<std::string>();
|
||||||
|
|
||||||
if (svPassword.empty())
|
if (svPassword.empty())
|
||||||
{
|
{
|
||||||
Logger::Print("RCon request from %s dropped. No password set!\n", address.GetCString());
|
Logger::Print("RCon request from %s dropped. No password set!\n", address.GetCString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svPassword == password)
|
if (svPassword == password)
|
||||||
{
|
{
|
||||||
static std::string outputBuffer;
|
static std::string outputBuffer;
|
||||||
outputBuffer.clear();
|
outputBuffer.clear();
|
||||||
|
|
||||||
Logger::Print("Executing RCon request from %s: %s\n", address.GetCString(), command.data());
|
Logger::Print("Executing RCon request from %s: %s\n", address.GetCString(), command.data());
|
||||||
|
|
||||||
Logger::PipeOutput([] (std::string output)
|
Logger::PipeOutput([] (std::string output)
|
||||||
{
|
{
|
||||||
outputBuffer.append(output);
|
outputBuffer.append(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::Execute(command, true);
|
Command::Execute(command, true);
|
||||||
|
|
||||||
Logger::PipeOutput(nullptr);
|
Logger::PipeOutput(nullptr);
|
||||||
|
|
||||||
Network::SendCommand(address, "print", outputBuffer);
|
Network::SendCommand(address, "print", outputBuffer);
|
||||||
outputBuffer.clear();
|
outputBuffer.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Invalid RCon password sent from %s\n", address.GetCString());
|
Logger::Print("Invalid RCon password sent from %s\n", address.GetCString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("rconRequest", [] (Network::Address address, std::string data)
|
Network::Handle("rconRequest", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
RCon::BackdoorContainer.address = address;
|
RCon::BackdoorContainer.address = address;
|
||||||
RCon::BackdoorContainer.challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
|
RCon::BackdoorContainer.challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
|
||||||
RCon::BackdoorContainer.timestamp = Game::Sys_Milliseconds();
|
RCon::BackdoorContainer.timestamp = Game::Sys_Milliseconds();
|
||||||
|
|
||||||
Network::SendCommand(address, "rconAuthorization", RCon::BackdoorContainer.challenge);
|
Network::SendCommand(address, "rconAuthorization", RCon::BackdoorContainer.challenge);
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("rconExecute", [] (Network::Address address, std::string data)
|
Network::Handle("rconExecute", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
if (address != RCon::BackdoorContainer.address) return; // Invalid IP
|
if (address != RCon::BackdoorContainer.address) return; // Invalid IP
|
||||||
if (!RCon::BackdoorContainer.timestamp || (Game::Sys_Milliseconds() - RCon::BackdoorContainer.timestamp) > (1000 * 10)) return; // Timeout
|
if (!RCon::BackdoorContainer.timestamp || (Game::Sys_Milliseconds() - RCon::BackdoorContainer.timestamp) > (1000 * 10)) return; // Timeout
|
||||||
RCon::BackdoorContainer.timestamp = 0;
|
RCon::BackdoorContainer.timestamp = 0;
|
||||||
|
|
||||||
Proto::RCon::Command command;
|
Proto::RCon::Command command;
|
||||||
command.ParseFromString(data);
|
command.ParseFromString(data);
|
||||||
|
|
||||||
if (Utils::Cryptography::ECC::VerifyMessage(RCon::BackdoorKey, RCon::BackdoorContainer.challenge, command.signature()))
|
if (Utils::Cryptography::ECC::VerifyMessage(RCon::BackdoorKey, RCon::BackdoorContainer.challenge, command.signature()))
|
||||||
{
|
{
|
||||||
RCon::BackdoorContainer.output.clear();
|
RCon::BackdoorContainer.output.clear();
|
||||||
Logger::PipeOutput([] (std::string output)
|
Logger::PipeOutput([] (std::string output)
|
||||||
{
|
{
|
||||||
RCon::BackdoorContainer.output.append(output);
|
RCon::BackdoorContainer.output.append(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::Execute(command.commands(), true);
|
Command::Execute(command.commands(), true);
|
||||||
|
|
||||||
Logger::PipeOutput(nullptr);
|
Logger::PipeOutput(nullptr);
|
||||||
|
|
||||||
Network::SendCommand(address, "print", RCon::BackdoorContainer.output);
|
Network::SendCommand(address, "print", RCon::BackdoorContainer.output);
|
||||||
RCon::BackdoorContainer.output.clear();
|
RCon::BackdoorContainer.output.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RCon::~RCon()
|
RCon::~RCon()
|
||||||
{
|
{
|
||||||
RCon::Password.clear();
|
RCon::Password.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,243 +1,243 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::string Script::ScriptName;
|
std::string Script::ScriptName;
|
||||||
std::vector<int> Script::ScriptHandles;
|
std::vector<int> Script::ScriptHandles;
|
||||||
std::vector<std::string> Script::ScriptNameStack;
|
std::vector<std::string> Script::ScriptNameStack;
|
||||||
unsigned short Script::FunctionName;
|
unsigned short Script::FunctionName;
|
||||||
|
|
||||||
void Script::FunctionError()
|
void Script::FunctionError()
|
||||||
{
|
{
|
||||||
std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
|
std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
|
||||||
|
|
||||||
Game::Scr_ShutdownAllocNode();
|
Game::Scr_ShutdownAllocNode();
|
||||||
|
|
||||||
Logger::Print(23, "\n");
|
Logger::Print(23, "\n");
|
||||||
Logger::Print(23, "******* script compile error *******\n");
|
Logger::Print(23, "******* script compile error *******\n");
|
||||||
Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data());
|
Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data());
|
||||||
Logger::Print(23, "************************************\n");
|
Logger::Print(23, "************************************\n");
|
||||||
|
|
||||||
Logger::Error(5, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data());
|
Logger::Error(5, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Script::StoreFunctionNameStub()
|
void __declspec(naked) Script::StoreFunctionNameStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, [esp - 8h]
|
mov eax, [esp - 8h]
|
||||||
mov Script::FunctionName, ax
|
mov Script::FunctionName, ax
|
||||||
|
|
||||||
sub esp, 0Ch
|
sub esp, 0Ch
|
||||||
push 0
|
push 0
|
||||||
push edi
|
push edi
|
||||||
|
|
||||||
mov eax, 612DB6h
|
mov eax, 612DB6h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::StoreScriptName(const char* name)
|
void Script::StoreScriptName(const char* name)
|
||||||
{
|
{
|
||||||
Script::ScriptNameStack.push_back(Script::ScriptName);
|
Script::ScriptNameStack.push_back(Script::ScriptName);
|
||||||
Script::ScriptName = name;
|
Script::ScriptName = name;
|
||||||
|
|
||||||
if (!Utils::EndsWith(Script::ScriptName, ".gsc"))
|
if (!Utils::String::EndsWith(Script::ScriptName, ".gsc"))
|
||||||
{
|
{
|
||||||
Script::ScriptName.append(".gsc");
|
Script::ScriptName.append(".gsc");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Script::StoreScriptNameStub()
|
void __declspec(naked) Script::StoreScriptNameStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
lea ecx, [esp + 10h]
|
lea ecx, [esp + 10h]
|
||||||
push ecx
|
push ecx
|
||||||
|
|
||||||
call Script::StoreScriptName
|
call Script::StoreScriptName
|
||||||
add esp, 4h
|
add esp, 4h
|
||||||
|
|
||||||
push ebp
|
push ebp
|
||||||
mov ebp, ds:1CDEAA8h
|
mov ebp, ds:1CDEAA8h
|
||||||
mov ecx, 427DC3h
|
mov ecx, 427DC3h
|
||||||
jmp ecx
|
jmp ecx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::RestoreScriptName()
|
void Script::RestoreScriptName()
|
||||||
{
|
{
|
||||||
Script::ScriptName = Script::ScriptNameStack.back();
|
Script::ScriptName = Script::ScriptNameStack.back();
|
||||||
Script::ScriptNameStack.pop_back();
|
Script::ScriptNameStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Script::RestoreScriptNameStub()
|
void __declspec(naked) Script::RestoreScriptNameStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
call Script::RestoreScriptName
|
call Script::RestoreScriptName
|
||||||
|
|
||||||
mov ds:1CDEAA8h, ebp
|
mov ds:1CDEAA8h, ebp
|
||||||
|
|
||||||
mov eax, 427E77h
|
mov eax, 427E77h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::PrintSourcePos(const char* filename, unsigned int offset)
|
void Script::PrintSourcePos(const char* filename, unsigned int offset)
|
||||||
{
|
{
|
||||||
FileSystem::File script(filename);
|
FileSystem::File script(filename);
|
||||||
|
|
||||||
if (script.Exists())
|
if (script.Exists())
|
||||||
{
|
{
|
||||||
std::string buffer = script.GetBuffer();
|
std::string buffer = script.GetBuffer();
|
||||||
Utils::Replace(buffer, "\t", " ");
|
Utils::String::Replace(buffer, "\t", " ");
|
||||||
|
|
||||||
int line = 1;
|
int line = 1;
|
||||||
int lineOffset = 0;
|
int lineOffset = 0;
|
||||||
int inlineOffset = 0;
|
int inlineOffset = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < buffer.size(); ++i)
|
for (unsigned int i = 0; i < buffer.size(); ++i)
|
||||||
{
|
{
|
||||||
// Terminate line
|
// Terminate line
|
||||||
if (i == offset)
|
if (i == offset)
|
||||||
{
|
{
|
||||||
while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0')
|
while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0')
|
||||||
{
|
{
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[i] = '\0';
|
buffer[i] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[i] == '\n')
|
if (buffer[i] == '\n')
|
||||||
{
|
{
|
||||||
++line;
|
++line;
|
||||||
lineOffset = i; // Includes the line break!
|
lineOffset = i; // Includes the line break!
|
||||||
inlineOffset = 0;
|
inlineOffset = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++inlineOffset;
|
++inlineOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print(23, "in file %s, line %d:", filename, line);
|
Logger::Print(23, "in file %s, line %d:", filename, line);
|
||||||
Logger::Print(23, "%s\n", buffer.data() + lineOffset);
|
Logger::Print(23, "%s\n", buffer.data() + lineOffset);
|
||||||
|
|
||||||
for (int i = 0; i < (inlineOffset - 1); ++i)
|
for (int i = 0; i < (inlineOffset - 1); ++i)
|
||||||
{
|
{
|
||||||
Logger::Print(23, " ");
|
Logger::Print(23, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print(23, "*\n");
|
Logger::Print(23, "*\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print(23, "in file %s, offset %d\n", filename, offset);
|
Logger::Print(23, "in file %s, offset %d\n", filename, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::CompileError(unsigned int offset, const char* message, ...)
|
void Script::CompileError(unsigned int offset, const char* message, ...)
|
||||||
{
|
{
|
||||||
char msgbuf[1024] = { 0 };
|
char msgbuf[1024] = { 0 };
|
||||||
va_list v;
|
va_list v;
|
||||||
va_start(v, message);
|
va_start(v, message);
|
||||||
_vsnprintf(msgbuf, sizeof(msgbuf), message, v);
|
_vsnprintf(msgbuf, sizeof(msgbuf), message, v);
|
||||||
va_end(v);
|
va_end(v);
|
||||||
|
|
||||||
Game::Scr_ShutdownAllocNode();
|
Game::Scr_ShutdownAllocNode();
|
||||||
|
|
||||||
Logger::Print(23, "\n");
|
Logger::Print(23, "\n");
|
||||||
Logger::Print(23, "******* script compile error *******\n");
|
Logger::Print(23, "******* script compile error *******\n");
|
||||||
Logger::Print(23, "Error: %s ", msgbuf);
|
Logger::Print(23, "Error: %s ", msgbuf);
|
||||||
Script::PrintSourcePos(Script::ScriptName.data(), offset);
|
Script::PrintSourcePos(Script::ScriptName.data(), offset);
|
||||||
Logger::Print(23, "************************************\n\n");
|
Logger::Print(23, "************************************\n\n");
|
||||||
|
|
||||||
Logger::Error(5, "script compile error\n%s\n%s\n(see console for actual details)\n", msgbuf, Script::ScriptName.data());
|
Logger::Error(5, "script compile error\n%s\n%s\n(see console for actual details)\n", msgbuf, Script::ScriptName.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Script::LoadScriptAndLabel(std::string script, std::string label)
|
int Script::LoadScriptAndLabel(std::string script, std::string label)
|
||||||
{
|
{
|
||||||
Logger::Print("Loading script %s.gsc...\n", script.data());
|
Logger::Print("Loading script %s.gsc...\n", script.data());
|
||||||
|
|
||||||
if (!Game::Scr_LoadScript(script.data()))
|
if (!Game::Scr_LoadScript(script.data()))
|
||||||
{
|
{
|
||||||
Logger::Print("Script %s encountered an error while loading. (doesn't exist?)", script.data());
|
Logger::Print("Script %s encountered an error while loading. (doesn't exist?)", script.data());
|
||||||
Logger::Error(1, (char*)0x70B810, script.data());
|
Logger::Error(1, (char*)0x70B810, script.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Script %s.gsc loaded successfully.\n", script.data());
|
Logger::Print("Script %s.gsc loaded successfully.\n", script.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print("Finding script handle %s::%s...\n", script.data(), label.data());
|
Logger::Print("Finding script handle %s::%s...\n", script.data(), label.data());
|
||||||
int handle = Game::Scr_GetFunctionHandle(script.data(), label.data());
|
int handle = Game::Scr_GetFunctionHandle(script.data(), label.data());
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
Logger::Print("Script handle %s::%s loaded successfully.\n", script.data(), label.data());
|
Logger::Print("Script handle %s::%s loaded successfully.\n", script.data(), label.data());
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Print("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", script.data(), label.data());
|
Logger::Print("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", script.data(), label.data());
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::LoadGameType()
|
void Script::LoadGameType()
|
||||||
{
|
{
|
||||||
for (auto handle : Script::ScriptHandles)
|
for (auto handle : Script::ScriptHandles)
|
||||||
{
|
{
|
||||||
Game::Scr_FreeThread(Game::Scr_ExecThread(handle, 0));
|
Game::Scr_FreeThread(Game::Scr_ExecThread(handle, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::Scr_LoadGameType();
|
Game::Scr_LoadGameType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::LoadGameTypeScript()
|
void Script::LoadGameTypeScript()
|
||||||
{
|
{
|
||||||
Script::ScriptHandles.clear();
|
Script::ScriptHandles.clear();
|
||||||
|
|
||||||
auto list = FileSystem::GetFileList("scripts/", "gsc");
|
auto list = FileSystem::GetFileList("scripts/", "gsc");
|
||||||
|
|
||||||
for (auto file : list)
|
for (auto file : list)
|
||||||
{
|
{
|
||||||
file = "scripts/" + file;
|
file = "scripts/" + file;
|
||||||
|
|
||||||
if (Utils::EndsWith(file, ".gsc"))
|
if (Utils::String::EndsWith(file, ".gsc"))
|
||||||
{
|
{
|
||||||
file = file.substr(0, file.size() - 4);
|
file = file.substr(0, file.size() - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle = Script::LoadScriptAndLabel(file, "init");
|
int handle = Script::LoadScriptAndLabel(file, "init");
|
||||||
|
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
Script::ScriptHandles.push_back(handle);
|
Script::ScriptHandles.push_back(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::GScr_LoadGameTypeScript();
|
Game::GScr_LoadGameTypeScript();
|
||||||
}
|
}
|
||||||
|
|
||||||
Script::Script()
|
Script::Script()
|
||||||
{
|
{
|
||||||
Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).Install()->Quick();
|
||||||
Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
||||||
Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x434260, Script::CompileError, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x434260, Script::CompileError, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).Install()->Quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
Script::~Script()
|
Script::~Script()
|
||||||
{
|
{
|
||||||
Script::ScriptName.clear();
|
Script::ScriptName.clear();
|
||||||
Script::ScriptHandles.clear();
|
Script::ScriptHandles.clear();
|
||||||
Script::ScriptNameStack.clear();
|
Script::ScriptNameStack.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,289 +1,289 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
ServerInfo::Container ServerInfo::PlayerContainer;
|
ServerInfo::Container ServerInfo::PlayerContainer;
|
||||||
|
|
||||||
unsigned int ServerInfo::GetPlayerCount()
|
unsigned int ServerInfo::GetPlayerCount()
|
||||||
{
|
{
|
||||||
return ServerInfo::PlayerContainer.PlayerList.size();
|
return ServerInfo::PlayerContainer.PlayerList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ServerInfo::GetPlayerText(unsigned int index, int column)
|
const char* ServerInfo::GetPlayerText(unsigned int index, int column)
|
||||||
{
|
{
|
||||||
if (index < ServerInfo::PlayerContainer.PlayerList.size())
|
if (index < ServerInfo::PlayerContainer.PlayerList.size())
|
||||||
{
|
{
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return Utils::VA("%d", index);
|
return Utils::String::VA("%d", index);
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return ServerInfo::PlayerContainer.PlayerList[index].Name.data();
|
return ServerInfo::PlayerContainer.PlayerList[index].Name.data();
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return Utils::VA("%d", ServerInfo::PlayerContainer.PlayerList[index].Score);
|
return Utils::String::VA("%d", ServerInfo::PlayerContainer.PlayerList[index].Score);
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return Utils::VA("%d", ServerInfo::PlayerContainer.PlayerList[index].Ping);
|
return Utils::String::VA("%d", ServerInfo::PlayerContainer.PlayerList[index].Ping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerInfo::SelectPlayer(unsigned int index)
|
void ServerInfo::SelectPlayer(unsigned int index)
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.CurrentPlayer = index;
|
ServerInfo::PlayerContainer.CurrentPlayer = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerInfo::ServerStatus()
|
void ServerInfo::ServerStatus()
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
||||||
ServerInfo::PlayerContainer.PlayerList.clear();
|
ServerInfo::PlayerContainer.PlayerList.clear();
|
||||||
|
|
||||||
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
|
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
|
||||||
|
|
||||||
if(info)
|
if(info)
|
||||||
{
|
{
|
||||||
Dvar::Var("uiSi_ServerName").Set(info->Hostname);
|
Dvar::Var("uiSi_ServerName").Set(info->Hostname);
|
||||||
Dvar::Var("uiSi_MaxClients").Set(info->Clients);
|
Dvar::Var("uiSi_MaxClients").Set(info->Clients);
|
||||||
Dvar::Var("uiSi_Version").Set(info->Shortversion);
|
Dvar::Var("uiSi_Version").Set(info->Shortversion);
|
||||||
Dvar::Var("uiSi_isPrivate").Set(info->Password ? "@MENU_YES" : "@MENU_NO");
|
Dvar::Var("uiSi_isPrivate").Set(info->Password ? "@MENU_YES" : "@MENU_NO");
|
||||||
Dvar::Var("uiSi_Hardcore").Set(info->Hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
|
Dvar::Var("uiSi_Hardcore").Set(info->Hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
|
||||||
Dvar::Var("uiSi_KillCam").Set("@MENU_NO");
|
Dvar::Var("uiSi_KillCam").Set("@MENU_NO");
|
||||||
Dvar::Var("uiSi_ffType").Set("@MENU_DISABLED");
|
Dvar::Var("uiSi_ffType").Set("@MENU_DISABLED");
|
||||||
Dvar::Var("uiSi_MapName").Set(info->Mapname);
|
Dvar::Var("uiSi_MapName").Set(info->Mapname);
|
||||||
Dvar::Var("uiSi_MapNameLoc").Set(Game::UI_LocalizeMapName(info->Mapname.data()));
|
Dvar::Var("uiSi_MapNameLoc").Set(Game::UI_LocalizeMapName(info->Mapname.data()));
|
||||||
Dvar::Var("uiSi_GameType").Set(Game::UI_LocalizeGameType(info->Gametype.data()));
|
Dvar::Var("uiSi_GameType").Set(Game::UI_LocalizeGameType(info->Gametype.data()));
|
||||||
Dvar::Var("uiSi_ModName").Set("");
|
Dvar::Var("uiSi_ModName").Set("");
|
||||||
|
|
||||||
if (info->Mod.size() > 5)
|
if (info->Mod.size() > 5)
|
||||||
{
|
{
|
||||||
Dvar::Var("uiSi_ModName").Set(info->Mod.data() + 5);
|
Dvar::Var("uiSi_ModName").Set(info->Mod.data() + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo::PlayerContainer.Target = info->Addr;
|
ServerInfo::PlayerContainer.Target = info->Addr;
|
||||||
Network::SendCommand(ServerInfo::PlayerContainer.Target, "getstatus");
|
Network::SendCommand(ServerInfo::PlayerContainer.Target, "getstatus");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerInfo::DrawScoreboardInfo(void* a1)
|
void ServerInfo::DrawScoreboardInfo(void* a1)
|
||||||
{
|
{
|
||||||
Game::Font* font = Game::R_RegisterFont("fonts/bigfont");
|
Game::Font* font = Game::R_RegisterFont("fonts/bigfont");
|
||||||
void* cxt = Game::UI_GetContext(a1);
|
void* cxt = Game::UI_GetContext(a1);
|
||||||
|
|
||||||
std::string addressText = Network::Address(*Game::connectedHost).GetString();
|
std::string addressText = Network::Address(*Game::connectedHost).GetString();
|
||||||
if (addressText == "0.0.0.0:0" || addressText == "loopback") addressText = "Listen Server";
|
if (addressText == "0.0.0.0:0" || addressText == "loopback") addressText = "Listen Server";
|
||||||
|
|
||||||
// get x positions
|
// get x positions
|
||||||
float fontSize = 0.35f;
|
float fontSize = 0.35f;
|
||||||
float y = (480.0f - Dvar::Var("cg_scoreboardHeight").Get<float>()) * 0.5f;
|
float y = (480.0f - Dvar::Var("cg_scoreboardHeight").Get<float>()) * 0.5f;
|
||||||
y += Dvar::Var("cg_scoreboardHeight").Get<float>() + 6.0f;
|
y += Dvar::Var("cg_scoreboardHeight").Get<float>() + 6.0f;
|
||||||
|
|
||||||
float x = 320.0f - Dvar::Var("cg_scoreboardWidth").Get<float>() * 0.5f;
|
float x = 320.0f - Dvar::Var("cg_scoreboardWidth").Get<float>() * 0.5f;
|
||||||
float x2 = 320.0f + Dvar::Var("cg_scoreboardWidth").Get<float>() * 0.5f;
|
float x2 = 320.0f + Dvar::Var("cg_scoreboardWidth").Get<float>() * 0.5f;
|
||||||
|
|
||||||
Game::UI_DrawText(cxt, reinterpret_cast<const char*>(0x7ED3F8), 0x7FFFFFFF, font, x, y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
|
Game::UI_DrawText(cxt, reinterpret_cast<const char*>(0x7ED3F8), 0x7FFFFFFF, font, x, y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
|
||||||
Game::UI_DrawText(cxt, addressText.data(), 0x7FFFFFFF, font, x2 - Game::UI_TextWidth(addressText.data(), 0, font, fontSize), y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
|
Game::UI_DrawText(cxt, addressText.data(), 0x7FFFFFFF, font, x2 - Game::UI_TextWidth(addressText.data(), 0, font, fontSize), y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) ServerInfo::DrawScoreboardStub()
|
void __declspec(naked) ServerInfo::DrawScoreboardStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push eax
|
push eax
|
||||||
call ServerInfo::DrawScoreboardInfo
|
call ServerInfo::DrawScoreboardInfo
|
||||||
pop eax
|
pop eax
|
||||||
mov ecx, 591B70h
|
mov ecx, 591B70h
|
||||||
jmp ecx
|
jmp ecx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::InfoString ServerInfo::GetInfo()
|
Utils::InfoString ServerInfo::GetInfo()
|
||||||
{
|
{
|
||||||
int maxclientCount = *Game::svs_numclients;
|
int maxclientCount = *Game::svs_numclients;
|
||||||
|
|
||||||
if (!maxclientCount)
|
if (!maxclientCount)
|
||||||
{
|
{
|
||||||
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
||||||
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::InfoString info(Game::Dvar_InfoString_Big(1024));
|
Utils::InfoString info(Game::Dvar_InfoString_Big(1024));
|
||||||
info.Set("gamename", "IW4");
|
info.Set("gamename", "IW4");
|
||||||
info.Set("sv_maxclients", Utils::VA("%i", maxclientCount));
|
info.Set("sv_maxclients", fmt::sprintf("%i", maxclientCount));
|
||||||
info.Set("protocol", Utils::VA("%i", PROTOCOL));
|
info.Set("protocol", fmt::sprintf("%i", PROTOCOL));
|
||||||
info.Set("shortversion", VERSION_STR);
|
info.Set("shortversion", VERSION_STR);
|
||||||
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
||||||
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().empty() ? "0" : "1"));
|
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().empty() ? "0" : "1"));
|
||||||
info.Set("checksum", Utils::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::VA("%u", Game::Sys_Milliseconds()))));
|
info.Set("checksum", fmt::sprintf("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(fmt::sprintf("%u", Game::Sys_Milliseconds()))));
|
||||||
|
|
||||||
// Ensure mapname is set
|
// Ensure mapname is set
|
||||||
if (info.Get("mapname").empty())
|
if (info.Get("mapname").empty())
|
||||||
{
|
{
|
||||||
info.Set("mapname", Dvar::Var("ui_mapname").Get<const char*>());
|
info.Set("mapname", Dvar::Var("ui_mapname").Get<const char*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set matchtype
|
// Set matchtype
|
||||||
// 0 - No match, connecting not possible
|
// 0 - No match, connecting not possible
|
||||||
// 1 - Party, use Steam_JoinLobby to connect
|
// 1 - Party, use Steam_JoinLobby to connect
|
||||||
// 2 - Match, use CL_ConnectFromParty to connect
|
// 2 - Match, use CL_ConnectFromParty to connect
|
||||||
|
|
||||||
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>()) // Party hosting
|
if (Dvar::Var("party_enable").Get<bool>() && Dvar::Var("party_host").Get<bool>()) // Party hosting
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "1");
|
info.Set("matchtype", "1");
|
||||||
}
|
}
|
||||||
else if (Dvar::Var("sv_running").Get<bool>()) // Match hosting
|
else if (Dvar::Var("sv_running").Get<bool>()) // Match hosting
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "2");
|
info.Set("matchtype", "2");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.Set("matchtype", "0");
|
info.Set("matchtype", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo::ServerInfo()
|
ServerInfo::ServerInfo()
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
||||||
ServerInfo::PlayerContainer.PlayerList.clear();
|
ServerInfo::PlayerContainer.PlayerList.clear();
|
||||||
|
|
||||||
// Draw IP and hostname on the scoreboard
|
// Draw IP and hostname on the scoreboard
|
||||||
Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Ignore native getStatus implementation
|
// Ignore native getStatus implementation
|
||||||
Utils::Hook::Nop(0x62654E, 6);
|
Utils::Hook::Nop(0x62654E, 6);
|
||||||
|
|
||||||
// Add uiscript
|
// Add uiscript
|
||||||
UIScript::Add("ServerStatus", ServerInfo::ServerStatus);
|
UIScript::Add("ServerStatus", ServerInfo::ServerStatus);
|
||||||
|
|
||||||
// Add uifeeder
|
// Add uifeeder
|
||||||
UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer);
|
UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer);
|
||||||
|
|
||||||
Network::Handle("getStatus", [] (Network::Address address, std::string data)
|
Network::Handle("getStatus", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
std::string playerList;
|
std::string playerList;
|
||||||
|
|
||||||
Utils::InfoString info = ServerInfo::GetInfo();
|
Utils::InfoString info = ServerInfo::GetInfo();
|
||||||
info.Set("challenge", Utils::ParseChallenge(data));
|
info.Set("challenge", Utils::ParseChallenge(data));
|
||||||
|
|
||||||
for (int i = 0; i < atoi(info.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
for (int i = 0; i < atoi(info.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
||||||
{
|
{
|
||||||
int score = 0;
|
int score = 0;
|
||||||
int ping = 0;
|
int ping = 0;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
if (Dvar::Var("sv_running").Get<bool>())
|
if (Dvar::Var("sv_running").Get<bool>())
|
||||||
{
|
{
|
||||||
if (Game::svs_clients[i].state < 3) continue;
|
if (Game::svs_clients[i].state < 3) continue;
|
||||||
|
|
||||||
score = Game::SV_GameClientNum_Score(i);
|
score = Game::SV_GameClientNum_Score(i);
|
||||||
ping = Game::svs_clients[i].ping;
|
ping = Game::svs_clients[i].ping;
|
||||||
name = Game::svs_clients[i].name;
|
name = Game::svs_clients[i].name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Score and ping are irrelevant
|
// Score and ping are irrelevant
|
||||||
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
|
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
|
||||||
if (!namePtr || !namePtr[0]) continue;
|
if (!namePtr || !namePtr[0]) continue;
|
||||||
|
|
||||||
name = namePtr;
|
name = namePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerList.append(Utils::VA("%i %i \"%s\"\n", score, ping, name.data()));
|
playerList.append(fmt::sprintf("%i %i \"%s\"\n", score, ping, name.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::SendCommand(address, "statusResponse", "\\" + info.Build() + "\n" + playerList + "\n");
|
Network::SendCommand(address, "statusResponse", "\\" + info.Build() + "\n" + playerList + "\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
Network::Handle("statusResponse", [] (Network::Address address, std::string data)
|
Network::Handle("statusResponse", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
if (ServerInfo::PlayerContainer.Target == address)
|
if (ServerInfo::PlayerContainer.Target == address)
|
||||||
{
|
{
|
||||||
Utils::InfoString info(data.substr(0, data.find_first_of("\n")));
|
Utils::InfoString info(data.substr(0, data.find_first_of("\n")));
|
||||||
|
|
||||||
Dvar::Var("uiSi_ServerName").Set(info.Get("sv_hostname"));
|
Dvar::Var("uiSi_ServerName").Set(info.Get("sv_hostname"));
|
||||||
Dvar::Var("uiSi_MaxClients").Set(info.Get("sv_maxclients"));
|
Dvar::Var("uiSi_MaxClients").Set(info.Get("sv_maxclients"));
|
||||||
Dvar::Var("uiSi_Version").Set(info.Get("shortversion"));
|
Dvar::Var("uiSi_Version").Set(info.Get("shortversion"));
|
||||||
Dvar::Var("uiSi_isPrivate").Set(info.Get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES");
|
Dvar::Var("uiSi_isPrivate").Set(info.Get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES");
|
||||||
Dvar::Var("uiSi_Hardcore").Set(info.Get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED");
|
Dvar::Var("uiSi_Hardcore").Set(info.Get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED");
|
||||||
Dvar::Var("uiSi_KillCam").Set(info.Get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES");
|
Dvar::Var("uiSi_KillCam").Set(info.Get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES");
|
||||||
Dvar::Var("uiSi_MapName").Set(info.Get("mapname"));
|
Dvar::Var("uiSi_MapName").Set(info.Get("mapname"));
|
||||||
Dvar::Var("uiSi_MapNameLoc").Set(Game::UI_LocalizeMapName(info.Get("mapname").data()));
|
Dvar::Var("uiSi_MapNameLoc").Set(Game::UI_LocalizeMapName(info.Get("mapname").data()));
|
||||||
Dvar::Var("uiSi_GameType").Set(Game::UI_LocalizeGameType(info.Get("g_gametype").data()));
|
Dvar::Var("uiSi_GameType").Set(Game::UI_LocalizeGameType(info.Get("g_gametype").data()));
|
||||||
Dvar::Var("uiSi_ModName").Set("");
|
Dvar::Var("uiSi_ModName").Set("");
|
||||||
|
|
||||||
switch (atoi(info.Get("scr_team_fftype").data()))
|
switch (atoi(info.Get("scr_team_fftype").data()))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
Dvar::Var("uiSi_ffType").Set("@MENU_DISABLED");
|
Dvar::Var("uiSi_ffType").Set("@MENU_DISABLED");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
Dvar::Var("uiSi_ffType").Set("@MENU_ENABLED");
|
Dvar::Var("uiSi_ffType").Set("@MENU_ENABLED");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
Dvar::Var("uiSi_ffType").Set("@MPUI_RULES_REFLECT");
|
Dvar::Var("uiSi_ffType").Set("@MPUI_RULES_REFLECT");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
Dvar::Var("uiSi_ffType").Set("@MPUI_RULES_SHARED");
|
Dvar::Var("uiSi_ffType").Set("@MPUI_RULES_SHARED");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.Get("fs_game").size() > 5)
|
if (info.Get("fs_game").size() > 5)
|
||||||
{
|
{
|
||||||
Dvar::Var("uiSi_ModName").Set(info.Get("fs_game").data() + 5);
|
Dvar::Var("uiSi_ModName").Set(info.Get("fs_game").data() + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lines = Utils::Explode(data, '\n');
|
auto lines = Utils::String::Explode(data, '\n');
|
||||||
|
|
||||||
if (lines.size() <= 1) return;
|
if (lines.size() <= 1) return;
|
||||||
|
|
||||||
for (unsigned int i = 1; i < lines.size(); ++i)
|
for (unsigned int i = 1; i < lines.size(); ++i)
|
||||||
{
|
{
|
||||||
ServerInfo::Container::Player player;
|
ServerInfo::Container::Player player;
|
||||||
|
|
||||||
std::string currentData = lines[i];
|
std::string currentData = lines[i];
|
||||||
|
|
||||||
if (currentData.size() < 3) continue;
|
if (currentData.size() < 3) continue;
|
||||||
|
|
||||||
// Insert score
|
// Insert score
|
||||||
player.Score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
|
player.Score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
|
||||||
|
|
||||||
// Remove score
|
// Remove score
|
||||||
currentData = currentData.substr(currentData.find_first_of(" ") + 1);
|
currentData = currentData.substr(currentData.find_first_of(" ") + 1);
|
||||||
|
|
||||||
// Insert ping
|
// Insert ping
|
||||||
player.Ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
|
player.Ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
|
||||||
|
|
||||||
// Remove ping
|
// Remove ping
|
||||||
currentData = currentData.substr(currentData.find_first_of(" ") + 1);
|
currentData = currentData.substr(currentData.find_first_of(" ") + 1);
|
||||||
|
|
||||||
if (currentData[0] == '\"')
|
if (currentData[0] == '\"')
|
||||||
{
|
{
|
||||||
currentData = currentData.substr(1);
|
currentData = currentData.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentData[currentData.size() - 1] == '\"')
|
if (currentData[currentData.size() - 1] == '\"')
|
||||||
{
|
{
|
||||||
currentData.pop_back();
|
currentData.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
player.Name = currentData;
|
player.Name = currentData;
|
||||||
|
|
||||||
ServerInfo::PlayerContainer.PlayerList.push_back(player);
|
ServerInfo::PlayerContainer.PlayerList.push_back(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo::~ServerInfo()
|
ServerInfo::~ServerInfo()
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.PlayerList.clear();
|
ServerInfo::PlayerContainer.PlayerList.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,213 +1,213 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Utils::Memory::Allocator StructuredData::MemAllocator;
|
Utils::Memory::Allocator StructuredData::MemAllocator;
|
||||||
|
|
||||||
const char* StructuredData::EnumTranslation[ENUM_MAX] =
|
const char* StructuredData::EnumTranslation[ENUM_MAX] =
|
||||||
{
|
{
|
||||||
"features",
|
"features",
|
||||||
"weapons",
|
"weapons",
|
||||||
"attachements",
|
"attachements",
|
||||||
"challenges",
|
"challenges",
|
||||||
"camos",
|
"camos",
|
||||||
"perks",
|
"perks",
|
||||||
"killstreaks",
|
"killstreaks",
|
||||||
"accolades",
|
"accolades",
|
||||||
"cardicons",
|
"cardicons",
|
||||||
"cardtitles",
|
"cardtitles",
|
||||||
"cardnameplates",
|
"cardnameplates",
|
||||||
"teams",
|
"teams",
|
||||||
"gametypes"
|
"gametypes"
|
||||||
};
|
};
|
||||||
|
|
||||||
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
|
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
|
||||||
{
|
{
|
||||||
if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return;
|
if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return;
|
||||||
|
|
||||||
Game::StructuredDataEnum* dataEnum = &data->enums[type];
|
Game::StructuredDataEnum* dataEnum = &data->enums[type];
|
||||||
|
|
||||||
// Find last index so we can add our offset to it.
|
// Find last index so we can add our offset to it.
|
||||||
// This whole procedure is potentially unsafe.
|
// This whole procedure is potentially unsafe.
|
||||||
// If any index changes, everything gets shifted and the stats are fucked.
|
// If any index changes, everything gets shifted and the stats are fucked.
|
||||||
int lastIndex = 0;
|
int lastIndex = 0;
|
||||||
for (int i = 0; i < dataEnum->numIndices; ++i)
|
for (int i = 0; i < dataEnum->numIndices; ++i)
|
||||||
{
|
{
|
||||||
if (dataEnum->indices[i].index > lastIndex)
|
if (dataEnum->indices[i].index > lastIndex)
|
||||||
{
|
{
|
||||||
lastIndex = dataEnum->indices[i].index;
|
lastIndex = dataEnum->indices[i].index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate new count
|
// Calculate new count
|
||||||
unsigned int indexCount = dataEnum->numIndices + entries.size();
|
unsigned int indexCount = dataEnum->numIndices + entries.size();
|
||||||
|
|
||||||
// Allocate new entries
|
// Allocate new entries
|
||||||
Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(indexCount);
|
Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(indexCount);
|
||||||
std::memcpy(indices, dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices);
|
std::memcpy(indices, dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < entries.size(); ++i)
|
for (unsigned int i = 0; i < entries.size(); ++i)
|
||||||
{
|
{
|
||||||
unsigned int pos = 0;
|
unsigned int pos = 0;
|
||||||
|
|
||||||
for (; pos < (dataEnum->numIndices + i); pos++)
|
for (; pos < (dataEnum->numIndices + i); pos++)
|
||||||
{
|
{
|
||||||
if (indices[pos].key == entries[i])
|
if (indices[pos].key == entries[i])
|
||||||
{
|
{
|
||||||
Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].data());
|
Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].data());
|
||||||
}
|
}
|
||||||
|
|
||||||
// We found our position
|
// We found our position
|
||||||
if (entries[i] < indices[pos].key)
|
if (entries[i] < indices[pos].key)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO directly shift the data using memmove
|
// TODO directly shift the data using memmove
|
||||||
for (unsigned int j = dataEnum->numIndices + i; j > pos && j < indexCount; j--)
|
for (unsigned int j = dataEnum->numIndices + i; j > pos && j < indexCount; j--)
|
||||||
{
|
{
|
||||||
std::memcpy(&indices[j], &indices[j - 1], sizeof(Game::StructuredDataEnumEntry));
|
std::memcpy(&indices[j], &indices[j - 1], sizeof(Game::StructuredDataEnumEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
indices[pos].index = i + lastIndex;
|
indices[pos].index = i + lastIndex;
|
||||||
indices[pos].key = StructuredData::MemAllocator.DuplicateString(entries[i]);
|
indices[pos].key = StructuredData::MemAllocator.DuplicateString(entries[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply our patches
|
// Apply our patches
|
||||||
dataEnum->numIndices = indexCount;
|
dataEnum->numIndices = indexCount;
|
||||||
dataEnum->indices = indices;
|
dataEnum->indices = indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
StructuredData::StructuredData()
|
StructuredData::StructuredData()
|
||||||
{
|
{
|
||||||
// Only execute this when building zones
|
// Only execute this when building zones
|
||||||
if (!ZoneBuilder::IsEnabled()) return;
|
if (!ZoneBuilder::IsEnabled()) return;
|
||||||
|
|
||||||
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* restrict)
|
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* restrict)
|
||||||
{
|
{
|
||||||
// Only intercept playerdatadef loading
|
// Only intercept playerdatadef loading
|
||||||
if (filename != "mp/playerdata.def" || type != Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF) return;
|
if (filename != "mp/playerdata.def" || type != Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF) return;
|
||||||
|
|
||||||
// Store asset
|
// Store asset
|
||||||
Game::StructuredDataDefSet* data = asset.structuredData;
|
Game::StructuredDataDefSet* data = asset.structuredData;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
if (data->count != 1)
|
if (data->count != 1)
|
||||||
{
|
{
|
||||||
Logger::Error("PlayerDataDefSet contains more than 1 definition!");
|
Logger::Error("PlayerDataDefSet contains more than 1 definition!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->data[0].version != 155)
|
if (data->data[0].version != 155)
|
||||||
{
|
{
|
||||||
Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!");
|
Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
|
std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
|
||||||
|
|
||||||
// First check if all versions are present
|
// First check if all versions are present
|
||||||
for (int i = 156;; ++i)
|
for (int i = 156;; ++i)
|
||||||
{
|
{
|
||||||
FileSystem::File definition(Utils::VA("%s/%d.json", filename.data(), i));
|
FileSystem::File definition(fmt::sprintf("%s/%d.json", filename.data(), i));
|
||||||
if (!definition.Exists()) break;
|
if (!definition.Exists()) break;
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> enumContainer;
|
std::vector<std::vector<std::string>> enumContainer;
|
||||||
|
|
||||||
std::string errors;
|
std::string errors;
|
||||||
json11::Json defData = json11::Json::parse(definition.GetBuffer(), errors);
|
json11::Json defData = json11::Json::parse(definition.GetBuffer(), errors);
|
||||||
|
|
||||||
if (!errors.empty())
|
if (!errors.empty())
|
||||||
{
|
{
|
||||||
Logger::Error("Parsing patch file '%s' for PlayerDataDef version %d failed: %s", definition.GetName().data(), i, errors.data());
|
Logger::Error("Parsing patch file '%s' for PlayerDataDef version %d failed: %s", definition.GetName().data(), i, errors.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defData.is_object())
|
if (!defData.is_object())
|
||||||
{
|
{
|
||||||
Logger::Error("PlayerDataDef patch for version %d is invalid!", i);
|
Logger::Error("PlayerDataDef patch for version %d is invalid!", i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
|
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
|
||||||
{
|
{
|
||||||
auto enumData = defData[StructuredData::EnumTranslation[pType]];
|
auto enumData = defData[StructuredData::EnumTranslation[pType]];
|
||||||
|
|
||||||
std::vector<std::string> entryData;
|
std::vector<std::string> entryData;
|
||||||
|
|
||||||
if (enumData.is_array())
|
if (enumData.is_array())
|
||||||
{
|
{
|
||||||
for (auto rawEntry : enumData.array_items())
|
for (auto rawEntry : enumData.array_items())
|
||||||
{
|
{
|
||||||
if (rawEntry.is_string())
|
if (rawEntry.is_string())
|
||||||
{
|
{
|
||||||
entryData.push_back(rawEntry.string_value());
|
entryData.push_back(rawEntry.string_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enumContainer.push_back(entryData);
|
enumContainer.push_back(entryData);
|
||||||
}
|
}
|
||||||
|
|
||||||
patchDefinitions[i] = enumContainer;
|
patchDefinitions[i] = enumContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to patch
|
// Nothing to patch
|
||||||
if (patchDefinitions.empty()) return;
|
if (patchDefinitions.empty()) return;
|
||||||
|
|
||||||
// Reallocate the definition
|
// Reallocate the definition
|
||||||
Game::StructuredDataDef* newData = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size());
|
Game::StructuredDataDef* newData = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size());
|
||||||
std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count);
|
std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count);
|
||||||
|
|
||||||
// Prepare the buffers
|
// Prepare the buffers
|
||||||
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
|
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
|
||||||
{
|
{
|
||||||
std::memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef);
|
std::memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef);
|
||||||
newData[i].version = (patchDefinitions.size() - i) + 155;
|
newData[i].version = (patchDefinitions.size() - i) + 155;
|
||||||
|
|
||||||
// Reallocate the enum array
|
// Reallocate the enum array
|
||||||
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataEnum>(data->data->numEnums);
|
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.AllocateArray<Game::StructuredDataEnum>(data->data->numEnums);
|
||||||
std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums);
|
std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums);
|
||||||
newData[i].enums = newEnums;
|
newData[i].enums = newEnums;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply new data
|
// Apply new data
|
||||||
data->data = newData;
|
data->data = newData;
|
||||||
data->count += patchDefinitions.size();
|
data->count += patchDefinitions.size();
|
||||||
|
|
||||||
// Patch the definition
|
// Patch the definition
|
||||||
for (int i = 0; i < data->count; ++i)
|
for (int i = 0; i < data->count; ++i)
|
||||||
{
|
{
|
||||||
// No need to patch version 155
|
// No need to patch version 155
|
||||||
if (newData[i].version == 155) continue;
|
if (newData[i].version == 155) continue;
|
||||||
|
|
||||||
if(patchDefinitions.find(newData[i].version) != patchDefinitions.end())
|
if(patchDefinitions.find(newData[i].version) != patchDefinitions.end())
|
||||||
{
|
{
|
||||||
auto patchData = patchDefinitions[newData[i].version];
|
auto patchData = patchDefinitions[newData[i].version];
|
||||||
|
|
||||||
// Invalid patch data
|
// Invalid patch data
|
||||||
if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX)
|
if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX)
|
||||||
{
|
{
|
||||||
Logger::Error("PlayerDataDef patch for version %d wasn't parsed correctly!", newData[i].version);
|
Logger::Error("PlayerDataDef patch for version %d wasn't parsed correctly!", newData[i].version);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the patch data
|
// Apply the patch data
|
||||||
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
|
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
|
||||||
{
|
{
|
||||||
if (!patchData[pType].empty())
|
if (!patchData[pType].empty())
|
||||||
{
|
{
|
||||||
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
|
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
StructuredData::~StructuredData()
|
StructuredData::~StructuredData()
|
||||||
{
|
{
|
||||||
StructuredData::MemAllocator.Free();
|
StructuredData::MemAllocator.Free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,376 +1,376 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Theatre::Container Theatre::DemoContainer;
|
Theatre::Container Theatre::DemoContainer;
|
||||||
|
|
||||||
char Theatre::BaselineSnapshot[131072] = { 0 };
|
char Theatre::BaselineSnapshot[131072] = { 0 };
|
||||||
int Theatre::BaselineSnapshotMsgLen;
|
int Theatre::BaselineSnapshotMsgLen;
|
||||||
int Theatre::BaselineSnapshotMsgOff;
|
int Theatre::BaselineSnapshotMsgOff;
|
||||||
|
|
||||||
void Theatre::GamestateWriteStub(Game::msg_t* msg, char byte)
|
void Theatre::GamestateWriteStub(Game::msg_t* msg, char byte)
|
||||||
{
|
{
|
||||||
Game::MSG_WriteLong(msg, 0);
|
Game::MSG_WriteLong(msg, 0);
|
||||||
Game::MSG_WriteByte(msg, byte);
|
Game::MSG_WriteByte(msg, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::RecordGamestateStub()
|
void Theatre::RecordGamestateStub()
|
||||||
{
|
{
|
||||||
int sequence = (*Game::serverMessageSequence - 1);
|
int sequence = (*Game::serverMessageSequence - 1);
|
||||||
Game::FS_Write(&sequence, 4, *Game::demoFile);
|
Game::FS_Write(&sequence, 4, *Game::demoFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::StoreBaseline(PBYTE snapshotMsg)
|
void Theatre::StoreBaseline(PBYTE snapshotMsg)
|
||||||
{
|
{
|
||||||
// Store offset and length
|
// Store offset and length
|
||||||
Theatre::BaselineSnapshotMsgLen = *reinterpret_cast<int*>(snapshotMsg + 20);
|
Theatre::BaselineSnapshotMsgLen = *reinterpret_cast<int*>(snapshotMsg + 20);
|
||||||
Theatre::BaselineSnapshotMsgOff = *reinterpret_cast<int*>(snapshotMsg + 28) - 7;
|
Theatre::BaselineSnapshotMsgOff = *reinterpret_cast<int*>(snapshotMsg + 28) - 7;
|
||||||
|
|
||||||
// Copy to our snapshot buffer
|
// Copy to our snapshot buffer
|
||||||
std::memcpy(Theatre::BaselineSnapshot, *reinterpret_cast<DWORD**>(snapshotMsg + 8), *reinterpret_cast<DWORD*>(snapshotMsg + 20));
|
std::memcpy(Theatre::BaselineSnapshot, *reinterpret_cast<DWORD**>(snapshotMsg + 8), *reinterpret_cast<DWORD*>(snapshotMsg + 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::BaselineStoreStub()
|
void __declspec(naked) Theatre::BaselineStoreStub()
|
||||||
{
|
{
|
||||||
_asm
|
_asm
|
||||||
{
|
{
|
||||||
push edi
|
push edi
|
||||||
call Theatre::StoreBaseline
|
call Theatre::StoreBaseline
|
||||||
pop edi
|
pop edi
|
||||||
|
|
||||||
mov edx, 5ABEF5h
|
mov edx, 5ABEF5h
|
||||||
jmp edx
|
jmp edx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::WriteBaseline()
|
void Theatre::WriteBaseline()
|
||||||
{
|
{
|
||||||
static char bufData[131072];
|
static char bufData[131072];
|
||||||
static char cmpData[131072];
|
static char cmpData[131072];
|
||||||
|
|
||||||
Game::msg_t buf;
|
Game::msg_t buf;
|
||||||
|
|
||||||
Game::MSG_Init(&buf, bufData, 131072);
|
Game::MSG_Init(&buf, bufData, 131072);
|
||||||
Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff);
|
Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff);
|
||||||
Game::MSG_WriteByte(&buf, 6);
|
Game::MSG_WriteByte(&buf, 6);
|
||||||
|
|
||||||
int compressedSize = Game::MSG_WriteBitsCompress(false, buf.data, cmpData, buf.cursize);
|
int compressedSize = Game::MSG_WriteBitsCompress(false, buf.data, cmpData, buf.cursize);
|
||||||
int fileCompressedSize = compressedSize + 4;
|
int fileCompressedSize = compressedSize + 4;
|
||||||
|
|
||||||
int byte8 = 8;
|
int byte8 = 8;
|
||||||
char byte0 = 0;
|
char byte0 = 0;
|
||||||
|
|
||||||
Game::FS_Write(&byte0, 1, *Game::demoFile);
|
Game::FS_Write(&byte0, 1, *Game::demoFile);
|
||||||
Game::FS_Write(Game::serverMessageSequence, 4, *Game::demoFile);
|
Game::FS_Write(Game::serverMessageSequence, 4, *Game::demoFile);
|
||||||
Game::FS_Write(&fileCompressedSize, 4, *Game::demoFile);
|
Game::FS_Write(&fileCompressedSize, 4, *Game::demoFile);
|
||||||
Game::FS_Write(&byte8, 4, *Game::demoFile);
|
Game::FS_Write(&byte8, 4, *Game::demoFile);
|
||||||
|
|
||||||
for (int i = 0; i < compressedSize; i += 1024)
|
for (int i = 0; i < compressedSize; i += 1024)
|
||||||
{
|
{
|
||||||
int size = min(compressedSize - i, 1024);
|
int size = std::min(compressedSize - i, 1024);
|
||||||
|
|
||||||
if (i + size >= sizeof(cmpData))
|
if (i + size >= sizeof(cmpData))
|
||||||
{
|
{
|
||||||
Logger::Print("Error: Writing compressed demo baseline exceeded buffer\n");
|
Logger::Print("Error: Writing compressed demo baseline exceeded buffer\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::FS_Write(&cmpData[i], size, *Game::demoFile);
|
Game::FS_Write(&cmpData[i], size, *Game::demoFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::BaselineToFileStub()
|
void __declspec(naked) Theatre::BaselineToFileStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
call Theatre::WriteBaseline
|
call Theatre::WriteBaseline
|
||||||
|
|
||||||
// Restore overwritten operation
|
// Restore overwritten operation
|
||||||
mov ecx, 0A5E9C4h
|
mov ecx, 0A5E9C4h
|
||||||
mov [ecx], 0
|
mov [ecx], 0
|
||||||
|
|
||||||
// Return to original code
|
// Return to original code
|
||||||
mov ecx, 5A863Ah
|
mov ecx, 5A863Ah
|
||||||
jmp ecx
|
jmp ecx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::AdjustTimeDeltaStub()
|
void __declspec(naked) Theatre::AdjustTimeDeltaStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, Game::demoPlaying
|
mov eax, Game::demoPlaying
|
||||||
mov eax, [eax]
|
mov eax, [eax]
|
||||||
test al, al
|
test al, al
|
||||||
jz continue
|
jz continue
|
||||||
|
|
||||||
// delta doesn't drift for demos
|
// delta doesn't drift for demos
|
||||||
retn
|
retn
|
||||||
|
|
||||||
continue:
|
continue:
|
||||||
mov eax, 5A1AD0h
|
mov eax, 5A1AD0h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::ServerTimedOutStub()
|
void __declspec(naked) Theatre::ServerTimedOutStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, Game::demoPlaying
|
mov eax, Game::demoPlaying
|
||||||
mov eax, [eax]
|
mov eax, [eax]
|
||||||
test al, al
|
test al, al
|
||||||
jz continue
|
jz continue
|
||||||
|
|
||||||
mov eax, 5A8E70h
|
mov eax, 5A8E70h
|
||||||
jmp eax
|
jmp eax
|
||||||
|
|
||||||
continue:
|
continue:
|
||||||
mov eax, 0B2BB90h
|
mov eax, 0B2BB90h
|
||||||
mov esi, 5A8E08h
|
mov esi, 5A8E08h
|
||||||
jmp esi
|
jmp esi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::UISetActiveMenuStub()
|
void __declspec(naked) Theatre::UISetActiveMenuStub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, Game::demoPlaying
|
mov eax, Game::demoPlaying
|
||||||
mov eax, [eax]
|
mov eax, [eax]
|
||||||
test al, al
|
test al, al
|
||||||
jz continue
|
jz continue
|
||||||
|
|
||||||
mov eax, 4CB49Ch
|
mov eax, 4CB49Ch
|
||||||
jmp eax
|
jmp eax
|
||||||
|
|
||||||
continue:
|
continue:
|
||||||
mov ecx, [esp + 10h]
|
mov ecx, [esp + 10h]
|
||||||
push 10h
|
push 10h
|
||||||
push ecx
|
push ecx
|
||||||
mov eax, 4CB3F6h
|
mov eax, 4CB3F6h
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::RecordStub(int channel, char* message, char* file)
|
void Theatre::RecordStub(int channel, char* message, char* file)
|
||||||
{
|
{
|
||||||
Game::Com_Printf(channel, message, file);
|
Game::Com_Printf(channel, message, file);
|
||||||
|
|
||||||
Theatre::DemoContainer.CurrentInfo.Name = file;
|
Theatre::DemoContainer.CurrentInfo.Name = file;
|
||||||
Theatre::DemoContainer.CurrentInfo.Mapname = Dvar::Var("mapname").Get<const char*>();
|
Theatre::DemoContainer.CurrentInfo.Mapname = Dvar::Var("mapname").Get<const char*>();
|
||||||
Theatre::DemoContainer.CurrentInfo.Gametype = Dvar::Var("g_gametype").Get<const char*>();
|
Theatre::DemoContainer.CurrentInfo.Gametype = Dvar::Var("g_gametype").Get<const char*>();
|
||||||
Theatre::DemoContainer.CurrentInfo.Author = Steam::SteamFriends()->GetPersonaName();
|
Theatre::DemoContainer.CurrentInfo.Author = Steam::SteamFriends()->GetPersonaName();
|
||||||
Theatre::DemoContainer.CurrentInfo.Length = Game::Sys_Milliseconds();
|
Theatre::DemoContainer.CurrentInfo.Length = Game::Sys_Milliseconds();
|
||||||
std::time(&Theatre::DemoContainer.CurrentInfo.TimeStamp);
|
std::time(&Theatre::DemoContainer.CurrentInfo.TimeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::StopRecordStub(int channel, char* message)
|
void Theatre::StopRecordStub(int channel, char* message)
|
||||||
{
|
{
|
||||||
Game::Com_Printf(channel, message);
|
Game::Com_Printf(channel, message);
|
||||||
|
|
||||||
// Store correct length
|
// Store correct length
|
||||||
Theatre::DemoContainer.CurrentInfo.Length = Game::Sys_Milliseconds() - Theatre::DemoContainer.CurrentInfo.Length;
|
Theatre::DemoContainer.CurrentInfo.Length = Game::Sys_Milliseconds() - Theatre::DemoContainer.CurrentInfo.Length;
|
||||||
|
|
||||||
// Write metadata
|
// Write metadata
|
||||||
FileSystem::FileWriter meta(Utils::VA("%s.json", Theatre::DemoContainer.CurrentInfo.Name.data()));
|
FileSystem::FileWriter meta(fmt::sprintf("%s.json", Theatre::DemoContainer.CurrentInfo.Name.data()));
|
||||||
meta.Write(json11::Json(Theatre::DemoContainer.CurrentInfo).dump());
|
meta.Write(json11::Json(Theatre::DemoContainer.CurrentInfo).dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::LoadDemos()
|
void Theatre::LoadDemos()
|
||||||
{
|
{
|
||||||
Theatre::DemoContainer.CurrentSelection = 0;
|
Theatre::DemoContainer.CurrentSelection = 0;
|
||||||
Theatre::DemoContainer.Demos.clear();
|
Theatre::DemoContainer.Demos.clear();
|
||||||
|
|
||||||
auto demos = FileSystem::GetFileList("demos/", "dm_13");
|
auto demos = FileSystem::GetFileList("demos/", "dm_13");
|
||||||
|
|
||||||
for (auto demo : demos)
|
for (auto demo : demos)
|
||||||
{
|
{
|
||||||
FileSystem::File meta(Utils::VA("demos/%s.json", demo.data()));
|
FileSystem::File meta(fmt::sprintf("demos/%s.json", demo.data()));
|
||||||
|
|
||||||
if (meta.Exists())
|
if (meta.Exists())
|
||||||
{
|
{
|
||||||
std::string error;
|
std::string error;
|
||||||
json11::Json metaObject = json11::Json::parse(meta.GetBuffer(), error);
|
json11::Json metaObject = json11::Json::parse(meta.GetBuffer(), error);
|
||||||
|
|
||||||
if (metaObject.is_object())
|
if (metaObject.is_object())
|
||||||
{
|
{
|
||||||
Theatre::Container::DemoInfo info;
|
Theatre::Container::DemoInfo info;
|
||||||
|
|
||||||
info.Name = demo.substr(0, demo.find_last_of("."));
|
info.Name = demo.substr(0, demo.find_last_of("."));
|
||||||
info.Author = metaObject["author"].string_value();
|
info.Author = metaObject["author"].string_value();
|
||||||
info.Gametype = metaObject["gametype"].string_value();
|
info.Gametype = metaObject["gametype"].string_value();
|
||||||
info.Mapname = metaObject["mapname"].string_value();
|
info.Mapname = metaObject["mapname"].string_value();
|
||||||
info.Length = (int)metaObject["length"].number_value();
|
info.Length = (int)metaObject["length"].number_value();
|
||||||
info.TimeStamp = _atoi64(metaObject["timestamp"].string_value().data());
|
info.TimeStamp = _atoi64(metaObject["timestamp"].string_value().data());
|
||||||
|
|
||||||
Theatre::DemoContainer.Demos.push_back(info);
|
Theatre::DemoContainer.Demos.push_back(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse, latest demo first!
|
// Reverse, latest demo first!
|
||||||
std::reverse(Theatre::DemoContainer.Demos.begin(), Theatre::DemoContainer.Demos.end());
|
std::reverse(Theatre::DemoContainer.Demos.begin(), Theatre::DemoContainer.Demos.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::DeleteDemo()
|
void Theatre::DeleteDemo()
|
||||||
{
|
{
|
||||||
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
||||||
{
|
{
|
||||||
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection];
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection];
|
||||||
|
|
||||||
Logger::Print("Deleting demo %s...\n", info.Name.data());
|
Logger::Print("Deleting demo %s...\n", info.Name.data());
|
||||||
|
|
||||||
FileSystem::DeleteFile("demos", info.Name + ".dm_13");
|
FileSystem::DeleteFile("demos", info.Name + ".dm_13");
|
||||||
FileSystem::DeleteFile("demos", info.Name + ".dm_13.json");
|
FileSystem::DeleteFile("demos", info.Name + ".dm_13.json");
|
||||||
|
|
||||||
// Reset our ui_demo_* dvars here, because the theater menu needs it.
|
// Reset our ui_demo_* dvars here, because the theater menu needs it.
|
||||||
Dvar::Var("ui_demo_mapname").Set("");
|
Dvar::Var("ui_demo_mapname").Set("");
|
||||||
Dvar::Var("ui_demo_mapname_localized").Set("");
|
Dvar::Var("ui_demo_mapname_localized").Set("");
|
||||||
Dvar::Var("ui_demo_gametype").Set("");
|
Dvar::Var("ui_demo_gametype").Set("");
|
||||||
Dvar::Var("ui_demo_length").Set("");
|
Dvar::Var("ui_demo_length").Set("");
|
||||||
Dvar::Var("ui_demo_author").Set("");
|
Dvar::Var("ui_demo_author").Set("");
|
||||||
Dvar::Var("ui_demo_date").Set("");
|
Dvar::Var("ui_demo_date").Set("");
|
||||||
|
|
||||||
// Reload demos
|
// Reload demos
|
||||||
Theatre::LoadDemos();
|
Theatre::LoadDemos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::PlayDemo()
|
void Theatre::PlayDemo()
|
||||||
{
|
{
|
||||||
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
||||||
{
|
{
|
||||||
Command::Execute(Utils::VA("demo %s", Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection].Name.data()), true);
|
Command::Execute(fmt::sprintf("demo %s", Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection].Name.data()), true);
|
||||||
Command::Execute("demoback", false);
|
Command::Execute("demoback", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Theatre::GetDemoCount()
|
unsigned int Theatre::GetDemoCount()
|
||||||
{
|
{
|
||||||
return Theatre::DemoContainer.Demos.size();
|
return Theatre::DemoContainer.Demos.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Omit column here
|
// Omit column here
|
||||||
const char* Theatre::GetDemoText(unsigned int item, int column)
|
const char* Theatre::GetDemoText(unsigned int item, int column)
|
||||||
{
|
{
|
||||||
if (item < Theatre::DemoContainer.Demos.size())
|
if (item < Theatre::DemoContainer.Demos.size())
|
||||||
{
|
{
|
||||||
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[item];
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[item];
|
||||||
|
|
||||||
return Utils::VA("%s on %s", Game::UI_LocalizeGameType(info.Gametype.data()), Game::UI_LocalizeMapName(info.Mapname.data()));
|
return Utils::String::VA("%s on %s", Game::UI_LocalizeGameType(info.Gametype.data()), Game::UI_LocalizeMapName(info.Mapname.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::SelectDemo(unsigned int index)
|
void Theatre::SelectDemo(unsigned int index)
|
||||||
{
|
{
|
||||||
if (index < Theatre::DemoContainer.Demos.size())
|
if (index < Theatre::DemoContainer.Demos.size())
|
||||||
{
|
{
|
||||||
Theatre::DemoContainer.CurrentSelection = index;
|
Theatre::DemoContainer.CurrentSelection = index;
|
||||||
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[index];
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[index];
|
||||||
|
|
||||||
Dvar::Var("ui_demo_mapname").Set(info.Mapname);
|
Dvar::Var("ui_demo_mapname").Set(info.Mapname);
|
||||||
Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data()));
|
Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data()));
|
||||||
Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data()));
|
Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data()));
|
||||||
Dvar::Var("ui_demo_length").Set(Utils::FormatTimeSpan(info.Length));
|
Dvar::Var("ui_demo_length").Set(Utils::String::FormatTimeSpan(info.Length));
|
||||||
Dvar::Var("ui_demo_author").Set(info.Author);
|
Dvar::Var("ui_demo_author").Set(info.Author);
|
||||||
Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp)));
|
Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Theatre::InitCGameStub()
|
uint32_t Theatre::InitCGameStub()
|
||||||
{
|
{
|
||||||
if (Dvar::Var("cl_autoRecord").Get<bool>() && !*Game::demoPlaying)
|
if (Dvar::Var("cl_autoRecord").Get<bool>() && !*Game::demoPlaying)
|
||||||
{
|
{
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
std::vector<std::string> demos = FileSystem::GetFileList("demos/", "dm_13");
|
std::vector<std::string> demos = FileSystem::GetFileList("demos/", "dm_13");
|
||||||
|
|
||||||
for (auto demo : demos)
|
for (auto demo : demos)
|
||||||
{
|
{
|
||||||
if (Utils::StartsWith(demo, "auto_"))
|
if (Utils::String::StartsWith(demo, "auto_"))
|
||||||
{
|
{
|
||||||
files.push_back(demo);
|
files.push_back(demo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int numDel = files.size() - Dvar::Var("cl_demosKeep").Get<int>();
|
int numDel = files.size() - Dvar::Var("cl_demosKeep").Get<int>();
|
||||||
|
|
||||||
for (int i = 0; i < numDel; ++i)
|
for (int i = 0; i < numDel; ++i)
|
||||||
{
|
{
|
||||||
Logger::Print("Deleting old demo %s\n", files[i].data());
|
Logger::Print("Deleting old demo %s\n", files[i].data());
|
||||||
FileSystem::DeleteFile("demos", files[i].data());
|
FileSystem::DeleteFile("demos", files[i].data());
|
||||||
FileSystem::DeleteFile("demos", Utils::VA("%s.json", files[i].data()));
|
FileSystem::DeleteFile("demos", fmt::sprintf("%s.json", files[i].data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Execute(Utils::VA("record auto_%I64d", time(0)), true);
|
Command::Execute(fmt::sprintf("record auto_%I64d", time(0)), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::Hook::Call<DWORD()>(0x42BBB0)();
|
return Utils::Hook::Call<DWORD()>(0x42BBB0)();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::MapChangeStub()
|
void Theatre::MapChangeStub()
|
||||||
{
|
{
|
||||||
if (*Game::demoRecording)
|
if (*Game::demoRecording)
|
||||||
{
|
{
|
||||||
Command::Execute("stoprecord", true);
|
Command::Execute("stoprecord", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Hook::Call<void()>(0x464A60)();
|
Utils::Hook::Call<void()>(0x464A60)();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theatre::MapChangeSVStub(char* a1, char* a2)
|
void Theatre::MapChangeSVStub(char* a1, char* a2)
|
||||||
{
|
{
|
||||||
if (*Game::demoRecording)
|
if (*Game::demoRecording)
|
||||||
{
|
{
|
||||||
Command::Execute("stoprecord", true);
|
Command::Execute("stoprecord", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Hook::Call<void(char*, char*)>(0x487C50)(a1, a2);
|
Utils::Hook::Call<void(char*, char*)>(0x487C50)(a1, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Theatre::Theatre()
|
Theatre::Theatre()
|
||||||
{
|
{
|
||||||
Dvar::Register<bool>("cl_autoRecord", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Automatically record games.");
|
Dvar::Register<bool>("cl_autoRecord", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Automatically record games.");
|
||||||
Dvar::Register<int>("cl_demosKeep", 30, 1, 999, Game::dvar_flag::DVAR_FLAG_SAVED, "How many demos to keep with autorecord.");
|
Dvar::Register<int>("cl_demosKeep", 30, 1, 999, Game::dvar_flag::DVAR_FLAG_SAVED, "How many demos to keep with autorecord.");
|
||||||
|
|
||||||
Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5A85D2, Theatre::RecordGamestateStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A85D2, Theatre::RecordGamestateStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5ABE36, Theatre::BaselineStoreStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x5ABE36, Theatre::BaselineStoreStub, HOOK_JUMP).Install()->Quick();
|
||||||
Utils::Hook(0x5A8630, Theatre::BaselineToFileStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x5A8630, Theatre::BaselineToFileStub, HOOK_JUMP).Install()->Quick();
|
||||||
Utils::Hook(0x4CB3EF, Theatre::UISetActiveMenuStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x4CB3EF, Theatre::UISetActiveMenuStub, HOOK_JUMP).Install()->Quick();
|
||||||
Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5A8E03, Theatre::ServerTimedOutStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x5A8E03, Theatre::ServerTimedOutStub, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
// Hook commands to enforce metadata generation
|
// Hook commands to enforce metadata generation
|
||||||
Utils::Hook(0x5A82AE, Theatre::RecordStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A82AE, Theatre::RecordStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5A8156, Theatre::StopRecordStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A8156, Theatre::StopRecordStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// Autorecording
|
// Autorecording
|
||||||
Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
// UIScripts
|
// UIScripts
|
||||||
UIScript::Add("loadDemos", Theatre::LoadDemos);
|
UIScript::Add("loadDemos", Theatre::LoadDemos);
|
||||||
UIScript::Add("launchDemo", Theatre::PlayDemo);
|
UIScript::Add("launchDemo", Theatre::PlayDemo);
|
||||||
UIScript::Add("deleteDemo", Theatre::DeleteDemo);
|
UIScript::Add("deleteDemo", Theatre::DeleteDemo);
|
||||||
|
|
||||||
// Feeder
|
// Feeder
|
||||||
UIFeeder::Add(10.0f, Theatre::GetDemoCount, Theatre::GetDemoText, Theatre::SelectDemo);
|
UIFeeder::Add(10.0f, Theatre::GetDemoCount, Theatre::GetDemoText, Theatre::SelectDemo);
|
||||||
|
|
||||||
// set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps
|
// set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps
|
||||||
if(!Dedicated::IsDedicated()) Utils::Hook::Set<char*>(0x47440B, "mp/defaultStringTable.csv");
|
if(!Dedicated::IsDedicated()) Utils::Hook::Set<char*>(0x47440B, "mp/defaultStringTable.csv");
|
||||||
|
|
||||||
// Change font size
|
// Change font size
|
||||||
Utils::Hook::Set<BYTE>(0x5AC854, 2);
|
Utils::Hook::Set<BYTE>(0x5AC854, 2);
|
||||||
Utils::Hook::Set<BYTE>(0x5AC85A, 2);
|
Utils::Hook::Set<BYTE>(0x5AC85A, 2);
|
||||||
|
|
||||||
// Command::Add("democycle", [] (Command::Params params)
|
// Command::Add("democycle", [] (Command::Params params)
|
||||||
// {
|
// {
|
||||||
// // Cmd_FollowCycle_f
|
// // Cmd_FollowCycle_f
|
||||||
// Utils::Hook::Call<void(Game::gentity_t*, int)>(0x458ED0)(Game::g_entities, -1);
|
// Utils::Hook::Call<void(Game::gentity_t*, int)>(0x458ED0)(Game::g_entities, -1);
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
class Theatre : public Component
|
class Theatre : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Theatre();
|
Theatre();
|
||||||
const char* GetName() { return "Theatre"; };
|
const char* GetName() { return "Theatre"; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Container
|
class Container
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class DemoInfo
|
class DemoInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string Name;
|
std::string Name;
|
||||||
std::string Mapname;
|
std::string Mapname;
|
||||||
std::string Gametype;
|
std::string Gametype;
|
||||||
std::string Author;
|
std::string Author;
|
||||||
int Length;
|
int Length;
|
||||||
std::time_t TimeStamp;
|
std::time_t TimeStamp;
|
||||||
|
|
||||||
json11::Json to_json() const
|
json11::Json to_json() const
|
||||||
{
|
{
|
||||||
return json11::Json::object
|
return json11::Json::object
|
||||||
{
|
{
|
||||||
{ "mapname", Mapname },
|
{ "mapname", Mapname },
|
||||||
{ "gametype", Gametype },
|
{ "gametype", Gametype },
|
||||||
{ "author", Author },
|
{ "author", Author },
|
||||||
{ "length", Length },
|
{ "length", Length },
|
||||||
{ "timestamp", Utils::VA("%lld", TimeStamp) } //Ugly, but prevents information loss
|
{ "timestamp", fmt::sprintf("%lld", TimeStamp) } //Ugly, but prevents information loss
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DemoInfo CurrentInfo;
|
DemoInfo CurrentInfo;
|
||||||
unsigned int CurrentSelection;
|
unsigned int CurrentSelection;
|
||||||
std::vector<DemoInfo> Demos;
|
std::vector<DemoInfo> Demos;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Container DemoContainer;
|
static Container DemoContainer;
|
||||||
|
|
||||||
static char BaselineSnapshot[131072];
|
static char BaselineSnapshot[131072];
|
||||||
static int BaselineSnapshotMsgLen;
|
static int BaselineSnapshotMsgLen;
|
||||||
static int BaselineSnapshotMsgOff;
|
static int BaselineSnapshotMsgOff;
|
||||||
|
|
||||||
static void WriteBaseline();
|
static void WriteBaseline();
|
||||||
static void StoreBaseline(PBYTE snapshotMsg);
|
static void StoreBaseline(PBYTE snapshotMsg);
|
||||||
|
|
||||||
static void LoadDemos();
|
static void LoadDemos();
|
||||||
static void DeleteDemo();
|
static void DeleteDemo();
|
||||||
static void PlayDemo();
|
static void PlayDemo();
|
||||||
|
|
||||||
static unsigned int GetDemoCount();
|
static unsigned int GetDemoCount();
|
||||||
static const char* GetDemoText(unsigned int item, int column);
|
static const char* GetDemoText(unsigned int item, int column);
|
||||||
static void SelectDemo(unsigned int index);
|
static void SelectDemo(unsigned int index);
|
||||||
|
|
||||||
static void GamestateWriteStub(Game::msg_t* msg, char byte);
|
static void GamestateWriteStub(Game::msg_t* msg, char byte);
|
||||||
static void RecordGamestateStub();
|
static void RecordGamestateStub();
|
||||||
static void BaselineStoreStub();
|
static void BaselineStoreStub();
|
||||||
static void BaselineToFileStub();
|
static void BaselineToFileStub();
|
||||||
static void AdjustTimeDeltaStub();
|
static void AdjustTimeDeltaStub();
|
||||||
static void ServerTimedOutStub();
|
static void ServerTimedOutStub();
|
||||||
static void UISetActiveMenuStub();
|
static void UISetActiveMenuStub();
|
||||||
|
|
||||||
static uint32_t InitCGameStub();
|
static uint32_t InitCGameStub();
|
||||||
static void MapChangeStub();
|
static void MapChangeStub();
|
||||||
static void MapChangeSVStub(char* a1, char* a2);
|
static void MapChangeSVStub(char* a1, char* a2);
|
||||||
|
|
||||||
static void RecordStub(int channel, char* message, char* file);
|
static void RecordStub(int channel, char* message, char* file);
|
||||||
static void StopRecordStub(int channel, char* message);
|
static void StopRecordStub(int channel, char* message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,142 +1,142 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::queue<Toast::UIToast> Toast::Queue;
|
std::queue<Toast::UIToast> Toast::Queue;
|
||||||
std::mutex Toast::Mutex;
|
std::mutex Toast::Mutex;
|
||||||
|
|
||||||
void Toast::Show(const char* image, const char* title, const char* description, int length)
|
void Toast::Show(std::string image, std::string title, std::string description, int length)
|
||||||
{
|
{
|
||||||
Toast::Mutex.lock();
|
Toast::Mutex.lock();
|
||||||
Toast::Queue.push({ image, title, description, length, 0 });
|
Toast::Queue.push({ image, title, description, length, 0 });
|
||||||
Toast::Mutex.unlock();
|
Toast::Mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toast::Draw(UIToast* toast)
|
void Toast::Draw(UIToast* toast)
|
||||||
{
|
{
|
||||||
if (!toast) return;
|
if (!toast) return;
|
||||||
|
|
||||||
int width = Renderer::Width();
|
int width = Renderer::Width();
|
||||||
int height = Renderer::Height();
|
int height = Renderer::Height();
|
||||||
int slideTime = 100;
|
int slideTime = 100;
|
||||||
|
|
||||||
int duration = toast->Length;
|
int duration = toast->Length;
|
||||||
int startTime = toast->Start;
|
int startTime = toast->Start;
|
||||||
|
|
||||||
int border = 1;
|
int border = 1;
|
||||||
int cornerSize = 15;
|
int cornerSize = 15;
|
||||||
int bHeight = 74;
|
int bHeight = 74;
|
||||||
|
|
||||||
int imgDim = 60;
|
int imgDim = 60;
|
||||||
|
|
||||||
float fontSize = 0.9f;
|
float fontSize = 0.9f;
|
||||||
float descSize = 0.9f;
|
float descSize = 0.9f;
|
||||||
|
|
||||||
Game::Material* white = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "white").material;
|
Game::Material* white = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "white").material;
|
||||||
Game::Material* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, toast->Image.data()).material;
|
Game::Material* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, toast->Image.data()).material;
|
||||||
Game::Font* font = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/objectiveFont").font;
|
Game::Font* font = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/objectiveFont").font;
|
||||||
Game::Font* descfont = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/normalFont").font;
|
Game::Font* descfont = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/normalFont").font;
|
||||||
Game::vec4_t wColor = { 1.0f, 1.0f, 1.0f, 1.0f };
|
Game::vec4_t wColor = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
Game::vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.5f };
|
Game::vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.5f };
|
||||||
Game::vec4_t borderColor = { 1.0f, 1.0f, 1.0f, 0.2f };
|
Game::vec4_t borderColor = { 1.0f, 1.0f, 1.0f, 0.2f };
|
||||||
|
|
||||||
height /= 5;
|
height /= 5;
|
||||||
height *= 4;
|
height *= 4;
|
||||||
|
|
||||||
if (Game::Sys_Milliseconds() < startTime || (startTime + duration) < Game::Sys_Milliseconds()) return;
|
if (Game::Sys_Milliseconds() < startTime || (startTime + duration) < Game::Sys_Milliseconds()) return;
|
||||||
|
|
||||||
// Fadein stuff
|
// Fadein stuff
|
||||||
else if (Game::Sys_Milliseconds() - startTime < slideTime)
|
else if (Game::Sys_Milliseconds() - startTime < slideTime)
|
||||||
{
|
{
|
||||||
int diffH = Renderer::Height() / 5;
|
int diffH = Renderer::Height() / 5;
|
||||||
int diff = Game::Sys_Milliseconds() - startTime;
|
int diff = Game::Sys_Milliseconds() - startTime;
|
||||||
double scale = 1.0 - ((1.0 * diff) / (1.0 * slideTime));
|
double scale = 1.0 - ((1.0 * diff) / (1.0 * slideTime));
|
||||||
diffH = static_cast<int>(diffH * scale);
|
diffH = static_cast<int>(diffH * scale);
|
||||||
height += diffH;
|
height += diffH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fadeout stuff
|
// Fadeout stuff
|
||||||
else if (Game::Sys_Milliseconds() - startTime > (duration - slideTime))
|
else if (Game::Sys_Milliseconds() - startTime > (duration - slideTime))
|
||||||
{
|
{
|
||||||
int diffH = Renderer::Height() / 5;
|
int diffH = Renderer::Height() / 5;
|
||||||
int diff = (startTime + duration) - Game::Sys_Milliseconds();
|
int diff = (startTime + duration) - Game::Sys_Milliseconds();
|
||||||
double scale = 1.0 - ((1.0 * diff) / (1.0 * slideTime));
|
double scale = 1.0 - ((1.0 * diff) / (1.0 * slideTime));
|
||||||
diffH = static_cast<int>(diffH * scale);
|
diffH = static_cast<int>(diffH * scale);
|
||||||
height += diffH;
|
height += diffH;
|
||||||
}
|
}
|
||||||
|
|
||||||
height += bHeight / 2 - cornerSize;
|
height += bHeight / 2 - cornerSize;
|
||||||
|
|
||||||
// Calculate width data
|
// Calculate width data
|
||||||
int iOffset = (bHeight - imgDim) / 2;
|
int iOffset = (bHeight - imgDim) / 2;
|
||||||
int iOffsetLeft = iOffset * 2;
|
int iOffsetLeft = iOffset * 2;
|
||||||
float titleSize = Game::R_TextWidth(toast->Title.data(), 0x7FFFFFFF, font) * fontSize;
|
float titleSize = Game::R_TextWidth(toast->Title.data(), 0x7FFFFFFF, font) * fontSize;
|
||||||
float descrSize = Game::R_TextWidth(toast->Desc.data(), 0x7FFFFFFF, descfont) * descSize;
|
float descrSize = Game::R_TextWidth(toast->Desc.data(), 0x7FFFFFFF, descfont) * descSize;
|
||||||
float bWidth = iOffsetLeft * 3 + imgDim + std::max(titleSize, descrSize);
|
float bWidth = iOffsetLeft * 3 + imgDim + std::max(titleSize, descrSize);
|
||||||
|
|
||||||
// Make stuff divisible by 2
|
// Make stuff divisible by 2
|
||||||
// Otherwise there are overlapping images
|
// Otherwise there are overlapping images
|
||||||
// and I'm too lazy to figure out the actual problem :P
|
// and I'm too lazy to figure out the actual problem :P
|
||||||
bWidth = (static_cast<int>(bWidth) + (static_cast<int>(bWidth) % 2)) * 1.0f;
|
bWidth = (static_cast<int>(bWidth) + (static_cast<int>(bWidth) % 2)) * 1.0f;
|
||||||
bHeight += (bHeight % 2);
|
bHeight += (bHeight % 2);
|
||||||
|
|
||||||
// Background
|
// Background
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height - bHeight / 2), bWidth * 1.0f, bHeight * 1.0f, 0, 0, 1.0f, 1.0f, bgColor, white);
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height - bHeight / 2), bWidth * 1.0f, bHeight * 1.0f, 0, 0, 1.0f, 1.0f, bgColor, white);
|
||||||
|
|
||||||
// Border
|
// Border
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 - border), static_cast<float>(height - bHeight / 2 - border), border * 1.0f, bHeight + (border * 2.0f), 0, 0, 1.0f, 1.0f, borderColor, white); // Left
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 - border), static_cast<float>(height - bHeight / 2 - border), border * 1.0f, bHeight + (border * 2.0f), 0, 0, 1.0f, 1.0f, borderColor, white); // Left
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 + bWidth), static_cast<float>(height - bHeight / 2 - border), border * 1.0f, bHeight + (border * 2.0f), 0, 0, 1.0f, 1.0f, borderColor, white); // Right
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 + bWidth), static_cast<float>(height - bHeight / 2 - border), border * 1.0f, bHeight + (border * 2.0f), 0, 0, 1.0f, 1.0f, borderColor, white); // Right
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height - bHeight / 2 - border), bWidth * 1.0f, border * 1.0f, 0, 0, 1.0f, 1.0f, borderColor, white); // Top
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height - bHeight / 2 - border), bWidth * 1.0f, border * 1.0f, 0, 0, 1.0f, 1.0f, borderColor, white); // Top
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height + bHeight / 2), bWidth * 1.0f, border * 1.0f, 0, 0, 1.0f, 1.0f, borderColor, white); // Bottom
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2), static_cast<float>(height + bHeight / 2), bWidth * 1.0f, border * 1.0f, 0, 0, 1.0f, 1.0f, borderColor, white); // Bottom
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 + iOffsetLeft), static_cast<float>(height - bHeight / 2 + iOffset), imgDim * 1.0f, imgDim * 1.0f, 0, 0, 1.0f, 1.0f, wColor, image);
|
Game::CL_DrawStretchPicPhysical(static_cast<float>(width / 2 - bWidth / 2 + iOffsetLeft), static_cast<float>(height - bHeight / 2 + iOffset), imgDim * 1.0f, imgDim * 1.0f, 0, 0, 1.0f, 1.0f, wColor, image);
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
float leftText = width / 2 - bWidth / 2 - cornerSize + iOffsetLeft * 2 + imgDim;
|
float leftText = width / 2 - bWidth / 2 - cornerSize + iOffsetLeft * 2 + imgDim;
|
||||||
float rightText = width / 2 + bWidth / 2 - cornerSize - iOffsetLeft;
|
float rightText = width / 2 + bWidth / 2 - cornerSize - iOffsetLeft;
|
||||||
Game::R_AddCmdDrawText(Utils::StrToUpper(toast->Title).data(), 0x7FFFFFFF, font, static_cast<float>(leftText + (rightText - leftText) / 2 - titleSize / 2 + cornerSize), static_cast<float>(height - bHeight / 2 + cornerSize * 2 + 7), fontSize, fontSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Title
|
Game::R_AddCmdDrawText(Utils::String::StrToUpper(toast->Title).data(), 0x7FFFFFFF, font, static_cast<float>(leftText + (rightText - leftText) / 2 - titleSize / 2 + cornerSize), static_cast<float>(height - bHeight / 2 + cornerSize * 2 + 7), fontSize, fontSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Title
|
||||||
Game::R_AddCmdDrawText(toast->Desc.data(), 0x7FFFFFFF, descfont, leftText + (rightText - leftText) / 2 - descrSize / 2 + cornerSize, static_cast<float>(height - bHeight / 2 + cornerSize * 2 + 33), descSize, descSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Description
|
Game::R_AddCmdDrawText(toast->Desc.data(), 0x7FFFFFFF, descfont, leftText + (rightText - leftText) / 2 - descrSize / 2 + cornerSize, static_cast<float>(height - bHeight / 2 + cornerSize * 2 + 33), descSize, descSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Description
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toast::Handler()
|
void Toast::Handler()
|
||||||
{
|
{
|
||||||
if (Toast::Queue.empty()) return;
|
if (Toast::Queue.empty()) return;
|
||||||
|
|
||||||
Toast::Mutex.lock();
|
Toast::Mutex.lock();
|
||||||
|
|
||||||
Toast::UIToast* toast = &Toast::Queue.front();
|
Toast::UIToast* toast = &Toast::Queue.front();
|
||||||
|
|
||||||
// Set start time
|
// Set start time
|
||||||
if (!toast->Start)
|
if (!toast->Start)
|
||||||
{
|
{
|
||||||
toast->Start = Game::Sys_Milliseconds();
|
toast->Start = Game::Sys_Milliseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((toast->Start + toast->Length) < Game::Sys_Milliseconds())
|
if ((toast->Start + toast->Length) < Game::Sys_Milliseconds())
|
||||||
{
|
{
|
||||||
Toast::Queue.pop();
|
Toast::Queue.pop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Toast::Draw(toast);
|
Toast::Draw(toast);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast::Mutex.unlock();
|
Toast::Mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast::Toast()
|
Toast::Toast()
|
||||||
{
|
{
|
||||||
Renderer::OnFrame(Toast::Handler);
|
Renderer::OnFrame(Toast::Handler);
|
||||||
|
|
||||||
Command::Add("testtoast", [] (Command::Params)
|
Command::Add("testtoast", [] (Command::Params)
|
||||||
{
|
{
|
||||||
Toast::Show("cardicon_prestige10", "Test", "This is a test toast", 3000);
|
Toast::Show("cardicon_prestige10", "Test", "This is a test toast", 3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast::~Toast()
|
Toast::~Toast()
|
||||||
{
|
{
|
||||||
Toast::Queue = std::queue<Toast::UIToast>();
|
Toast::Queue = std::queue<Toast::UIToast>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
class Toast : public Component
|
class Toast : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Toast();
|
Toast();
|
||||||
~Toast();
|
~Toast();
|
||||||
const char* GetName() { return "Toast"; };
|
const char* GetName() { return "Toast"; };
|
||||||
|
|
||||||
static void Show(const char* image, const char* title, const char* description, int length);
|
static void Show(std::string image, std::string title, std::string description, int length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class UIToast
|
class UIToast
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string Image;
|
std::string Image;
|
||||||
std::string Title;
|
std::string Title;
|
||||||
std::string Desc;
|
std::string Desc;
|
||||||
int Length;
|
int Length;
|
||||||
int Start;
|
int Start;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void Handler();
|
static void Handler();
|
||||||
static void Draw(UIToast* toast);
|
static void Draw(UIToast* toast);
|
||||||
|
|
||||||
static std::queue<UIToast> Queue;
|
static std::queue<UIToast> Queue;
|
||||||
static std::mutex Mutex;
|
static std::mutex Mutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Game::XAssetHeader Weapon::WeaponFileLoad(Game::XAssetType type, std::string filename)
|
Game::XAssetHeader Weapon::WeaponFileLoad(Game::XAssetType type, std::string filename)
|
||||||
{
|
{
|
||||||
Game::XAssetHeader header = { 0 };
|
Game::XAssetHeader header = { 0 };
|
||||||
|
|
||||||
// Try loading raw weapon
|
// Try loading raw weapon
|
||||||
if (FileSystem::File(Utils::VA("weapons/mp/%s", filename.data())).Exists())
|
if (FileSystem::File(fmt::sprintf("weapons/mp/%s", filename.data())).Exists())
|
||||||
{
|
{
|
||||||
header.data = Game::BG_LoadWeaponDef_LoadObj(filename.data());
|
header.data = Game::BG_LoadWeaponDef_LoadObj(filename.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
Weapon::Weapon()
|
Weapon::Weapon()
|
||||||
{
|
{
|
||||||
// Intercept weapon loading
|
// Intercept weapon loading
|
||||||
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_WEAPON, Weapon::WeaponFileLoad);
|
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_WEAPON, Weapon::WeaponFileLoad);
|
||||||
|
|
||||||
// weapon asset existence check
|
// weapon asset existence check
|
||||||
Utils::Hook::Nop(0x408228, 5); // find asset header
|
Utils::Hook::Nop(0x408228, 5); // find asset header
|
||||||
Utils::Hook::Nop(0x408230, 5); // is asset default
|
Utils::Hook::Nop(0x408230, 5); // is asset default
|
||||||
Utils::Hook::Nop(0x40823A, 2); // jump
|
Utils::Hook::Nop(0x40823A, 2); // jump
|
||||||
|
|
||||||
// Skip double loading for fs_game
|
// Skip double loading for fs_game
|
||||||
Utils::Hook::Set<BYTE>(0x4081FD, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4081FD, 0xEB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,407 +1,407 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
// C-Style casts are fine here, that's where we're doing our dirty stuff anyways...
|
// C-Style casts are fine here, that's where we're doing our dirty stuff anyways...
|
||||||
BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = (BG_LoadWeaponDef_LoadObj_t)0x57B5F0;
|
BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = (BG_LoadWeaponDef_LoadObj_t)0x57B5F0;
|
||||||
|
|
||||||
Cbuf_AddServerText_t Cbuf_AddServerText = (Cbuf_AddServerText_t)0x4BB9B0;
|
Cbuf_AddServerText_t Cbuf_AddServerText = (Cbuf_AddServerText_t)0x4BB9B0;
|
||||||
Cbuf_AddText_t Cbuf_AddText = (Cbuf_AddText_t)0x404B20;
|
Cbuf_AddText_t Cbuf_AddText = (Cbuf_AddText_t)0x404B20;
|
||||||
|
|
||||||
CL_GetClientName_t CL_GetClientName = (CL_GetClientName_t)0x4563D0;
|
CL_GetClientName_t CL_GetClientName = (CL_GetClientName_t)0x4563D0;
|
||||||
CL_IsCgameInitialized_t CL_IsCgameInitialized = (CL_IsCgameInitialized_t)0x43EB20;
|
CL_IsCgameInitialized_t CL_IsCgameInitialized = (CL_IsCgameInitialized_t)0x43EB20;
|
||||||
CL_ConnectFromParty_t CL_ConnectFromParty = (CL_ConnectFromParty_t)0x433D30;
|
CL_ConnectFromParty_t CL_ConnectFromParty = (CL_ConnectFromParty_t)0x433D30;
|
||||||
CL_DownloadsComplete_t CL_DownloadsComplete = (CL_DownloadsComplete_t)0x42CE90;
|
CL_DownloadsComplete_t CL_DownloadsComplete = (CL_DownloadsComplete_t)0x42CE90;
|
||||||
CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical = (CL_DrawStretchPicPhysical_t)0x4FC120;
|
CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical = (CL_DrawStretchPicPhysical_t)0x4FC120;
|
||||||
CL_ResetViewport_t CL_ResetViewport = (CL_ResetViewport_t)0x4A8830;
|
CL_ResetViewport_t CL_ResetViewport = (CL_ResetViewport_t)0x4A8830;
|
||||||
|
|
||||||
Cmd_AddCommand_t Cmd_AddCommand = (Cmd_AddCommand_t)0x470090;
|
Cmd_AddCommand_t Cmd_AddCommand = (Cmd_AddCommand_t)0x470090;
|
||||||
Cmd_AddServerCommand_t Cmd_AddServerCommand = (Cmd_AddServerCommand_t)0x4DCE00;
|
Cmd_AddServerCommand_t Cmd_AddServerCommand = (Cmd_AddServerCommand_t)0x4DCE00;
|
||||||
Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand = (Cmd_ExecuteSingleCommand_t)0x609540;
|
Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand = (Cmd_ExecuteSingleCommand_t)0x609540;
|
||||||
|
|
||||||
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
|
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
|
||||||
Com_Printf_t Com_Printf = (Com_Printf_t)0x402500;
|
Com_Printf_t Com_Printf = (Com_Printf_t)0x402500;
|
||||||
Com_PrintMessage_t Com_PrintMessage = (Com_PrintMessage_t)0x4AA830;
|
Com_PrintMessage_t Com_PrintMessage = (Com_PrintMessage_t)0x4AA830;
|
||||||
Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60;
|
Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60;
|
||||||
|
|
||||||
Con_DrawMiniConsole_t Con_DrawMiniConsole = (Con_DrawMiniConsole_t)0x464F30;
|
Con_DrawMiniConsole_t Con_DrawMiniConsole = (Con_DrawMiniConsole_t)0x464F30;
|
||||||
Con_DrawSolidConsole_t Con_DrawSolidConsole = (Con_DrawSolidConsole_t)0x5A5040;
|
Con_DrawSolidConsole_t Con_DrawSolidConsole = (Con_DrawSolidConsole_t)0x5A5040;
|
||||||
|
|
||||||
DB_EnumXAssets_t DB_EnumXAssets = (DB_EnumXAssets_t)0x4B76D0;
|
DB_EnumXAssets_t DB_EnumXAssets = (DB_EnumXAssets_t)0x4B76D0;
|
||||||
DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal = (DB_EnumXAssets_Internal_t)0x5BB0A0;
|
DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal = (DB_EnumXAssets_Internal_t)0x5BB0A0;
|
||||||
DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930;
|
DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930;
|
||||||
DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328;
|
DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328;
|
||||||
DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488;
|
DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488;
|
||||||
DB_GetXAssetTypeName_t DB_GetXAssetTypeName = (DB_GetXAssetTypeName_t)0x4CFCF0;
|
DB_GetXAssetTypeName_t DB_GetXAssetTypeName = (DB_GetXAssetTypeName_t)0x4CFCF0;
|
||||||
DB_IsXAssetDefault_t DB_IsXAssetDefault = (DB_IsXAssetDefault_t)0x48E6A0;
|
DB_IsXAssetDefault_t DB_IsXAssetDefault = (DB_IsXAssetDefault_t)0x48E6A0;
|
||||||
DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930;
|
DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930;
|
||||||
DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = (DB_ReadXFileUncompressed_t)0x4705E0;
|
DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = (DB_ReadXFileUncompressed_t)0x4705E0;
|
||||||
|
|
||||||
Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x4CE1A0;
|
Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x4CE1A0;
|
||||||
Dvar_RegisterFloat_t Dvar_RegisterFloat = (Dvar_RegisterFloat_t)0x648440;
|
Dvar_RegisterFloat_t Dvar_RegisterFloat = (Dvar_RegisterFloat_t)0x648440;
|
||||||
Dvar_RegisterVec2_t Dvar_RegisterVec2 = (Dvar_RegisterVec2_t)0x4F6070;
|
Dvar_RegisterVec2_t Dvar_RegisterVec2 = (Dvar_RegisterVec2_t)0x4F6070;
|
||||||
Dvar_RegisterVec3_t Dvar_RegisterVec3 = (Dvar_RegisterVec3_t)0x4EF8E0;
|
Dvar_RegisterVec3_t Dvar_RegisterVec3 = (Dvar_RegisterVec3_t)0x4EF8E0;
|
||||||
Dvar_RegisterVec4_t Dvar_RegisterVec4 = (Dvar_RegisterVec4_t)0x4F28E0;
|
Dvar_RegisterVec4_t Dvar_RegisterVec4 = (Dvar_RegisterVec4_t)0x4F28E0;
|
||||||
Dvar_RegisterInt_t Dvar_RegisterInt = (Dvar_RegisterInt_t)0x479830;
|
Dvar_RegisterInt_t Dvar_RegisterInt = (Dvar_RegisterInt_t)0x479830;
|
||||||
Dvar_RegisterEnum_t Dvar_RegisterEnum = (Dvar_RegisterEnum_t)0x412E40;
|
Dvar_RegisterEnum_t Dvar_RegisterEnum = (Dvar_RegisterEnum_t)0x412E40;
|
||||||
Dvar_RegisterString_t Dvar_RegisterString = (Dvar_RegisterString_t)0x4FC7E0;
|
Dvar_RegisterString_t Dvar_RegisterString = (Dvar_RegisterString_t)0x4FC7E0;
|
||||||
Dvar_RegisterColor_t Dvar_RegisterColor = (Dvar_RegisterColor_t)0x4F28E0;//0x471500;
|
Dvar_RegisterColor_t Dvar_RegisterColor = (Dvar_RegisterColor_t)0x4F28E0;//0x471500;
|
||||||
|
|
||||||
Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = (Dvar_GetUnpackedColorByName_t)0x406530;
|
Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = (Dvar_GetUnpackedColorByName_t)0x406530;
|
||||||
Dvar_FindVar_t Dvar_FindVar = (Dvar_FindVar_t)0x4D5390;
|
Dvar_FindVar_t Dvar_FindVar = (Dvar_FindVar_t)0x4D5390;
|
||||||
Dvar_InfoString_Big_t Dvar_InfoString_Big = (Dvar_InfoString_Big_t)0x4D98A0;
|
Dvar_InfoString_Big_t Dvar_InfoString_Big = (Dvar_InfoString_Big_t)0x4D98A0;
|
||||||
Dvar_SetCommand_t Dvar_SetCommand = (Dvar_SetCommand_t)0x4EE430;
|
Dvar_SetCommand_t Dvar_SetCommand = (Dvar_SetCommand_t)0x4EE430;
|
||||||
|
|
||||||
Field_Clear_t Field_Clear = (Field_Clear_t)0x437EB0;
|
Field_Clear_t Field_Clear = (Field_Clear_t)0x437EB0;
|
||||||
|
|
||||||
FreeMemory_t FreeMemory = (FreeMemory_t)0x4D6640;
|
FreeMemory_t FreeMemory = (FreeMemory_t)0x4D6640;
|
||||||
|
|
||||||
FS_FileExists_t FS_FileExists = (FS_FileExists_t)0x4DEFA0;
|
FS_FileExists_t FS_FileExists = (FS_FileExists_t)0x4DEFA0;
|
||||||
FS_FreeFile_t FS_FreeFile = (FS_FreeFile_t)0x4416B0;
|
FS_FreeFile_t FS_FreeFile = (FS_FreeFile_t)0x4416B0;
|
||||||
FS_ReadFile_t FS_ReadFile = (FS_ReadFile_t)0x4F4B90;
|
FS_ReadFile_t FS_ReadFile = (FS_ReadFile_t)0x4F4B90;
|
||||||
FS_GetFileList_t FS_GetFileList = (FS_GetFileList_t)0x441BB0;
|
FS_GetFileList_t FS_GetFileList = (FS_GetFileList_t)0x441BB0;
|
||||||
FS_FreeFileList_t FS_FreeFileList = (FS_FreeFileList_t)0x4A5DE0;
|
FS_FreeFileList_t FS_FreeFileList = (FS_FreeFileList_t)0x4A5DE0;
|
||||||
FS_FOpenFileAppend_t FS_FOpenFileAppend = (FS_FOpenFileAppend_t)0x410BB0;
|
FS_FOpenFileAppend_t FS_FOpenFileAppend = (FS_FOpenFileAppend_t)0x410BB0;
|
||||||
FS_FOpenFileAppend_t FS_FOpenFileWrite = (FS_FOpenFileAppend_t)0x4BA530;
|
FS_FOpenFileAppend_t FS_FOpenFileWrite = (FS_FOpenFileAppend_t)0x4BA530;
|
||||||
FS_FOpenFileRead_t FS_FOpenFileRead = (FS_FOpenFileRead_t)0x46CBF0;
|
FS_FOpenFileRead_t FS_FOpenFileRead = (FS_FOpenFileRead_t)0x46CBF0;
|
||||||
FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread = (FS_FOpenFileReadForThread_t)0x643270;
|
FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread = (FS_FOpenFileReadForThread_t)0x643270;
|
||||||
FS_FCloseFile_t FS_FCloseFile = (FS_FCloseFile_t)0x462000;
|
FS_FCloseFile_t FS_FCloseFile = (FS_FCloseFile_t)0x462000;
|
||||||
FS_WriteFile_t FS_WriteFile = (FS_WriteFile_t)0x426450;
|
FS_WriteFile_t FS_WriteFile = (FS_WriteFile_t)0x426450;
|
||||||
FS_Write_t FS_Write = (FS_Write_t)0x4C06E0;
|
FS_Write_t FS_Write = (FS_Write_t)0x4C06E0;
|
||||||
FS_Read_t FS_Read = (FS_Read_t)0x4A04C0;
|
FS_Read_t FS_Read = (FS_Read_t)0x4A04C0;
|
||||||
FS_Seek_t FS_Seek = (FS_Seek_t)0x4A63D0;
|
FS_Seek_t FS_Seek = (FS_Seek_t)0x4A63D0;
|
||||||
FS_FTell_t FS_FTell = (FS_FTell_t)0x4E6760;
|
FS_FTell_t FS_FTell = (FS_FTell_t)0x4E6760;
|
||||||
FS_Remove_t FS_Remove = (FS_Remove_t)0x4660F0;
|
FS_Remove_t FS_Remove = (FS_Remove_t)0x4660F0;
|
||||||
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
|
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
|
||||||
FS_BuildPathToFile_t FS_BuildPathToFile = (FS_BuildPathToFile_t)0x4702C0;
|
FS_BuildPathToFile_t FS_BuildPathToFile = (FS_BuildPathToFile_t)0x4702C0;
|
||||||
|
|
||||||
G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = (G_SpawnEntitiesFromString_t)0x4D8840;
|
G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = (G_SpawnEntitiesFromString_t)0x4D8840;
|
||||||
|
|
||||||
GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript = (GScr_LoadGameTypeScript_t)0x4ED9A0;
|
GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript = (GScr_LoadGameTypeScript_t)0x4ED9A0;
|
||||||
|
|
||||||
Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader = (Image_LoadFromFileWithReader_t)0x53ABF0;
|
Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader = (Image_LoadFromFileWithReader_t)0x53ABF0;
|
||||||
Image_Release_t Image_Release = (Image_Release_t)0x51F010;
|
Image_Release_t Image_Release = (Image_Release_t)0x51F010;
|
||||||
|
|
||||||
Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0;
|
Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0;
|
||||||
Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
|
Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
|
||||||
Menus_FindByName_t Menus_FindByName = (Menus_FindByName_t)0x487240;
|
Menus_FindByName_t Menus_FindByName = (Menus_FindByName_t)0x487240;
|
||||||
Menu_IsVisible_t Menu_IsVisible = (Menu_IsVisible_t)0x4D77D0;
|
Menu_IsVisible_t Menu_IsVisible = (Menu_IsVisible_t)0x4D77D0;
|
||||||
Menus_MenuIsInStack_t Menus_MenuIsInStack = (Menus_MenuIsInStack_t)0x47ACB0;
|
Menus_MenuIsInStack_t Menus_MenuIsInStack = (Menus_MenuIsInStack_t)0x47ACB0;
|
||||||
|
|
||||||
MSG_Init_t MSG_Init = (MSG_Init_t)0x45FCA0;
|
MSG_Init_t MSG_Init = (MSG_Init_t)0x45FCA0;
|
||||||
MSG_ReadData_t MSG_ReadData = (MSG_ReadData_t)0x4527C0;
|
MSG_ReadData_t MSG_ReadData = (MSG_ReadData_t)0x4527C0;
|
||||||
MSG_ReadLong_t MSG_ReadLong = (MSG_ReadLong_t)0x4C9550;
|
MSG_ReadLong_t MSG_ReadLong = (MSG_ReadLong_t)0x4C9550;
|
||||||
MSG_ReadShort_t MSG_ReadShort = (MSG_ReadShort_t)0x40BDD0;
|
MSG_ReadShort_t MSG_ReadShort = (MSG_ReadShort_t)0x40BDD0;
|
||||||
MSG_ReadInt64_t MSG_ReadInt64 = (MSG_ReadInt64_t)0x4F1850;
|
MSG_ReadInt64_t MSG_ReadInt64 = (MSG_ReadInt64_t)0x4F1850;
|
||||||
MSG_ReadString_t MSG_ReadString = (MSG_ReadString_t)0x60E2B0;
|
MSG_ReadString_t MSG_ReadString = (MSG_ReadString_t)0x60E2B0;
|
||||||
MSG_WriteByte_t MSG_WriteByte = (MSG_WriteByte_t)0x48C520;
|
MSG_WriteByte_t MSG_WriteByte = (MSG_WriteByte_t)0x48C520;
|
||||||
MSG_WriteData_t MSG_WriteData = (MSG_WriteData_t)0x4F4120;
|
MSG_WriteData_t MSG_WriteData = (MSG_WriteData_t)0x4F4120;
|
||||||
MSG_WriteLong_t MSG_WriteLong = (MSG_WriteLong_t)0x41CA20;
|
MSG_WriteLong_t MSG_WriteLong = (MSG_WriteLong_t)0x41CA20;
|
||||||
MSG_WriteBitsCompress_t MSG_WriteBitsCompress = (MSG_WriteBitsCompress_t)0x4319D0;
|
MSG_WriteBitsCompress_t MSG_WriteBitsCompress = (MSG_WriteBitsCompress_t)0x4319D0;
|
||||||
MSG_ReadByte_t MSG_ReadByte = (MSG_ReadByte_t)0x4C1C20;
|
MSG_ReadByte_t MSG_ReadByte = (MSG_ReadByte_t)0x4C1C20;
|
||||||
MSG_ReadBitsCompress_t MSG_ReadBitsCompress = (MSG_ReadBitsCompress_t)0x4DCC30;
|
MSG_ReadBitsCompress_t MSG_ReadBitsCompress = (MSG_ReadBitsCompress_t)0x4DCC30;
|
||||||
|
|
||||||
NetadrToSockadr_t NetadrToSockadr = (NetadrToSockadr_t)0x4B4B40;
|
NetadrToSockadr_t NetadrToSockadr = (NetadrToSockadr_t)0x4B4B40;
|
||||||
|
|
||||||
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
|
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
|
||||||
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
|
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
|
||||||
NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0;
|
NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0;
|
||||||
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
||||||
NET_OutOfBandPrint_t NET_OutOfBandPrint = (NET_OutOfBandPrint_t)0x4AEF00;
|
NET_OutOfBandPrint_t NET_OutOfBandPrint = (NET_OutOfBandPrint_t)0x4AEF00;
|
||||||
NET_OutOfBandData_t NET_OutOfBandData = (NET_OutOfBandData_t)0x49C7E0;
|
NET_OutOfBandData_t NET_OutOfBandData = (NET_OutOfBandData_t)0x49C7E0;
|
||||||
|
|
||||||
Live_MPAcceptInvite_t Live_MPAcceptInvite = (Live_MPAcceptInvite_t)0x420A6D;
|
Live_MPAcceptInvite_t Live_MPAcceptInvite = (Live_MPAcceptInvite_t)0x420A6D;
|
||||||
Live_ParsePlaylists_t Live_ParsePlaylists = (Live_ParsePlaylists_t)0x4295A0;
|
Live_ParsePlaylists_t Live_ParsePlaylists = (Live_ParsePlaylists_t)0x4295A0;
|
||||||
|
|
||||||
LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0;
|
LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0;
|
||||||
|
|
||||||
LocalizeString_t LocalizeString = (LocalizeString_t)0x4FB010;
|
LocalizeString_t LocalizeString = (LocalizeString_t)0x4FB010;
|
||||||
LocalizeMapString_t LocalizeMapString = (LocalizeMapString_t)0x44BB30;
|
LocalizeMapString_t LocalizeMapString = (LocalizeMapString_t)0x44BB30;
|
||||||
|
|
||||||
PC_ReadToken_t PC_ReadToken = (PC_ReadToken_t)0x4ACCD0;
|
PC_ReadToken_t PC_ReadToken = (PC_ReadToken_t)0x4ACCD0;
|
||||||
PC_ReadTokenHandle_t PC_ReadTokenHandle = (PC_ReadTokenHandle_t)0x4D2060;
|
PC_ReadTokenHandle_t PC_ReadTokenHandle = (PC_ReadTokenHandle_t)0x4D2060;
|
||||||
PC_SourceError_t PC_SourceError = (PC_SourceError_t)0x467A00;
|
PC_SourceError_t PC_SourceError = (PC_SourceError_t)0x467A00;
|
||||||
|
|
||||||
Party_GetMaxPlayers_t Party_GetMaxPlayers = (Party_GetMaxPlayers_t)0x4F5D60;
|
Party_GetMaxPlayers_t Party_GetMaxPlayers = (Party_GetMaxPlayers_t)0x4F5D60;
|
||||||
PartyHost_CountMembers_t PartyHost_CountMembers = (PartyHost_CountMembers_t)0x497330;
|
PartyHost_CountMembers_t PartyHost_CountMembers = (PartyHost_CountMembers_t)0x497330;
|
||||||
PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = (PartyHost_GetMemberAddressBySlot_t)0x44E100;
|
PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = (PartyHost_GetMemberAddressBySlot_t)0x44E100;
|
||||||
PartyHost_GetMemberName_t PartyHost_GetMemberName = (PartyHost_GetMemberName_t)0x44BE90;
|
PartyHost_GetMemberName_t PartyHost_GetMemberName = (PartyHost_GetMemberName_t)0x44BE90;
|
||||||
|
|
||||||
R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic = (R_AddCmdDrawStretchPic_t)0x509770;
|
R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic = (R_AddCmdDrawStretchPic_t)0x509770;
|
||||||
R_RegisterFont_t R_RegisterFont = (R_RegisterFont_t)0x505670;
|
R_RegisterFont_t R_RegisterFont = (R_RegisterFont_t)0x505670;
|
||||||
R_AddCmdDrawText_t R_AddCmdDrawText = (R_AddCmdDrawText_t)0x509D80;
|
R_AddCmdDrawText_t R_AddCmdDrawText = (R_AddCmdDrawText_t)0x509D80;
|
||||||
R_LoadGraphicsAssets_t R_LoadGraphicsAssets = (R_LoadGraphicsAssets_t)0x506AC0;
|
R_LoadGraphicsAssets_t R_LoadGraphicsAssets = (R_LoadGraphicsAssets_t)0x506AC0;
|
||||||
R_TextWidth_t R_TextWidth = (R_TextWidth_t)0x5056C0;
|
R_TextWidth_t R_TextWidth = (R_TextWidth_t)0x5056C0;
|
||||||
R_TextHeight_t R_TextHeight = (R_TextHeight_t)0x505770;
|
R_TextHeight_t R_TextHeight = (R_TextHeight_t)0x505770;
|
||||||
|
|
||||||
Scr_LoadGameType_t Scr_LoadGameType = (Scr_LoadGameType_t)0x4D9520;
|
Scr_LoadGameType_t Scr_LoadGameType = (Scr_LoadGameType_t)0x4D9520;
|
||||||
|
|
||||||
Scr_LoadScript_t Scr_LoadScript = (Scr_LoadScript_t)0x45D940;
|
Scr_LoadScript_t Scr_LoadScript = (Scr_LoadScript_t)0x45D940;
|
||||||
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = (Scr_GetFunctionHandle_t)0x4234F0;
|
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = (Scr_GetFunctionHandle_t)0x4234F0;
|
||||||
|
|
||||||
Scr_ExecThread_t Scr_ExecThread = (Scr_ExecThread_t)0x4AD0B0;
|
Scr_ExecThread_t Scr_ExecThread = (Scr_ExecThread_t)0x4AD0B0;
|
||||||
Scr_FreeThread_t Scr_FreeThread = (Scr_FreeThread_t)0x4BD320;
|
Scr_FreeThread_t Scr_FreeThread = (Scr_FreeThread_t)0x4BD320;
|
||||||
|
|
||||||
Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = (Scr_ShutdownAllocNode_t)0x441650;
|
Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = (Scr_ShutdownAllocNode_t)0x441650;
|
||||||
|
|
||||||
Script_Alloc_t Script_Alloc = (Script_Alloc_t)0x422E70;
|
Script_Alloc_t Script_Alloc = (Script_Alloc_t)0x422E70;
|
||||||
Script_SetupTokens_t Script_SetupTokens = (Script_SetupTokens_t)0x4E6950;
|
Script_SetupTokens_t Script_SetupTokens = (Script_SetupTokens_t)0x4E6950;
|
||||||
Script_CleanString_t Script_CleanString = (Script_CleanString_t)0x498220;
|
Script_CleanString_t Script_CleanString = (Script_CleanString_t)0x498220;
|
||||||
|
|
||||||
SE_Load_t SE_Load = (SE_Load_t)0x502A30;
|
SE_Load_t SE_Load = (SE_Load_t)0x502A30;
|
||||||
|
|
||||||
Dvar_SetStringByName_t Dvar_SetStringByName = (Dvar_SetStringByName_t)0x44F060;
|
Dvar_SetStringByName_t Dvar_SetStringByName = (Dvar_SetStringByName_t)0x44F060;
|
||||||
|
|
||||||
SL_ConvertToString_t SL_ConvertToString = (SL_ConvertToString_t)0x4EC1D0;
|
SL_ConvertToString_t SL_ConvertToString = (SL_ConvertToString_t)0x4EC1D0;
|
||||||
SL_GetString_t SL_GetString = (SL_GetString_t)0x4CDC10;
|
SL_GetString_t SL_GetString = (SL_GetString_t)0x4CDC10;
|
||||||
|
|
||||||
SND_InitDriver_t SND_InitDriver = (SND_InitDriver_t)0x4F5090;
|
SND_InitDriver_t SND_InitDriver = (SND_InitDriver_t)0x4F5090;
|
||||||
|
|
||||||
SockadrToNetadr_t SockadrToNetadr = (SockadrToNetadr_t)0x4F8460;
|
SockadrToNetadr_t SockadrToNetadr = (SockadrToNetadr_t)0x4F8460;
|
||||||
|
|
||||||
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
|
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
|
||||||
|
|
||||||
SV_GameClientNum_Score_t SV_GameClientNum_Score = (SV_GameClientNum_Score_t)0x469AC0;
|
SV_GameClientNum_Score_t SV_GameClientNum_Score = (SV_GameClientNum_Score_t)0x469AC0;
|
||||||
SV_GameSendServerCommand_t SV_GameSendServerCommand = (SV_GameSendServerCommand_t)0x4BC3A0;
|
SV_GameSendServerCommand_t SV_GameSendServerCommand = (SV_GameSendServerCommand_t)0x4BC3A0;
|
||||||
|
|
||||||
Sys_FreeFileList_t Sys_FreeFileList = (Sys_FreeFileList_t)0x4D8580;
|
Sys_FreeFileList_t Sys_FreeFileList = (Sys_FreeFileList_t)0x4D8580;
|
||||||
Sys_IsMainThread_t Sys_IsMainThread = (Sys_IsMainThread_t)0x4C37D0;
|
Sys_IsMainThread_t Sys_IsMainThread = (Sys_IsMainThread_t)0x4C37D0;
|
||||||
Sys_SendPacket_t Sys_SendPacket = (Sys_SendPacket_t)0x60FDC0;
|
Sys_SendPacket_t Sys_SendPacket = (Sys_SendPacket_t)0x60FDC0;
|
||||||
Sys_ShowConsole_t Sys_ShowConsole = (Sys_ShowConsole_t)0x4305E0;
|
Sys_ShowConsole_t Sys_ShowConsole = (Sys_ShowConsole_t)0x4305E0;
|
||||||
Sys_ListFiles_t Sys_ListFiles = (Sys_ListFiles_t)0x45A660;
|
Sys_ListFiles_t Sys_ListFiles = (Sys_ListFiles_t)0x45A660;
|
||||||
Sys_Milliseconds_t Sys_Milliseconds = (Sys_Milliseconds_t)0x42A660;
|
Sys_Milliseconds_t Sys_Milliseconds = (Sys_Milliseconds_t)0x42A660;
|
||||||
|
|
||||||
UI_AddMenuList_t UI_AddMenuList = (UI_AddMenuList_t)0x4533C0;
|
UI_AddMenuList_t UI_AddMenuList = (UI_AddMenuList_t)0x4533C0;
|
||||||
UI_LoadMenus_t UI_LoadMenus = (UI_LoadMenus_t)0x641460;
|
UI_LoadMenus_t UI_LoadMenus = (UI_LoadMenus_t)0x641460;
|
||||||
UI_DrawHandlePic_t UI_DrawHandlePic = (UI_DrawHandlePic_t)0x4D0EA0;
|
UI_DrawHandlePic_t UI_DrawHandlePic = (UI_DrawHandlePic_t)0x4D0EA0;
|
||||||
UI_GetContext_t UI_GetContext = (UI_GetContext_t)0x4F8940;
|
UI_GetContext_t UI_GetContext = (UI_GetContext_t)0x4F8940;
|
||||||
UI_TextWidth_t UI_TextWidth = (UI_TextWidth_t)0x6315C0;
|
UI_TextWidth_t UI_TextWidth = (UI_TextWidth_t)0x6315C0;
|
||||||
UI_DrawText_t UI_DrawText = (UI_DrawText_t)0x49C0D0;
|
UI_DrawText_t UI_DrawText = (UI_DrawText_t)0x49C0D0;
|
||||||
|
|
||||||
Win_GetLanguage_t Win_GetLanguage = (Win_GetLanguage_t)0x45CBA0;
|
Win_GetLanguage_t Win_GetLanguage = (Win_GetLanguage_t)0x45CBA0;
|
||||||
|
|
||||||
XAssetHeader* DB_XAssetPool = (XAssetHeader*)0x7998A8;
|
XAssetHeader* DB_XAssetPool = (XAssetHeader*)0x7998A8;
|
||||||
unsigned int* g_poolSize = (unsigned int*)0x7995E8;
|
unsigned int* g_poolSize = (unsigned int*)0x7995E8;
|
||||||
|
|
||||||
DWORD* cmd_id = (DWORD*)0x1AAC5D0;
|
DWORD* cmd_id = (DWORD*)0x1AAC5D0;
|
||||||
DWORD* cmd_argc = (DWORD*)0x1AAC614;
|
DWORD* cmd_argc = (DWORD*)0x1AAC614;
|
||||||
char*** cmd_argv = (char***)0x1AAC634;
|
char*** cmd_argv = (char***)0x1AAC634;
|
||||||
|
|
||||||
DWORD* cmd_id_sv = (DWORD*)0x1ACF8A0;
|
DWORD* cmd_id_sv = (DWORD*)0x1ACF8A0;
|
||||||
DWORD* cmd_argc_sv = (DWORD*)0x1ACF8E4;
|
DWORD* cmd_argc_sv = (DWORD*)0x1ACF8E4;
|
||||||
char*** cmd_argv_sv = (char***)0x1ACF904;
|
char*** cmd_argv_sv = (char***)0x1ACF904;
|
||||||
|
|
||||||
source_t **sourceFiles = (source_t **)0x7C4A98;
|
source_t **sourceFiles = (source_t **)0x7C4A98;
|
||||||
keywordHash_t **menuParseKeywordHash = (keywordHash_t **)0x63AE928;
|
keywordHash_t **menuParseKeywordHash = (keywordHash_t **)0x63AE928;
|
||||||
|
|
||||||
int* svs_numclients = (int*)0x31D938C;
|
int* svs_numclients = (int*)0x31D938C;
|
||||||
client_t* svs_clients = (client_t*)0x31D9390;
|
client_t* svs_clients = (client_t*)0x31D9390;
|
||||||
|
|
||||||
UiContext *uiContext = (UiContext *)0x62E2858;
|
UiContext *uiContext = (UiContext *)0x62E2858;
|
||||||
|
|
||||||
int* arenaCount = (int*)0x62E6930;
|
int* arenaCount = (int*)0x62E6930;
|
||||||
mapArena_t* arenas = (mapArena_t*)0x62E6934;
|
mapArena_t* arenas = (mapArena_t*)0x62E6934;
|
||||||
|
|
||||||
int* gameTypeCount = (int*)0x62E50A0;
|
int* gameTypeCount = (int*)0x62E50A0;
|
||||||
gameTypeName_t* gameTypes = (gameTypeName_t*)0x62E50A4;
|
gameTypeName_t* gameTypes = (gameTypeName_t*)0x62E50A4;
|
||||||
|
|
||||||
XBlock** g_streamBlocks = (XBlock**)0x16E554C;
|
XBlock** g_streamBlocks = (XBlock**)0x16E554C;
|
||||||
|
|
||||||
bool* g_lobbyCreateInProgress = (bool*)0x66C9BC2;
|
bool* g_lobbyCreateInProgress = (bool*)0x66C9BC2;
|
||||||
party_t** partyIngame = (party_t**)0x1081C00;
|
party_t** partyIngame = (party_t**)0x1081C00;
|
||||||
PartyData_s** partyData = (PartyData_s**)0x107E500;
|
PartyData_s** partyData = (PartyData_s**)0x107E500;
|
||||||
|
|
||||||
int* numIP = (int*)0x64A1E68;
|
int* numIP = (int*)0x64A1E68;
|
||||||
netIP_t* localIP = (netIP_t*)0x64A1E28;
|
netIP_t* localIP = (netIP_t*)0x64A1E28;
|
||||||
|
|
||||||
int* demoFile = (int*)0xA5EA1C;
|
int* demoFile = (int*)0xA5EA1C;
|
||||||
int* demoPlaying = (int*)0xA5EA0C;
|
int* demoPlaying = (int*)0xA5EA0C;
|
||||||
int* demoRecording = (int*)0xA5EA08;
|
int* demoRecording = (int*)0xA5EA08;
|
||||||
int* serverMessageSequence = (int*)0xA3E9B4;
|
int* serverMessageSequence = (int*)0xA3E9B4;
|
||||||
|
|
||||||
gentity_t* g_entities = (gentity_t*)0x18835D8;
|
gentity_t* g_entities = (gentity_t*)0x18835D8;
|
||||||
|
|
||||||
netadr_t* connectedHost = (netadr_t*)0xA1E888;
|
netadr_t* connectedHost = (netadr_t*)0xA1E888;
|
||||||
|
|
||||||
SOCKET* ip_socket = (SOCKET*)0x64A3008;
|
SOCKET* ip_socket = (SOCKET*)0x64A3008;
|
||||||
|
|
||||||
SafeArea* safeArea = (SafeArea*)0xA15F3C;
|
SafeArea* safeArea = (SafeArea*)0xA15F3C;
|
||||||
|
|
||||||
SpawnVar* spawnVars = (SpawnVar*)0x1A83DE8;
|
SpawnVar* spawnVars = (SpawnVar*)0x1A83DE8;
|
||||||
MapEnts** marMapEntsPtr = (MapEnts**)0x112AD34;
|
MapEnts** marMapEntsPtr = (MapEnts**)0x112AD34;
|
||||||
|
|
||||||
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize)
|
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize)
|
||||||
{
|
{
|
||||||
int elSize = DB_GetXAssetSizeHandlers[type]();
|
int elSize = DB_GetXAssetSizeHandlers[type]();
|
||||||
XAssetHeader poolEntry = { Utils::Memory::Allocate(newSize * elSize) };
|
XAssetHeader poolEntry = { Utils::Memory::Allocate(newSize * elSize) };
|
||||||
DB_XAssetPool[type] = poolEntry;
|
DB_XAssetPool[type] = poolEntry;
|
||||||
g_poolSize[type] = newSize;
|
g_poolSize[type] = newSize;
|
||||||
return poolEntry;
|
return poolEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu_FreeItemMemory(Game::itemDef_t* item)
|
void Menu_FreeItemMemory(Game::itemDef_t* item)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov edi, item
|
mov edi, item
|
||||||
mov eax, 63D880h
|
mov eax, 63D880h
|
||||||
call eax
|
call eax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* TableLookup(StringTable* stringtable, int row, int column)
|
const char* TableLookup(StringTable* stringtable, int row, int column)
|
||||||
{
|
{
|
||||||
if (!stringtable || !stringtable->values || row >= stringtable->rowCount || column >= stringtable->columnCount) return "";
|
if (!stringtable || !stringtable->values || row >= stringtable->rowCount || column >= stringtable->columnCount) return "";
|
||||||
|
|
||||||
const char* value = stringtable->values[row * stringtable->columnCount + column].string;
|
const char* value = stringtable->values[row * stringtable->columnCount + column].string;
|
||||||
if (!value) value = "";
|
if (!value) value = "";
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* UI_LocalizeMapName(const char* mapName)
|
const char* UI_LocalizeMapName(const char* mapName)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < *arenaCount; ++i)
|
for (int i = 0; i < *arenaCount; ++i)
|
||||||
{
|
{
|
||||||
if (!_stricmp(arenas[i].mapName, mapName))
|
if (!_stricmp(arenas[i].mapName, mapName))
|
||||||
{
|
{
|
||||||
char* uiName = &arenas[i].uiName[0];
|
char* uiName = &arenas[i].uiName[0];
|
||||||
if ((uiName[0] == 'M' && uiName[1] == 'P') || (uiName[0] == 'P' && uiName[1] == 'A')) // MPUI/PATCH
|
if ((uiName[0] == 'M' && uiName[1] == 'P') || (uiName[0] == 'P' && uiName[1] == 'A')) // MPUI/PATCH
|
||||||
{
|
{
|
||||||
return LocalizeMapString(uiName);
|
return LocalizeMapString(uiName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return uiName;
|
return uiName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapName;
|
return mapName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* UI_LocalizeGameType(const char* gameType)
|
const char* UI_LocalizeGameType(const char* gameType)
|
||||||
{
|
{
|
||||||
if (!gameType || !*gameType)
|
if (!gameType || !*gameType)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < *gameTypeCount; ++i)
|
for (int i = 0; i < *gameTypeCount; ++i)
|
||||||
{
|
{
|
||||||
if (!_stricmp(gameTypes[i].gameType, gameType))
|
if (!_stricmp(gameTypes[i].gameType, gameType))
|
||||||
{
|
{
|
||||||
return LocalizeMapString(gameTypes[i].uiName);
|
return LocalizeMapString(gameTypes[i].uiName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return gameType;
|
return gameType;
|
||||||
}
|
}
|
||||||
|
|
||||||
float UI_GetScoreboardLeft(void* a1)
|
float UI_GetScoreboardLeft(void* a1)
|
||||||
{
|
{
|
||||||
static int func = 0x590390;
|
static int func = 0x590390;
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, [esp + 4h]
|
mov eax, [esp + 4h]
|
||||||
call func
|
call func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DB_GetXAssetName(XAsset *asset)
|
const char *DB_GetXAssetName(XAsset *asset)
|
||||||
{
|
{
|
||||||
if (!asset) return "";
|
if (!asset) return "";
|
||||||
return DB_GetXAssetNameHandlers[asset->type](&asset->header);
|
return DB_GetXAssetNameHandlers[asset->type](&asset->header);
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetType DB_GetXAssetNameType(const char* name)
|
XAssetType DB_GetXAssetNameType(const char* name)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ASSET_TYPE_COUNT; ++i)
|
for (int i = 0; i < ASSET_TYPE_COUNT; ++i)
|
||||||
{
|
{
|
||||||
XAssetType type = static_cast<XAssetType>(i);
|
XAssetType type = static_cast<XAssetType>(i);
|
||||||
if (!_stricmp(DB_GetXAssetTypeName(type), name))
|
if (!_stricmp(DB_GetXAssetTypeName(type), name))
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ASSET_TYPE_INVALID;
|
return ASSET_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DB_IsZoneLoaded(const char* zone)
|
bool DB_IsZoneLoaded(const char* zone)
|
||||||
{
|
{
|
||||||
int zoneCount = Utils::Hook::Get<int>(0x1261BCC);
|
int zoneCount = Utils::Hook::Get<int>(0x1261BCC);
|
||||||
char* zoneIndices = reinterpret_cast<char*>(0x16B8A34);
|
char* zoneIndices = reinterpret_cast<char*>(0x16B8A34);
|
||||||
char* zoneData = reinterpret_cast<char*>(0x14C0F80);
|
char* zoneData = reinterpret_cast<char*>(0x14C0F80);
|
||||||
|
|
||||||
for (int i = 0; i < zoneCount; ++i)
|
for (int i = 0; i < zoneCount; ++i)
|
||||||
{
|
{
|
||||||
std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF);
|
std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF);
|
||||||
|
|
||||||
if (name == zone)
|
if (name == zone)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS_AddLocalizedGameDirectory(const char *path, const char *dir)
|
void FS_AddLocalizedGameDirectory(const char *path, const char *dir)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov ebx, path
|
mov ebx, path
|
||||||
mov eax, dir
|
mov eax, dir
|
||||||
mov ecx, 642EF0h
|
mov ecx, 642EF0h
|
||||||
call ecx
|
call ecx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBox(std::string message, std::string title)
|
void MessageBox(std::string message, std::string title)
|
||||||
{
|
{
|
||||||
Dvar_SetStringByName("com_errorMessage", message.data());
|
Dvar_SetStringByName("com_errorMessage", message.data());
|
||||||
Dvar_SetStringByName("com_errorTitle", title.data());
|
Dvar_SetStringByName("com_errorTitle", title.data());
|
||||||
Cbuf_AddText(0, "openmenu error_popmenu_lobby");
|
Cbuf_AddText(0, "openmenu error_popmenu_lobby");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int R_HashString(const char* string)
|
unsigned int R_HashString(const char* string)
|
||||||
{
|
{
|
||||||
unsigned int hash = 0;
|
unsigned int hash = 0;
|
||||||
|
|
||||||
while (*string)
|
while (*string)
|
||||||
{
|
{
|
||||||
hash = (*string | 0x20) ^ (33 * hash);
|
hash = (*string | 0x20) ^ (33 * hash);
|
||||||
++string;
|
++string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_KickClient(client_t* client, const char* reason)
|
void SV_KickClient(client_t* client, const char* reason)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push edi
|
push edi
|
||||||
push esi
|
push esi
|
||||||
mov edi, 0
|
mov edi, 0
|
||||||
mov esi, client
|
mov esi, client
|
||||||
push reason
|
push reason
|
||||||
push 0
|
push 0
|
||||||
push 0
|
push 0
|
||||||
mov eax, 6249A0h
|
mov eax, 6249A0h
|
||||||
call eax
|
call eax
|
||||||
add esp, 0Ch
|
add esp, 0Ch
|
||||||
pop esi
|
pop esi
|
||||||
pop edi
|
pop edi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_KickClientError(client_t* client, const char* reason)
|
void SV_KickClientError(client_t* client, std::string reason)
|
||||||
{
|
{
|
||||||
if (client->state < 5)
|
if (client->state < 5)
|
||||||
{
|
{
|
||||||
Components::Network::Send(client->addr, Utils::VA("error\n%s", reason));
|
Components::Network::Send(client->addr, fmt::sprintf("error\n%s", reason.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
SV_KickClient(client, reason);
|
SV_KickClient(client, reason.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,481 +1,481 @@
|
|||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* filename);
|
typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* filename);
|
||||||
extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj;
|
extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj;
|
||||||
|
|
||||||
typedef void(__cdecl * Cbuf_AddServerText_t)();
|
typedef void(__cdecl * Cbuf_AddServerText_t)();
|
||||||
extern Cbuf_AddServerText_t Cbuf_AddServerText;
|
extern Cbuf_AddServerText_t Cbuf_AddServerText;
|
||||||
|
|
||||||
typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char *text);
|
typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char *text);
|
||||||
extern Cbuf_AddText_t Cbuf_AddText;
|
extern Cbuf_AddText_t Cbuf_AddText;
|
||||||
|
|
||||||
typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size);
|
typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size);
|
||||||
extern CL_GetClientName_t CL_GetClientName;
|
extern CL_GetClientName_t CL_GetClientName;
|
||||||
|
|
||||||
typedef int(__cdecl * CL_IsCgameInitialized_t)();
|
typedef int(__cdecl * CL_IsCgameInitialized_t)();
|
||||||
extern CL_IsCgameInitialized_t CL_IsCgameInitialized;
|
extern CL_IsCgameInitialized_t CL_IsCgameInitialized;
|
||||||
|
|
||||||
typedef void(__cdecl * CL_ConnectFromParty_t)(int controllerIndex, _XSESSION_INFO *hostInfo, netadr_t addr, int numPublicSlots, int numPrivateSlots, const char *mapname, const char *gametype);
|
typedef void(__cdecl * CL_ConnectFromParty_t)(int controllerIndex, _XSESSION_INFO *hostInfo, netadr_t addr, int numPublicSlots, int numPrivateSlots, const char *mapname, const char *gametype);
|
||||||
extern CL_ConnectFromParty_t CL_ConnectFromParty;
|
extern CL_ConnectFromParty_t CL_ConnectFromParty;
|
||||||
|
|
||||||
typedef void(__cdecl * CL_DownloadsComplete_t)(int controller);
|
typedef void(__cdecl * CL_DownloadsComplete_t)(int controller);
|
||||||
extern CL_DownloadsComplete_t CL_DownloadsComplete;
|
extern CL_DownloadsComplete_t CL_DownloadsComplete;
|
||||||
|
|
||||||
typedef void(_cdecl * CL_DrawStretchPicPhysical_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material);
|
typedef void(_cdecl * CL_DrawStretchPicPhysical_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material);
|
||||||
extern CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical;
|
extern CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical;
|
||||||
|
|
||||||
typedef void(__cdecl * CL_ResetViewport_t)();
|
typedef void(__cdecl * CL_ResetViewport_t)();
|
||||||
extern CL_ResetViewport_t CL_ResetViewport;
|
extern CL_ResetViewport_t CL_ResetViewport;
|
||||||
|
|
||||||
typedef void(__cdecl * Cmd_AddCommand_t)(const char* name, void(*callback), cmd_function_t* data, char);
|
typedef void(__cdecl * Cmd_AddCommand_t)(const char* name, void(*callback), cmd_function_t* data, char);
|
||||||
extern Cmd_AddCommand_t Cmd_AddCommand;
|
extern Cmd_AddCommand_t Cmd_AddCommand;
|
||||||
|
|
||||||
typedef void(__cdecl * Cmd_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data);
|
typedef void(__cdecl * Cmd_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data);
|
||||||
extern Cmd_AddServerCommand_t Cmd_AddServerCommand;
|
extern Cmd_AddServerCommand_t Cmd_AddServerCommand;
|
||||||
|
|
||||||
typedef void(__cdecl * Cmd_ExecuteSingleCommand_t)(int localClientNum, int controllerIndex, const char* cmd);
|
typedef void(__cdecl * Cmd_ExecuteSingleCommand_t)(int localClientNum, int controllerIndex, const char* cmd);
|
||||||
extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand;
|
extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand;
|
||||||
|
|
||||||
typedef void(__cdecl * Com_Error_t)(int type, char* message, ...);
|
typedef void(__cdecl * Com_Error_t)(int type, char* message, ...);
|
||||||
extern Com_Error_t Com_Error;
|
extern Com_Error_t Com_Error;
|
||||||
|
|
||||||
typedef void(__cdecl * Com_Printf_t)(int channel, const char *fmt, ...);
|
typedef void(__cdecl * Com_Printf_t)(int channel, const char *fmt, ...);
|
||||||
extern Com_Printf_t Com_Printf;
|
extern Com_Printf_t Com_Printf;
|
||||||
|
|
||||||
typedef void(__cdecl * Com_PrintMessage_t)(int channel, const char *msg, int error);
|
typedef void(__cdecl * Com_PrintMessage_t)(int channel, const char *msg, int error);
|
||||||
extern Com_PrintMessage_t Com_PrintMessage;
|
extern Com_PrintMessage_t Com_PrintMessage;
|
||||||
|
|
||||||
typedef char* (__cdecl * Com_ParseExt_t)(const char **data_p);
|
typedef char* (__cdecl * Com_ParseExt_t)(const char **data_p);
|
||||||
extern Com_ParseExt_t Com_ParseExt;
|
extern Com_ParseExt_t Com_ParseExt;
|
||||||
|
|
||||||
typedef char* (__cdecl * Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha);
|
typedef char* (__cdecl * Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha);
|
||||||
extern Con_DrawMiniConsole_t Con_DrawMiniConsole;
|
extern Con_DrawMiniConsole_t Con_DrawMiniConsole;
|
||||||
|
|
||||||
typedef void (__cdecl * Con_DrawSolidConsole_t)();
|
typedef void (__cdecl * Con_DrawSolidConsole_t)();
|
||||||
extern Con_DrawSolidConsole_t Con_DrawSolidConsole;
|
extern Con_DrawSolidConsole_t Con_DrawSolidConsole;
|
||||||
|
|
||||||
typedef void(__cdecl * DB_EnumXAssets_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides);
|
typedef void(__cdecl * DB_EnumXAssets_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides);
|
||||||
extern DB_EnumXAssets_t DB_EnumXAssets;
|
extern DB_EnumXAssets_t DB_EnumXAssets;
|
||||||
|
|
||||||
typedef void(__cdecl * DB_EnumXAssets_Internal_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides);
|
typedef void(__cdecl * DB_EnumXAssets_Internal_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides);
|
||||||
extern DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal;
|
extern DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal;
|
||||||
|
|
||||||
typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* name);
|
typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* name);
|
||||||
extern DB_FindXAssetHeader_t DB_FindXAssetHeader;
|
extern DB_FindXAssetHeader_t DB_FindXAssetHeader;
|
||||||
|
|
||||||
typedef const char* (__cdecl * DB_GetXAssetNameHandler_t)(XAssetHeader* asset);
|
typedef const char* (__cdecl * DB_GetXAssetNameHandler_t)(XAssetHeader* asset);
|
||||||
extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers;
|
extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers;
|
||||||
|
|
||||||
typedef int(__cdecl * DB_GetXAssetSizeHandler_t)();
|
typedef int(__cdecl * DB_GetXAssetSizeHandler_t)();
|
||||||
extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers;
|
extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers;
|
||||||
|
|
||||||
typedef const char *(__cdecl * DB_GetXAssetTypeName_t)(XAssetType type);
|
typedef const char *(__cdecl * DB_GetXAssetTypeName_t)(XAssetType type);
|
||||||
extern DB_GetXAssetTypeName_t DB_GetXAssetTypeName;
|
extern DB_GetXAssetTypeName_t DB_GetXAssetTypeName;
|
||||||
|
|
||||||
typedef const char *(__cdecl * DB_IsXAssetDefault_t)(XAssetType type, const char* name);
|
typedef const char *(__cdecl * DB_IsXAssetDefault_t)(XAssetType type, const char* name);
|
||||||
extern DB_IsXAssetDefault_t DB_IsXAssetDefault;
|
extern DB_IsXAssetDefault_t DB_IsXAssetDefault;
|
||||||
|
|
||||||
typedef void(*DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
|
typedef void(*DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
|
||||||
extern DB_LoadXAssets_t DB_LoadXAssets;
|
extern DB_LoadXAssets_t DB_LoadXAssets;
|
||||||
|
|
||||||
typedef void(__cdecl * DB_ReadXFileUncompressed_t)(void* buffer, int size);
|
typedef void(__cdecl * DB_ReadXFileUncompressed_t)(void* buffer, int size);
|
||||||
extern DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed;
|
extern DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterBool_t)(const char* name, bool default, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterBool_t)(const char* name, bool default, int flags, const char* description);
|
||||||
extern Dvar_RegisterBool_t Dvar_RegisterBool;
|
extern Dvar_RegisterBool_t Dvar_RegisterBool;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterFloat_t)(const char* name, float default, float min, float max, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterFloat_t)(const char* name, float default, float min, float max, int flags, const char* description);
|
||||||
extern Dvar_RegisterFloat_t Dvar_RegisterFloat;
|
extern Dvar_RegisterFloat_t Dvar_RegisterFloat;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterVec2_t)(const char* name, float defx, float defy, float min, float max, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterVec2_t)(const char* name, float defx, float defy, float min, float max, int flags, const char* description);
|
||||||
extern Dvar_RegisterVec2_t Dvar_RegisterVec2;
|
extern Dvar_RegisterVec2_t Dvar_RegisterVec2;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterVec3_t)(const char* name, float defx, float defy, float defz, float min, float max, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterVec3_t)(const char* name, float defx, float defy, float defz, float min, float max, int flags, const char* description);
|
||||||
extern Dvar_RegisterVec3_t Dvar_RegisterVec3;
|
extern Dvar_RegisterVec3_t Dvar_RegisterVec3;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterVec4_t)(const char* name, float defx, float defy, float defz, float defw, float min, float max, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterVec4_t)(const char* name, float defx, float defy, float defz, float defw, float min, float max, int flags, const char* description);
|
||||||
extern Dvar_RegisterVec4_t Dvar_RegisterVec4;
|
extern Dvar_RegisterVec4_t Dvar_RegisterVec4;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterInt_t)(const char* name, int default, int min, int max, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterInt_t)(const char* name, int default, int min, int max, int flags, const char* description);
|
||||||
extern Dvar_RegisterInt_t Dvar_RegisterInt;
|
extern Dvar_RegisterInt_t Dvar_RegisterInt;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterEnum_t)(const char* name, char** enumValues, int default, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterEnum_t)(const char* name, char** enumValues, int default, int flags, const char* description);
|
||||||
extern Dvar_RegisterEnum_t Dvar_RegisterEnum;
|
extern Dvar_RegisterEnum_t Dvar_RegisterEnum;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterString_t)(const char* name, const char* default, int, const char*);
|
typedef dvar_t* (__cdecl * Dvar_RegisterString_t)(const char* name, const char* default, int, const char*);
|
||||||
extern Dvar_RegisterString_t Dvar_RegisterString;
|
extern Dvar_RegisterString_t Dvar_RegisterString;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_RegisterColor_t)(const char* name, float r, float g, float b, float a, int flags, const char* description);
|
typedef dvar_t* (__cdecl * Dvar_RegisterColor_t)(const char* name, float r, float g, float b, float a, int flags, const char* description);
|
||||||
extern Dvar_RegisterColor_t Dvar_RegisterColor;
|
extern Dvar_RegisterColor_t Dvar_RegisterColor;
|
||||||
|
|
||||||
typedef void(__cdecl * Dvar_GetUnpackedColorByName_t)(const char* name, float* color);
|
typedef void(__cdecl * Dvar_GetUnpackedColorByName_t)(const char* name, float* color);
|
||||||
extern Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName;
|
extern Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_FindVar_t)(const char *dvarName);
|
typedef dvar_t* (__cdecl * Dvar_FindVar_t)(const char *dvarName);
|
||||||
extern Dvar_FindVar_t Dvar_FindVar;
|
extern Dvar_FindVar_t Dvar_FindVar;
|
||||||
|
|
||||||
typedef char* (__cdecl* Dvar_InfoString_Big_t)(int typeMask);
|
typedef char* (__cdecl* Dvar_InfoString_Big_t)(int typeMask);
|
||||||
extern Dvar_InfoString_Big_t Dvar_InfoString_Big;
|
extern Dvar_InfoString_Big_t Dvar_InfoString_Big;
|
||||||
|
|
||||||
typedef dvar_t* (__cdecl * Dvar_SetCommand_t)(const char* name, const char* value);
|
typedef dvar_t* (__cdecl * Dvar_SetCommand_t)(const char* name, const char* value);
|
||||||
extern Dvar_SetCommand_t Dvar_SetCommand;
|
extern Dvar_SetCommand_t Dvar_SetCommand;
|
||||||
|
|
||||||
typedef void(__cdecl * Field_Clear_t)(void* field);
|
typedef void(__cdecl * Field_Clear_t)(void* field);
|
||||||
extern Field_Clear_t Field_Clear;
|
extern Field_Clear_t Field_Clear;
|
||||||
|
|
||||||
typedef void(__cdecl * FreeMemory_t)(void* buffer);
|
typedef void(__cdecl * FreeMemory_t)(void* buffer);
|
||||||
extern FreeMemory_t FreeMemory;
|
extern FreeMemory_t FreeMemory;
|
||||||
|
|
||||||
typedef void(__cdecl * FS_FreeFile_t)(void* buffer);
|
typedef void(__cdecl * FS_FreeFile_t)(void* buffer);
|
||||||
extern FS_FreeFile_t FS_FreeFile;
|
extern FS_FreeFile_t FS_FreeFile;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer);
|
typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer);
|
||||||
extern FS_ReadFile_t FS_ReadFile;
|
extern FS_ReadFile_t FS_ReadFile;
|
||||||
|
|
||||||
typedef char** (__cdecl * FS_GetFileList_t)(const char *path, const char *extension, FsListBehavior_e behavior, int *numfiles, int allocTrackType);
|
typedef char** (__cdecl * FS_GetFileList_t)(const char *path, const char *extension, FsListBehavior_e behavior, int *numfiles, int allocTrackType);
|
||||||
extern FS_GetFileList_t FS_GetFileList;
|
extern FS_GetFileList_t FS_GetFileList;
|
||||||
|
|
||||||
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
|
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
|
||||||
extern FS_FreeFileList_t FS_FreeFileList;
|
extern FS_FreeFileList_t FS_FreeFileList;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FOpenFileAppend_t)(const char* file);
|
typedef int(__cdecl * FS_FOpenFileAppend_t)(const char* file);
|
||||||
extern FS_FOpenFileAppend_t FS_FOpenFileAppend;
|
extern FS_FOpenFileAppend_t FS_FOpenFileAppend;
|
||||||
extern FS_FOpenFileAppend_t FS_FOpenFileWrite;
|
extern FS_FOpenFileAppend_t FS_FOpenFileWrite;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FOpenFileRead_t)(const char* file, int* fh, int uniqueFile);
|
typedef int(__cdecl * FS_FOpenFileRead_t)(const char* file, int* fh, int uniqueFile);
|
||||||
extern FS_FOpenFileRead_t FS_FOpenFileRead;
|
extern FS_FOpenFileRead_t FS_FOpenFileRead;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FOpenFileReadForThread_t)(const char *filename, int *file, int thread);
|
typedef int(__cdecl * FS_FOpenFileReadForThread_t)(const char *filename, int *file, int thread);
|
||||||
extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread;
|
extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FCloseFile_t)(int fh);
|
typedef int(__cdecl * FS_FCloseFile_t)(int fh);
|
||||||
extern FS_FCloseFile_t FS_FCloseFile;
|
extern FS_FCloseFile_t FS_FCloseFile;
|
||||||
|
|
||||||
typedef bool(__cdecl * FS_FileExists_t)(const char* file);
|
typedef bool(__cdecl * FS_FileExists_t)(const char* file);
|
||||||
extern FS_FileExists_t FS_FileExists;
|
extern FS_FileExists_t FS_FileExists;
|
||||||
|
|
||||||
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
|
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
|
||||||
extern FS_WriteFile_t FS_WriteFile;
|
extern FS_WriteFile_t FS_WriteFile;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file);
|
typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file);
|
||||||
extern FS_Write_t FS_Write;
|
extern FS_Write_t FS_Write;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
|
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
|
||||||
extern FS_Read_t FS_Read;
|
extern FS_Read_t FS_Read;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Seek_t)(int fileHandle, int seekPosition, int seekOrigin);
|
typedef int(__cdecl * FS_Seek_t)(int fileHandle, int seekPosition, int seekOrigin);
|
||||||
extern FS_Seek_t FS_Seek;
|
extern FS_Seek_t FS_Seek;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FTell_t)(int fileHandle);
|
typedef int(__cdecl * FS_FTell_t)(int fileHandle);
|
||||||
extern FS_FTell_t FS_FTell;
|
extern FS_FTell_t FS_FTell;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Remove_t)(char *);
|
typedef int(__cdecl * FS_Remove_t)(char *);
|
||||||
extern FS_Remove_t FS_Remove;
|
extern FS_Remove_t FS_Remove;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Restart_t)(int localClientNum, int checksumFeed);
|
typedef int(__cdecl * FS_Restart_t)(int localClientNum, int checksumFeed);
|
||||||
extern FS_Restart_t FS_Restart;
|
extern FS_Restart_t FS_Restart;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**);
|
typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**);
|
||||||
extern FS_BuildPathToFile_t FS_BuildPathToFile;
|
extern FS_BuildPathToFile_t FS_BuildPathToFile;
|
||||||
|
|
||||||
typedef void(__cdecl* G_SpawnEntitiesFromString_t)();
|
typedef void(__cdecl* G_SpawnEntitiesFromString_t)();
|
||||||
extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString;
|
extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString;
|
||||||
|
|
||||||
typedef void(__cdecl * GScr_LoadGameTypeScript_t)();
|
typedef void(__cdecl * GScr_LoadGameTypeScript_t)();
|
||||||
extern GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript;
|
extern GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript;
|
||||||
|
|
||||||
typedef int(__cdecl * Reader_t)(char const*, int *);
|
typedef int(__cdecl * Reader_t)(char const*, int *);
|
||||||
typedef bool(__cdecl * Image_LoadFromFileWithReader_t)(GfxImage* image, Reader_t reader);
|
typedef bool(__cdecl * Image_LoadFromFileWithReader_t)(GfxImage* image, Reader_t reader);
|
||||||
extern Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader;
|
extern Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader;
|
||||||
|
|
||||||
typedef void(__cdecl * Image_Release_t)(GfxImage* image);
|
typedef void(__cdecl * Image_Release_t)(GfxImage* image);
|
||||||
extern Image_Release_t Image_Release;
|
extern Image_Release_t Image_Release;
|
||||||
|
|
||||||
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
|
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
|
||||||
extern Menus_CloseAll_t Menus_CloseAll;
|
extern Menus_CloseAll_t Menus_CloseAll;
|
||||||
|
|
||||||
typedef int(__cdecl * Menus_OpenByName_t)(UiContext *dc, const char *p);
|
typedef int(__cdecl * Menus_OpenByName_t)(UiContext *dc, const char *p);
|
||||||
extern Menus_OpenByName_t Menus_OpenByName;
|
extern Menus_OpenByName_t Menus_OpenByName;
|
||||||
|
|
||||||
typedef menuDef_t *(__cdecl * Menus_FindByName_t)(UiContext *dc, const char *name);
|
typedef menuDef_t *(__cdecl * Menus_FindByName_t)(UiContext *dc, const char *name);
|
||||||
extern Menus_FindByName_t Menus_FindByName;
|
extern Menus_FindByName_t Menus_FindByName;
|
||||||
|
|
||||||
typedef bool(__cdecl * Menu_IsVisible_t)(UiContext *dc, menuDef_t *menu);
|
typedef bool(__cdecl * Menu_IsVisible_t)(UiContext *dc, menuDef_t *menu);
|
||||||
extern Menu_IsVisible_t Menu_IsVisible;
|
extern Menu_IsVisible_t Menu_IsVisible;
|
||||||
|
|
||||||
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu);
|
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu);
|
||||||
extern Menus_MenuIsInStack_t Menus_MenuIsInStack;
|
extern Menus_MenuIsInStack_t Menus_MenuIsInStack;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
||||||
extern MSG_Init_t MSG_Init;
|
extern MSG_Init_t MSG_Init;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_ReadData_t)(msg_t *msg, void *data, int len);
|
typedef void(__cdecl * MSG_ReadData_t)(msg_t *msg, void *data, int len);
|
||||||
extern MSG_ReadData_t MSG_ReadData;
|
extern MSG_ReadData_t MSG_ReadData;
|
||||||
|
|
||||||
typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg);
|
typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg);
|
||||||
extern MSG_ReadLong_t MSG_ReadLong;
|
extern MSG_ReadLong_t MSG_ReadLong;
|
||||||
|
|
||||||
typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg);
|
typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg);
|
||||||
extern MSG_ReadShort_t MSG_ReadShort;
|
extern MSG_ReadShort_t MSG_ReadShort;
|
||||||
|
|
||||||
typedef __int64(__cdecl * MSG_ReadInt64_t)(msg_t* msg);
|
typedef __int64(__cdecl * MSG_ReadInt64_t)(msg_t* msg);
|
||||||
extern MSG_ReadInt64_t MSG_ReadInt64;
|
extern MSG_ReadInt64_t MSG_ReadInt64;
|
||||||
|
|
||||||
typedef char* (__cdecl * MSG_ReadString_t)(msg_t* msg);
|
typedef char* (__cdecl * MSG_ReadString_t)(msg_t* msg);
|
||||||
extern MSG_ReadString_t MSG_ReadString;
|
extern MSG_ReadString_t MSG_ReadString;
|
||||||
|
|
||||||
typedef int(__cdecl * MSG_ReadByte_t)(msg_t* msg);
|
typedef int(__cdecl * MSG_ReadByte_t)(msg_t* msg);
|
||||||
extern MSG_ReadByte_t MSG_ReadByte;
|
extern MSG_ReadByte_t MSG_ReadByte;
|
||||||
|
|
||||||
typedef int(__cdecl * MSG_ReadBitsCompress_t)(const char *from, char *to, int size);
|
typedef int(__cdecl * MSG_ReadBitsCompress_t)(const char *from, char *to, int size);
|
||||||
extern MSG_ReadBitsCompress_t MSG_ReadBitsCompress;
|
extern MSG_ReadBitsCompress_t MSG_ReadBitsCompress;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_WriteByte_t)(msg_t* msg, unsigned char c);
|
typedef void(__cdecl * MSG_WriteByte_t)(msg_t* msg, unsigned char c);
|
||||||
extern MSG_WriteByte_t MSG_WriteByte;
|
extern MSG_WriteByte_t MSG_WriteByte;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_WriteData_t)(msg_t *buf, const void *data, int length);
|
typedef void(__cdecl * MSG_WriteData_t)(msg_t *buf, const void *data, int length);
|
||||||
extern MSG_WriteData_t MSG_WriteData;
|
extern MSG_WriteData_t MSG_WriteData;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_WriteLong_t)(msg_t *msg, int c);
|
typedef void(__cdecl * MSG_WriteLong_t)(msg_t *msg, int c);
|
||||||
extern MSG_WriteLong_t MSG_WriteLong;
|
extern MSG_WriteLong_t MSG_WriteLong;
|
||||||
|
|
||||||
typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size);
|
typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size);
|
||||||
extern MSG_WriteBitsCompress_t MSG_WriteBitsCompress;
|
extern MSG_WriteBitsCompress_t MSG_WriteBitsCompress;
|
||||||
|
|
||||||
typedef void(__cdecl * NetadrToSockadr_t)(netadr_t *a, sockaddr *s);
|
typedef void(__cdecl * NetadrToSockadr_t)(netadr_t *a, sockaddr *s);
|
||||||
extern NetadrToSockadr_t NetadrToSockadr;
|
extern NetadrToSockadr_t NetadrToSockadr;
|
||||||
|
|
||||||
typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr);
|
typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr);
|
||||||
extern NET_AdrToString_t NET_AdrToString;
|
extern NET_AdrToString_t NET_AdrToString;
|
||||||
|
|
||||||
typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
||||||
extern NET_CompareAdr_t NET_CompareAdr;
|
extern NET_CompareAdr_t NET_CompareAdr;
|
||||||
|
|
||||||
typedef bool(__cdecl * NET_IsLocalAddress_t)(netadr_t adr);
|
typedef bool(__cdecl * NET_IsLocalAddress_t)(netadr_t adr);
|
||||||
extern NET_IsLocalAddress_t NET_IsLocalAddress;
|
extern NET_IsLocalAddress_t NET_IsLocalAddress;
|
||||||
|
|
||||||
typedef bool(__cdecl * NET_StringToAdr_t)(const char *s, netadr_t *a);
|
typedef bool(__cdecl * NET_StringToAdr_t)(const char *s, netadr_t *a);
|
||||||
extern NET_StringToAdr_t NET_StringToAdr;
|
extern NET_StringToAdr_t NET_StringToAdr;
|
||||||
|
|
||||||
typedef void(__cdecl* NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char *data);
|
typedef void(__cdecl* NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char *data);
|
||||||
extern NET_OutOfBandPrint_t NET_OutOfBandPrint;
|
extern NET_OutOfBandPrint_t NET_OutOfBandPrint;
|
||||||
|
|
||||||
typedef void(__cdecl* NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char *format, int len);
|
typedef void(__cdecl* NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char *format, int len);
|
||||||
extern NET_OutOfBandData_t NET_OutOfBandData;
|
extern NET_OutOfBandData_t NET_OutOfBandData;
|
||||||
|
|
||||||
typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite);
|
typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite);
|
||||||
extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
|
extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
|
||||||
|
|
||||||
typedef void(__cdecl * Live_ParsePlaylists_t)(const char* data);
|
typedef void(__cdecl * Live_ParsePlaylists_t)(const char* data);
|
||||||
extern Live_ParsePlaylists_t Live_ParsePlaylists;
|
extern Live_ParsePlaylists_t Live_ParsePlaylists;
|
||||||
|
|
||||||
typedef void* (__cdecl * LoadModdableRawfile_t)(int a1, const char* filename);
|
typedef void* (__cdecl * LoadModdableRawfile_t)(int a1, const char* filename);
|
||||||
extern LoadModdableRawfile_t LoadModdableRawfile;
|
extern LoadModdableRawfile_t LoadModdableRawfile;
|
||||||
|
|
||||||
typedef char* (__cdecl * LocalizeString_t)(char*, char*);
|
typedef char* (__cdecl * LocalizeString_t)(char*, char*);
|
||||||
extern LocalizeString_t LocalizeString;
|
extern LocalizeString_t LocalizeString;
|
||||||
|
|
||||||
typedef char* (__cdecl * LocalizeMapString_t)(char*);
|
typedef char* (__cdecl * LocalizeMapString_t)(char*);
|
||||||
extern LocalizeMapString_t LocalizeMapString;
|
extern LocalizeMapString_t LocalizeMapString;
|
||||||
|
|
||||||
typedef int(__cdecl * PC_ReadToken_t)(source_t*, token_t*);
|
typedef int(__cdecl * PC_ReadToken_t)(source_t*, token_t*);
|
||||||
extern PC_ReadToken_t PC_ReadToken;
|
extern PC_ReadToken_t PC_ReadToken;
|
||||||
|
|
||||||
typedef int(__cdecl * PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token);
|
typedef int(__cdecl * PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token);
|
||||||
extern PC_ReadTokenHandle_t PC_ReadTokenHandle;
|
extern PC_ReadTokenHandle_t PC_ReadTokenHandle;
|
||||||
|
|
||||||
typedef void(__cdecl * PC_SourceError_t)(int, const char*, ...);
|
typedef void(__cdecl * PC_SourceError_t)(int, const char*, ...);
|
||||||
extern PC_SourceError_t PC_SourceError;
|
extern PC_SourceError_t PC_SourceError;
|
||||||
|
|
||||||
typedef int(__cdecl * Party_GetMaxPlayers_t)(party_s* party);
|
typedef int(__cdecl * Party_GetMaxPlayers_t)(party_s* party);
|
||||||
extern Party_GetMaxPlayers_t Party_GetMaxPlayers;
|
extern Party_GetMaxPlayers_t Party_GetMaxPlayers;
|
||||||
|
|
||||||
typedef int(__cdecl * PartyHost_CountMembers_t)(PartyData_s* party);
|
typedef int(__cdecl * PartyHost_CountMembers_t)(PartyData_s* party);
|
||||||
extern PartyHost_CountMembers_t PartyHost_CountMembers;
|
extern PartyHost_CountMembers_t PartyHost_CountMembers;
|
||||||
|
|
||||||
typedef netadr_t *(__cdecl * PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot);
|
typedef netadr_t *(__cdecl * PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot);
|
||||||
extern PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot;
|
extern PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot;
|
||||||
|
|
||||||
typedef const char *(__cdecl * PartyHost_GetMemberName_t)(PartyData_s* party, const int clientNum);
|
typedef const char *(__cdecl * PartyHost_GetMemberName_t)(PartyData_s* party, const int clientNum);
|
||||||
extern PartyHost_GetMemberName_t PartyHost_GetMemberName;
|
extern PartyHost_GetMemberName_t PartyHost_GetMemberName;
|
||||||
|
|
||||||
typedef Font* (__cdecl * R_RegisterFont_t)(const char* asset);
|
typedef Font* (__cdecl * R_RegisterFont_t)(const char* asset);
|
||||||
extern R_RegisterFont_t R_RegisterFont;
|
extern R_RegisterFont_t R_RegisterFont;
|
||||||
|
|
||||||
typedef void(__cdecl * R_AddCmdDrawText_t)(const char *text, int maxChars, Font *font, float x, float y, float xScale, float yScale, float rotation, const float *color, int style);
|
typedef void(__cdecl * R_AddCmdDrawText_t)(const char *text, int maxChars, Font *font, float x, float y, float xScale, float yScale, float rotation, const float *color, int style);
|
||||||
extern R_AddCmdDrawText_t R_AddCmdDrawText;
|
extern R_AddCmdDrawText_t R_AddCmdDrawText;
|
||||||
|
|
||||||
typedef void(_cdecl * R_AddCmdDrawStretchPic_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material);
|
typedef void(_cdecl * R_AddCmdDrawStretchPic_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material);
|
||||||
extern R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic;
|
extern R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic;
|
||||||
|
|
||||||
typedef void(__cdecl * R_LoadGraphicsAssets_t)();
|
typedef void(__cdecl * R_LoadGraphicsAssets_t)();
|
||||||
extern R_LoadGraphicsAssets_t R_LoadGraphicsAssets;
|
extern R_LoadGraphicsAssets_t R_LoadGraphicsAssets;
|
||||||
|
|
||||||
typedef int(__cdecl * R_TextWidth_t)(const char* text, int maxlength, Font* font);
|
typedef int(__cdecl * R_TextWidth_t)(const char* text, int maxlength, Font* font);
|
||||||
extern R_TextWidth_t R_TextWidth;
|
extern R_TextWidth_t R_TextWidth;
|
||||||
|
|
||||||
typedef int(__cdecl * R_TextHeight_t)(Font* font);
|
typedef int(__cdecl * R_TextHeight_t)(Font* font);
|
||||||
extern R_TextHeight_t R_TextHeight;
|
extern R_TextHeight_t R_TextHeight;
|
||||||
|
|
||||||
typedef void(__cdecl * Scr_ShutdownAllocNode_t)();
|
typedef void(__cdecl * Scr_ShutdownAllocNode_t)();
|
||||||
extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode;
|
extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode;
|
||||||
|
|
||||||
typedef int(__cdecl * Scr_LoadGameType_t)();
|
typedef int(__cdecl * Scr_LoadGameType_t)();
|
||||||
extern Scr_LoadGameType_t Scr_LoadGameType;
|
extern Scr_LoadGameType_t Scr_LoadGameType;
|
||||||
|
|
||||||
typedef int(__cdecl * Scr_LoadScript_t)(const char*);
|
typedef int(__cdecl * Scr_LoadScript_t)(const char*);
|
||||||
extern Scr_LoadScript_t Scr_LoadScript;
|
extern Scr_LoadScript_t Scr_LoadScript;
|
||||||
|
|
||||||
typedef int(__cdecl * Scr_GetFunctionHandle_t)(const char*, const char*);
|
typedef int(__cdecl * Scr_GetFunctionHandle_t)(const char*, const char*);
|
||||||
extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle;
|
extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle;
|
||||||
|
|
||||||
typedef int(__cdecl * Scr_ExecThread_t)(int, int);
|
typedef int(__cdecl * Scr_ExecThread_t)(int, int);
|
||||||
extern Scr_ExecThread_t Scr_ExecThread;
|
extern Scr_ExecThread_t Scr_ExecThread;
|
||||||
|
|
||||||
typedef int(__cdecl * Scr_FreeThread_t)(int);
|
typedef int(__cdecl * Scr_FreeThread_t)(int);
|
||||||
extern Scr_FreeThread_t Scr_FreeThread;
|
extern Scr_FreeThread_t Scr_FreeThread;
|
||||||
|
|
||||||
typedef script_t* (__cdecl * Script_Alloc_t)(int length);
|
typedef script_t* (__cdecl * Script_Alloc_t)(int length);
|
||||||
extern Script_Alloc_t Script_Alloc;
|
extern Script_Alloc_t Script_Alloc;
|
||||||
|
|
||||||
typedef void(__cdecl * Script_SetupTokens_t)(script_t* script, void* tokens);
|
typedef void(__cdecl * Script_SetupTokens_t)(script_t* script, void* tokens);
|
||||||
extern Script_SetupTokens_t Script_SetupTokens;
|
extern Script_SetupTokens_t Script_SetupTokens;
|
||||||
|
|
||||||
typedef int(__cdecl * Script_CleanString_t)(char* buffer);
|
typedef int(__cdecl * Script_CleanString_t)(char* buffer);
|
||||||
extern Script_CleanString_t Script_CleanString;
|
extern Script_CleanString_t Script_CleanString;
|
||||||
|
|
||||||
typedef char* (__cdecl * SE_Load_t)(char* file, int Unk);
|
typedef char* (__cdecl * SE_Load_t)(char* file, int Unk);
|
||||||
extern SE_Load_t SE_Load;
|
extern SE_Load_t SE_Load;
|
||||||
|
|
||||||
typedef void(__cdecl * Dvar_SetStringByName_t)(const char* cvar, const char* value);
|
typedef void(__cdecl * Dvar_SetStringByName_t)(const char* cvar, const char* value);
|
||||||
extern Dvar_SetStringByName_t Dvar_SetStringByName;
|
extern Dvar_SetStringByName_t Dvar_SetStringByName;
|
||||||
|
|
||||||
typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue);
|
typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue);
|
||||||
extern SL_ConvertToString_t SL_ConvertToString;
|
extern SL_ConvertToString_t SL_ConvertToString;
|
||||||
|
|
||||||
typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user);
|
typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user);
|
||||||
extern SL_GetString_t SL_GetString;
|
extern SL_GetString_t SL_GetString;
|
||||||
|
|
||||||
typedef void(__cdecl * SND_InitDriver_t)();
|
typedef void(__cdecl * SND_InitDriver_t)();
|
||||||
extern SND_InitDriver_t SND_InitDriver;
|
extern SND_InitDriver_t SND_InitDriver;
|
||||||
|
|
||||||
typedef void(__cdecl * SockadrToNetadr_t)(sockaddr *s, netadr_t *a);
|
typedef void(__cdecl * SockadrToNetadr_t)(sockaddr *s, netadr_t *a);
|
||||||
extern SockadrToNetadr_t SockadrToNetadr;
|
extern SockadrToNetadr_t SockadrToNetadr;
|
||||||
|
|
||||||
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
|
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
|
||||||
extern Steam_JoinLobby_t Steam_JoinLobby;
|
extern Steam_JoinLobby_t Steam_JoinLobby;
|
||||||
|
|
||||||
typedef int(__cdecl* SV_GameClientNum_Score_t)(int clientID);
|
typedef int(__cdecl* SV_GameClientNum_Score_t)(int clientID);
|
||||||
extern SV_GameClientNum_Score_t SV_GameClientNum_Score;
|
extern SV_GameClientNum_Score_t SV_GameClientNum_Score;
|
||||||
|
|
||||||
typedef void(__cdecl * SV_GameSendServerCommand_t)(int clientNum, /*svscmd_type*/int type, const char* text);
|
typedef void(__cdecl * SV_GameSendServerCommand_t)(int clientNum, /*svscmd_type*/int type, const char* text);
|
||||||
extern SV_GameSendServerCommand_t SV_GameSendServerCommand;
|
extern SV_GameSendServerCommand_t SV_GameSendServerCommand;
|
||||||
|
|
||||||
typedef FS_FreeFileList_t Sys_FreeFileList_t;
|
typedef FS_FreeFileList_t Sys_FreeFileList_t;
|
||||||
extern Sys_FreeFileList_t Sys_FreeFileList;
|
extern Sys_FreeFileList_t Sys_FreeFileList;
|
||||||
|
|
||||||
typedef bool(__cdecl * Sys_IsMainThread_t)();
|
typedef bool(__cdecl * Sys_IsMainThread_t)();
|
||||||
extern Sys_IsMainThread_t Sys_IsMainThread;
|
extern Sys_IsMainThread_t Sys_IsMainThread;
|
||||||
|
|
||||||
typedef char** (__cdecl * Sys_ListFiles_t)(const char *directory, const char *extension, const char *filter, int *numfiles, int wantsubs);
|
typedef char** (__cdecl * Sys_ListFiles_t)(const char *directory, const char *extension, const char *filter, int *numfiles, int wantsubs);
|
||||||
extern Sys_ListFiles_t Sys_ListFiles;
|
extern Sys_ListFiles_t Sys_ListFiles;
|
||||||
|
|
||||||
typedef int(__cdecl * Sys_Milliseconds_t)();
|
typedef int(__cdecl * Sys_Milliseconds_t)();
|
||||||
extern Sys_Milliseconds_t Sys_Milliseconds;
|
extern Sys_Milliseconds_t Sys_Milliseconds;
|
||||||
|
|
||||||
typedef bool(__cdecl * Sys_SendPacket_t)(netsrc_t sock, size_t len, const char *format, netadr_t adr);
|
typedef bool(__cdecl * Sys_SendPacket_t)(netsrc_t sock, size_t len, const char *format, netadr_t adr);
|
||||||
extern Sys_SendPacket_t Sys_SendPacket;
|
extern Sys_SendPacket_t Sys_SendPacket;
|
||||||
|
|
||||||
typedef void(__cdecl * Sys_ShowConsole_t)();
|
typedef void(__cdecl * Sys_ShowConsole_t)();
|
||||||
extern Sys_ShowConsole_t Sys_ShowConsole;
|
extern Sys_ShowConsole_t Sys_ShowConsole;
|
||||||
|
|
||||||
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
|
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
|
||||||
extern UI_AddMenuList_t UI_AddMenuList;
|
extern UI_AddMenuList_t UI_AddMenuList;
|
||||||
|
|
||||||
typedef MenuList *(__cdecl * UI_LoadMenus_t)(const char *menuFile, int imageTrack);
|
typedef MenuList *(__cdecl * UI_LoadMenus_t)(const char *menuFile, int imageTrack);
|
||||||
extern UI_LoadMenus_t UI_LoadMenus;
|
extern UI_LoadMenus_t UI_LoadMenus;
|
||||||
|
|
||||||
typedef void(__cdecl * UI_DrawHandlePic_t)(/*ScreenPlacement*/void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Material *material);
|
typedef void(__cdecl * UI_DrawHandlePic_t)(/*ScreenPlacement*/void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Material *material);
|
||||||
extern UI_DrawHandlePic_t UI_DrawHandlePic;
|
extern UI_DrawHandlePic_t UI_DrawHandlePic;
|
||||||
|
|
||||||
typedef void* (__cdecl * UI_GetContext_t)(void*);
|
typedef void* (__cdecl * UI_GetContext_t)(void*);
|
||||||
extern UI_GetContext_t UI_GetContext;
|
extern UI_GetContext_t UI_GetContext;
|
||||||
|
|
||||||
typedef int(__cdecl * UI_TextWidth_t)(const char *text, int maxChars, Font *font, float scale);
|
typedef int(__cdecl * UI_TextWidth_t)(const char *text, int maxChars, Font *font, float scale);
|
||||||
extern UI_TextWidth_t UI_TextWidth;
|
extern UI_TextWidth_t UI_TextWidth;
|
||||||
|
|
||||||
typedef void(__cdecl * UI_DrawText_t)(void* scrPlace, const char *text, int maxChars, Font *font, float x, float y, int horzAlign, int vertAlign, float scale, const float *color, int style);
|
typedef void(__cdecl * UI_DrawText_t)(void* scrPlace, const char *text, int maxChars, Font *font, float x, float y, int horzAlign, int vertAlign, float scale, const float *color, int style);
|
||||||
extern UI_DrawText_t UI_DrawText;
|
extern UI_DrawText_t UI_DrawText;
|
||||||
|
|
||||||
typedef const char * (__cdecl * Win_GetLanguage_t)();
|
typedef const char * (__cdecl * Win_GetLanguage_t)();
|
||||||
extern Win_GetLanguage_t Win_GetLanguage;
|
extern Win_GetLanguage_t Win_GetLanguage;
|
||||||
|
|
||||||
extern XAssetHeader* DB_XAssetPool;
|
extern XAssetHeader* DB_XAssetPool;
|
||||||
extern unsigned int* g_poolSize;
|
extern unsigned int* g_poolSize;
|
||||||
|
|
||||||
extern DWORD* cmd_id;
|
extern DWORD* cmd_id;
|
||||||
extern DWORD* cmd_argc;
|
extern DWORD* cmd_argc;
|
||||||
extern char*** cmd_argv;
|
extern char*** cmd_argv;
|
||||||
|
|
||||||
extern DWORD* cmd_id_sv;
|
extern DWORD* cmd_id_sv;
|
||||||
extern DWORD* cmd_argc_sv;
|
extern DWORD* cmd_argc_sv;
|
||||||
extern char*** cmd_argv_sv;
|
extern char*** cmd_argv_sv;
|
||||||
|
|
||||||
extern int* svs_numclients;
|
extern int* svs_numclients;
|
||||||
extern client_t* svs_clients;
|
extern client_t* svs_clients;
|
||||||
|
|
||||||
extern source_t **sourceFiles;
|
extern source_t **sourceFiles;
|
||||||
extern keywordHash_t **menuParseKeywordHash;
|
extern keywordHash_t **menuParseKeywordHash;
|
||||||
|
|
||||||
extern UiContext *uiContext;
|
extern UiContext *uiContext;
|
||||||
|
|
||||||
extern int* arenaCount;
|
extern int* arenaCount;
|
||||||
extern mapArena_t* arenas;
|
extern mapArena_t* arenas;
|
||||||
|
|
||||||
extern int* gameTypeCount;
|
extern int* gameTypeCount;
|
||||||
extern gameTypeName_t* gameTypes;
|
extern gameTypeName_t* gameTypes;
|
||||||
|
|
||||||
extern XBlock** g_streamBlocks;
|
extern XBlock** g_streamBlocks;
|
||||||
|
|
||||||
extern bool* g_lobbyCreateInProgress;
|
extern bool* g_lobbyCreateInProgress;
|
||||||
extern party_t** partyIngame;
|
extern party_t** partyIngame;
|
||||||
extern PartyData_s** partyData;
|
extern PartyData_s** partyData;
|
||||||
|
|
||||||
extern int* numIP;
|
extern int* numIP;
|
||||||
extern netIP_t* localIP;
|
extern netIP_t* localIP;
|
||||||
|
|
||||||
extern int* demoFile;
|
extern int* demoFile;
|
||||||
extern int* demoPlaying;
|
extern int* demoPlaying;
|
||||||
extern int* demoRecording;
|
extern int* demoRecording;
|
||||||
extern int* serverMessageSequence;
|
extern int* serverMessageSequence;
|
||||||
|
|
||||||
extern gentity_t* g_entities;
|
extern gentity_t* g_entities;
|
||||||
|
|
||||||
extern netadr_t* connectedHost;
|
extern netadr_t* connectedHost;
|
||||||
extern SOCKET* ip_socket;
|
extern SOCKET* ip_socket;
|
||||||
|
|
||||||
extern SafeArea* safeArea;
|
extern SafeArea* safeArea;
|
||||||
|
|
||||||
extern SpawnVar* spawnVars;
|
extern SpawnVar* spawnVars;
|
||||||
extern MapEnts** marMapEntsPtr;
|
extern MapEnts** marMapEntsPtr;
|
||||||
|
|
||||||
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
|
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
|
||||||
void Menu_FreeItemMemory(Game::itemDef_t* item);
|
void Menu_FreeItemMemory(Game::itemDef_t* item);
|
||||||
const char* TableLookup(StringTable* stringtable, int row, int column);
|
const char* TableLookup(StringTable* stringtable, int row, int column);
|
||||||
const char* UI_LocalizeMapName(const char* mapName);
|
const char* UI_LocalizeMapName(const char* mapName);
|
||||||
const char* UI_LocalizeGameType(const char* gameType);
|
const char* UI_LocalizeGameType(const char* gameType);
|
||||||
float UI_GetScoreboardLeft(void*);
|
float UI_GetScoreboardLeft(void*);
|
||||||
|
|
||||||
const char *DB_GetXAssetName(XAsset *asset);
|
const char *DB_GetXAssetName(XAsset *asset);
|
||||||
XAssetType DB_GetXAssetNameType(const char* name);
|
XAssetType DB_GetXAssetNameType(const char* name);
|
||||||
bool DB_IsZoneLoaded(const char* zone);
|
bool DB_IsZoneLoaded(const char* zone);
|
||||||
|
|
||||||
void FS_AddLocalizedGameDirectory(const char *path, const char *dir);
|
void FS_AddLocalizedGameDirectory(const char *path, const char *dir);
|
||||||
|
|
||||||
void MessageBox(std::string message, std::string title);
|
void MessageBox(std::string message, std::string title);
|
||||||
|
|
||||||
unsigned int R_HashString(const char* string);
|
unsigned int R_HashString(const char* string);
|
||||||
|
|
||||||
void SV_KickClient(client_t* client, const char* reason);
|
void SV_KickClient(client_t* client, const char* reason);
|
||||||
void SV_KickClientError(client_t* client, const char* reason);
|
void SV_KickClientError(client_t* client, std::string reason);
|
||||||
}
|
}
|
||||||
|
@ -1,143 +1,157 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Version number
|
// Version number
|
||||||
#include <version.hpp>
|
#include <version.hpp>
|
||||||
|
|
||||||
#ifndef RESOURCE_DATA
|
#ifndef RESOURCE_DATA
|
||||||
|
|
||||||
// Disable irrelevant warnings
|
// Disable irrelevant warnings
|
||||||
#pragma warning(disable: 4100) // Unreferenced parameter (steam has to have them and other stubs as well, due to their calling convention)
|
#pragma warning(disable: 4100) // Unreferenced parameter (steam has to have them and other stubs as well, due to their calling convention)
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <timeapi.h>
|
#include <timeapi.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
#include <Wininet.h>
|
#include <Wininet.h>
|
||||||
#include <Urlmon.h>
|
#include <Urlmon.h>
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
// Submodules
|
// Submodules
|
||||||
// Ignore the warnings, it's no our code!
|
// Ignore the warnings, it's no our code!
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4005)
|
#pragma warning(disable: 4005)
|
||||||
#pragma warning(disable: 4389)
|
#pragma warning(disable: 4389)
|
||||||
#pragma warning(disable: 6001)
|
#pragma warning(disable: 4702)
|
||||||
#pragma warning(disable: 6011)
|
#pragma warning(disable: 6001)
|
||||||
#pragma warning(disable: 6031)
|
#pragma warning(disable: 6011)
|
||||||
#pragma warning(disable: 6255)
|
#pragma warning(disable: 6031)
|
||||||
#pragma warning(disable: 6258)
|
#pragma warning(disable: 6255)
|
||||||
#pragma warning(disable: 6386)
|
#pragma warning(disable: 6258)
|
||||||
#pragma warning(disable: 6387)
|
#pragma warning(disable: 6386)
|
||||||
|
#pragma warning(disable: 6387)
|
||||||
#define ZLIB_CONST
|
|
||||||
|
#define ZLIB_CONST
|
||||||
#define USE_LTM
|
|
||||||
#define LTM_DESC
|
#define USE_LTM
|
||||||
#define LTC_NO_FAST
|
#define LTM_DESC
|
||||||
#define LTC_NO_PROTOTYPES
|
#define LTC_NO_FAST
|
||||||
#define LTC_NO_RSA_BLINDING
|
#define LTC_NO_PROTOTYPES
|
||||||
|
#define LTC_NO_RSA_BLINDING
|
||||||
#include <zlib.h>
|
|
||||||
#include <curses.h>
|
#include <zlib.h>
|
||||||
#include <mongoose.h>
|
#include <curses.h>
|
||||||
#include <json11.hpp>
|
#include <mongoose.h>
|
||||||
#include <tomcrypt.h>
|
#include <json11.hpp>
|
||||||
#include <wink/signal.hpp>
|
#include <tomcrypt.h>
|
||||||
|
#include <wink/signal.hpp>
|
||||||
// Protobuf
|
|
||||||
#include "proto/network.pb.h"
|
#ifdef max
|
||||||
#include "proto/party.pb.h"
|
#undef max
|
||||||
#include "proto/auth.pb.h"
|
#endif
|
||||||
#include "proto/node.pb.h"
|
|
||||||
#include "proto/rcon.pb.h"
|
#ifdef min
|
||||||
|
#undef min
|
||||||
#pragma warning(pop)
|
#endif
|
||||||
|
|
||||||
#include "Utils\CSV.hpp"
|
#include <fmt/printf.h>
|
||||||
#include "Utils\Utils.hpp"
|
|
||||||
#include "Utils\WebIO.hpp"
|
// Protobuf
|
||||||
#include "Utils\Memory.hpp"
|
#include "proto/network.pb.h"
|
||||||
#include "Utils\Hooking.hpp"
|
#include "proto/party.pb.h"
|
||||||
#include "Utils\Compression.hpp"
|
#include "proto/auth.pb.h"
|
||||||
#include "Utils\Cryptography.hpp"
|
#include "proto/node.pb.h"
|
||||||
|
#include "proto/rcon.pb.h"
|
||||||
#include "Steam\Steam.hpp"
|
|
||||||
|
#pragma warning(pop)
|
||||||
#include "Game\Structs.hpp"
|
|
||||||
#include "Game\Functions.hpp"
|
#include "Utils\IO.hpp"
|
||||||
|
#include "Utils\CSV.hpp"
|
||||||
#include "Utils\Stream.hpp"
|
#include "Utils\Utils.hpp"
|
||||||
|
#include "Utils\WebIO.hpp"
|
||||||
#include "Components\Loader.hpp"
|
#include "Utils\Memory.hpp"
|
||||||
|
#include "Utils\String.hpp"
|
||||||
// Libraries
|
#include "Utils\Hooking.hpp"
|
||||||
#pragma comment(lib, "Winmm.lib")
|
#include "Utils\InfoString.hpp"
|
||||||
#pragma comment(lib, "Crypt32.lib")
|
#include "Utils\Compression.hpp"
|
||||||
#pragma comment(lib, "Ws2_32.lib")
|
#include "Utils\Cryptography.hpp"
|
||||||
#pragma comment(lib, "d3d9.lib")
|
|
||||||
#pragma comment(lib, "Wininet.lib")
|
#include "Steam\Steam.hpp"
|
||||||
#pragma comment(lib, "shlwapi.lib")
|
|
||||||
#pragma comment(lib, "Urlmon.lib")
|
#include "Game\Structs.hpp"
|
||||||
|
#include "Game\Functions.hpp"
|
||||||
// Enable additional literals
|
|
||||||
using namespace std::literals;
|
#include "Utils\Stream.hpp"
|
||||||
|
|
||||||
#endif
|
#include "Components\Loader.hpp"
|
||||||
|
|
||||||
// Revision number
|
// Libraries
|
||||||
#define STRINGIZE_(x) #x
|
#pragma comment(lib, "Winmm.lib")
|
||||||
#define STRINGIZE(x) STRINGIZE_(x)
|
#pragma comment(lib, "Crypt32.lib")
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
#define BASEGAME "iw4x"
|
#pragma comment(lib, "d3d9.lib")
|
||||||
#define CLIENT_CONFIG "iw4x_config.cfg"
|
#pragma comment(lib, "Wininet.lib")
|
||||||
#define MILESTONE "beta"
|
#pragma comment(lib, "shlwapi.lib")
|
||||||
|
#pragma comment(lib, "Urlmon.lib")
|
||||||
#define REVISION_STR STRINGIZE(REVISION)
|
|
||||||
#if !REVISION_CLEAN
|
// Enable additional literals
|
||||||
#define REVISION_SUFFIX "*"
|
using namespace std::literals;
|
||||||
#else
|
|
||||||
#define REVISION_SUFFIX ""
|
#endif
|
||||||
#endif
|
|
||||||
#define VERSION 4,2,REVISION
|
// Revision number
|
||||||
#define VERSION_STR "4.2." REVISION_STR
|
#define STRINGIZE_(x) #x
|
||||||
|
#define STRINGIZE(x) STRINGIZE_(x)
|
||||||
#define Assert_Size(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.")
|
|
||||||
|
#define BASEGAME "iw4x"
|
||||||
// Enable unit-test flag for release builds
|
#define CLIENT_CONFIG "iw4x_config.cfg"
|
||||||
//#define FORCE_UNIT_TESTS
|
#define MILESTONE "beta"
|
||||||
|
|
||||||
// Resource stuff
|
#define REVISION_STR STRINGIZE(REVISION)
|
||||||
#ifdef APSTUDIO_INVOKED
|
#if !REVISION_CLEAN
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#define REVISION_SUFFIX "*"
|
||||||
// Defines below make accessing the resources from the code easier.
|
#else
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
#define REVISION_SUFFIX ""
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
#endif
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
#define VERSION 4,2,REVISION
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
#define VERSION_STR "4.2." REVISION_STR
|
||||||
#endif
|
|
||||||
#endif
|
#define Assert_Size(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.")
|
||||||
|
|
||||||
|
// Enable unit-test flag for release builds
|
||||||
|
//#define FORCE_UNIT_TESTS
|
||||||
|
|
||||||
|
// Resource stuff
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
// Defines below make accessing the resources from the code easier.
|
||||||
|
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||||
|
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||||
|
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||||
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
@ -1,185 +1,185 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Steam
|
namespace Steam
|
||||||
{
|
{
|
||||||
HMODULE Overlay = 0;
|
HMODULE Overlay = 0;
|
||||||
|
|
||||||
uint64_t Callbacks::CallID = 0;
|
uint64_t Callbacks::CallID = 0;
|
||||||
std::map<uint64_t, bool> Callbacks::Calls;
|
std::map<uint64_t, bool> Callbacks::Calls;
|
||||||
std::map<uint64_t, Callbacks::Base*> Callbacks::ResultHandlers;
|
std::map<uint64_t, Callbacks::Base*> Callbacks::ResultHandlers;
|
||||||
std::vector<Callbacks::Result> Callbacks::Results;
|
std::vector<Callbacks::Result> Callbacks::Results;
|
||||||
std::vector<Callbacks::Base*> Callbacks::CallbackList;
|
std::vector<Callbacks::Base*> Callbacks::CallbackList;
|
||||||
|
|
||||||
uint64_t Callbacks::RegisterCall()
|
uint64_t Callbacks::RegisterCall()
|
||||||
{
|
{
|
||||||
Callbacks::Calls[++Callbacks::CallID] = false;
|
Callbacks::Calls[++Callbacks::CallID] = false;
|
||||||
return Callbacks::CallID;
|
return Callbacks::CallID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Callbacks::RegisterCallback(Callbacks::Base* handler, int callback)
|
void Callbacks::RegisterCallback(Callbacks::Base* handler, int callback)
|
||||||
{
|
{
|
||||||
handler->SetICallback(callback);
|
handler->SetICallback(callback);
|
||||||
Callbacks::CallbackList.push_back(handler);
|
Callbacks::CallbackList.push_back(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Callbacks::RegisterCallResult(uint64_t call, Callbacks::Base* result)
|
void Callbacks::RegisterCallResult(uint64_t call, Callbacks::Base* result)
|
||||||
{
|
{
|
||||||
Callbacks::ResultHandlers[call] = result;
|
Callbacks::ResultHandlers[call] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Callbacks::ReturnCall(void* data, int size, int type, uint64_t call)
|
void Callbacks::ReturnCall(void* data, int size, int type, uint64_t call)
|
||||||
{
|
{
|
||||||
Callbacks::Result result;
|
Callbacks::Result result;
|
||||||
|
|
||||||
Callbacks::Calls[call] = true;
|
Callbacks::Calls[call] = true;
|
||||||
|
|
||||||
result.call = call;
|
result.call = call;
|
||||||
result.data = data;
|
result.data = data;
|
||||||
result.size = size;
|
result.size = size;
|
||||||
result.type = type;
|
result.type = type;
|
||||||
|
|
||||||
Callbacks::Results.push_back(result);
|
Callbacks::Results.push_back(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Callbacks::RunCallbacks()
|
void Callbacks::RunCallbacks()
|
||||||
{
|
{
|
||||||
for (auto result : Callbacks::Results)
|
for (auto result : Callbacks::Results)
|
||||||
{
|
{
|
||||||
if (Callbacks::ResultHandlers.find(result.call) != Callbacks::ResultHandlers.end())
|
if (Callbacks::ResultHandlers.find(result.call) != Callbacks::ResultHandlers.end())
|
||||||
{
|
{
|
||||||
Callbacks::ResultHandlers[result.call]->Run(result.data, false, result.call);
|
Callbacks::ResultHandlers[result.call]->Run(result.data, false, result.call);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto callback : Callbacks::CallbackList)
|
for (auto callback : Callbacks::CallbackList)
|
||||||
{
|
{
|
||||||
if (callback && callback->GetICallback() == result.type)
|
if (callback && callback->GetICallback() == result.type)
|
||||||
{
|
{
|
||||||
callback->Run(result.data, false, 0);
|
callback->Run(result.data, false, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.data)
|
if (result.data)
|
||||||
{
|
{
|
||||||
::Utils::Memory::Free(result.data);
|
::Utils::Memory::Free(result.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Callbacks::Results.clear();
|
Callbacks::Results.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
bool SteamAPI_Init()
|
bool SteamAPI_Init()
|
||||||
{
|
{
|
||||||
Overlay = GetModuleHandleA("gameoverlayrenderer.dll");
|
Overlay = GetModuleHandleA("gameoverlayrenderer.dll");
|
||||||
|
|
||||||
if (!Overlay)
|
if (!Overlay)
|
||||||
{
|
{
|
||||||
HKEY hRegKey;
|
HKEY hRegKey;
|
||||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS)
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
char steamPath[MAX_PATH] = { 0 };
|
char steamPath[MAX_PATH] = { 0 };
|
||||||
DWORD dwLength = sizeof(steamPath);
|
DWORD dwLength = sizeof(steamPath);
|
||||||
RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast<BYTE*>(steamPath), &dwLength);
|
RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast<BYTE*>(steamPath), &dwLength);
|
||||||
RegCloseKey(hRegKey);
|
RegCloseKey(hRegKey);
|
||||||
|
|
||||||
SetDllDirectoryA(steamPath);
|
SetDllDirectoryA(steamPath);
|
||||||
|
|
||||||
Overlay = LoadLibraryA(::Utils::VA("%s\\%s", steamPath, "gameoverlayrenderer.dll"));
|
Overlay = LoadLibraryA(::Utils::String::VA("%s\\%s", steamPath, "gameoverlayrenderer.dll"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call)
|
void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call)
|
||||||
{
|
{
|
||||||
Callbacks::RegisterCallResult(call, result);
|
Callbacks::RegisterCallResult(call, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback)
|
void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback)
|
||||||
{
|
{
|
||||||
Callbacks::RegisterCallback(handler, callback);
|
Callbacks::RegisterCallback(handler, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_RunCallbacks()
|
void SteamAPI_RunCallbacks()
|
||||||
{
|
{
|
||||||
Callbacks::RunCallbacks();
|
Callbacks::RunCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_Shutdown()
|
void SteamAPI_Shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_UnregisterCallResult()
|
void SteamAPI_UnregisterCallResult()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamAPI_UnregisterCallback()
|
void SteamAPI_UnregisterCallback()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SteamGameServer_Init()
|
bool SteamGameServer_Init()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamGameServer_RunCallbacks()
|
void SteamGameServer_RunCallbacks()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SteamGameServer_Shutdown()
|
void SteamGameServer_Shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Steam::Friends* SteamFriends()
|
Steam::Friends* SteamFriends()
|
||||||
{
|
{
|
||||||
static Steam::Friends iFriends;
|
static Steam::Friends iFriends;
|
||||||
return &iFriends;
|
return &iFriends;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::Matchmaking* SteamMatchmaking()
|
Steam::Matchmaking* SteamMatchmaking()
|
||||||
{
|
{
|
||||||
static Steam::Matchmaking iMatchmaking;
|
static Steam::Matchmaking iMatchmaking;
|
||||||
return &iMatchmaking;
|
return &iMatchmaking;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::GameServer* SteamGameServer()
|
Steam::GameServer* SteamGameServer()
|
||||||
{
|
{
|
||||||
static Steam::GameServer iGameServer;
|
static Steam::GameServer iGameServer;
|
||||||
return &iGameServer;
|
return &iGameServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::MasterServerUpdater* SteamMasterServerUpdater()
|
Steam::MasterServerUpdater* SteamMasterServerUpdater()
|
||||||
{
|
{
|
||||||
static Steam::MasterServerUpdater iMasterServerUpdater;
|
static Steam::MasterServerUpdater iMasterServerUpdater;
|
||||||
return &iMasterServerUpdater;
|
return &iMasterServerUpdater;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::Networking* SteamNetworking()
|
Steam::Networking* SteamNetworking()
|
||||||
{
|
{
|
||||||
static Steam::Networking iNetworking;
|
static Steam::Networking iNetworking;
|
||||||
return &iNetworking;
|
return &iNetworking;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::RemoteStorage* SteamRemoteStorage()
|
Steam::RemoteStorage* SteamRemoteStorage()
|
||||||
{
|
{
|
||||||
static Steam::RemoteStorage iRemoteStorage;
|
static Steam::RemoteStorage iRemoteStorage;
|
||||||
return &iRemoteStorage;
|
return &iRemoteStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::User* SteamUser()
|
Steam::User* SteamUser()
|
||||||
{
|
{
|
||||||
static Steam::User iUser;
|
static Steam::User iUser;
|
||||||
return &iUser;
|
return &iUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam::Utils* SteamUtils()
|
Steam::Utils* SteamUtils()
|
||||||
{
|
{
|
||||||
static Steam::Utils iUtils;
|
static Steam::Utils iUtils;
|
||||||
return &iUtils;
|
return &iUtils;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,144 +1,144 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
CSV::CSV(std::string file, bool isFile, bool allowComments)
|
CSV::CSV(std::string file, bool isFile, bool allowComments)
|
||||||
{
|
{
|
||||||
CSV::Parse(file, isFile, allowComments);
|
CSV::Parse(file, isFile, allowComments);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSV::~CSV()
|
CSV::~CSV()
|
||||||
{
|
{
|
||||||
for (auto row : CSV::DataMap)
|
for (auto row : CSV::DataMap)
|
||||||
{
|
{
|
||||||
for (auto entry : row)
|
for (auto entry : row)
|
||||||
{
|
{
|
||||||
entry.clear();
|
entry.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
row.clear();
|
row.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSV::DataMap.clear();
|
CSV::DataMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSV::GetRows()
|
int CSV::GetRows()
|
||||||
{
|
{
|
||||||
return CSV::DataMap.size();
|
return CSV::DataMap.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSV::GetColumns(size_t row)
|
int CSV::GetColumns(size_t row)
|
||||||
{
|
{
|
||||||
if (CSV::DataMap.size() > row)
|
if (CSV::DataMap.size() > row)
|
||||||
{
|
{
|
||||||
return CSV::DataMap[row].size();
|
return CSV::DataMap[row].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSV::GetColumns()
|
int CSV::GetColumns()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (int i = 0; i < CSV::GetRows(); ++i)
|
for (int i = 0; i < CSV::GetRows(); ++i)
|
||||||
{
|
{
|
||||||
count = std::max(CSV::GetColumns(i), count);
|
count = std::max(CSV::GetColumns(i), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CSV::GetElementAt(size_t row, size_t column)
|
std::string CSV::GetElementAt(size_t row, size_t column)
|
||||||
{
|
{
|
||||||
if (CSV::DataMap.size() > row)
|
if (CSV::DataMap.size() > row)
|
||||||
{
|
{
|
||||||
auto _row = CSV::DataMap[row];
|
auto _row = CSV::DataMap[row];
|
||||||
|
|
||||||
if (_row.size() > column)
|
if (_row.size() > column)
|
||||||
{
|
{
|
||||||
return _row[column];
|
return _row[column];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSV::Parse(std::string file, bool isFile, bool allowComments)
|
void CSV::Parse(std::string file, bool isFile, bool allowComments)
|
||||||
{
|
{
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
|
|
||||||
if (isFile)
|
if (isFile)
|
||||||
{
|
{
|
||||||
if (!Utils::FileExists(file)) return;
|
if (!Utils::IO::FileExists(file)) return;
|
||||||
buffer = Utils::ReadFile(file);
|
buffer = Utils::IO::ReadFile(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer = file;
|
buffer = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buffer.empty())
|
if (!buffer.empty())
|
||||||
{
|
{
|
||||||
auto rows = Utils::Explode(buffer, '\n');
|
auto rows = Utils::String::Explode(buffer, '\n');
|
||||||
|
|
||||||
for (auto row : rows)
|
for (auto row : rows)
|
||||||
{
|
{
|
||||||
CSV::ParseRow(row, allowComments);
|
CSV::ParseRow(row, allowComments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSV::ParseRow(std::string row, bool allowComments)
|
void CSV::ParseRow(std::string row, bool allowComments)
|
||||||
{
|
{
|
||||||
bool isString = false;
|
bool isString = false;
|
||||||
std::string element;
|
std::string element;
|
||||||
std::vector<std::string> _row;
|
std::vector<std::string> _row;
|
||||||
char tempStr = 0;
|
char tempStr = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < row.size(); ++i)
|
for (unsigned int i = 0; i < row.size(); ++i)
|
||||||
{
|
{
|
||||||
if (row[i] == ',' && !isString) // FLush entry
|
if (row[i] == ',' && !isString) // FLush entry
|
||||||
{
|
{
|
||||||
_row.push_back(element);
|
_row.push_back(element);
|
||||||
element.clear();
|
element.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (row[i] == '"') // Start/Terminate string
|
else if (row[i] == '"') // Start/Terminate string
|
||||||
{
|
{
|
||||||
isString = !isString;
|
isString = !isString;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (i < (row.size() - 1) && row[i] == '\\' &&row[i + 1] == '"' && isString) // Handle quotes in strings as \"
|
else if (i < (row.size() - 1) && row[i] == '\\' &&row[i + 1] == '"' && isString) // Handle quotes in strings as \"
|
||||||
{
|
{
|
||||||
tempStr = '"';
|
tempStr = '"';
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
else if (!isString && (row[i] == '\n' || row[i] == '\x0D' || row[i] == '\x0A' || row[i] == '\t'))
|
else if (!isString && (row[i] == '\n' || row[i] == '\x0D' || row[i] == '\x0A' || row[i] == '\t'))
|
||||||
{
|
{
|
||||||
//++i;
|
//++i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (!isString && row[i] == '#' && allowComments) // Skip comments. I know CSVs usually don't have comments, but in this case it's useful
|
else if (!isString && row[i] == '#' && allowComments) // Skip comments. I know CSVs usually don't have comments, but in this case it's useful
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tempStr = row[i];
|
tempStr = row[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
element.append(&tempStr, 1);
|
element.append(&tempStr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push last element
|
// Push last element
|
||||||
_row.push_back(element);
|
_row.push_back(element);
|
||||||
|
|
||||||
if (_row.size() == 0 || (_row.size() == 1 && !_row[0].size())) // Skip empty rows
|
if (_row.size() == 0 || (_row.size() == 1 && !_row[0].size())) // Skip empty rows
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataMap.push_back(_row);
|
DataMap.push_back(_row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
namespace Compression
|
namespace Compression
|
||||||
{
|
{
|
||||||
std::string ZLib::Compress(std::string data)
|
std::string ZLib::Compress(std::string data)
|
||||||
{
|
{
|
||||||
unsigned long length = (data.size() * 2);
|
unsigned long length = (data.size() * 2);
|
||||||
char* buffer = Utils::Memory::AllocateArray<char>(length);
|
char* buffer = Utils::Memory::AllocateArray<char>(length);
|
||||||
|
|
||||||
if (compress2(reinterpret_cast<Bytef*>(buffer), &length, reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(), Z_BEST_COMPRESSION) != Z_OK)
|
if (compress2(reinterpret_cast<Bytef*>(buffer), &length, reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(), Z_BEST_COMPRESSION) != Z_OK)
|
||||||
{
|
{
|
||||||
Utils::Memory::Free(buffer);
|
Utils::Memory::Free(buffer);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
data.clear();
|
data.clear();
|
||||||
data.append(buffer, length);
|
data.append(buffer, length);
|
||||||
|
|
||||||
Utils::Memory::Free(buffer);
|
Utils::Memory::Free(buffer);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ZLib::Decompress(std::string data)
|
std::string ZLib::Decompress(std::string data)
|
||||||
{
|
{
|
||||||
z_stream stream;
|
z_stream stream;
|
||||||
ZeroMemory(&stream, sizeof(stream));
|
ZeroMemory(&stream, sizeof(stream));
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
|
|
||||||
if (inflateInit(&stream) != Z_OK)
|
if (inflateInit(&stream) != Z_OK)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint8_t* dest = Utils::Memory::AllocateArray<uint8_t>(CHUNK);
|
uint8_t* dest = Utils::Memory::AllocateArray<uint8_t>(CHUNK);
|
||||||
const char* dataPtr = data.data();
|
const char* dataPtr = data.data();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
stream.avail_in = min(CHUNK, data.size() - (dataPtr - data.data()));
|
stream.avail_in = std::min(static_cast<size_t>(CHUNK), data.size() - (dataPtr - data.data()));
|
||||||
stream.next_in = reinterpret_cast<const uint8_t*>(dataPtr);
|
stream.next_in = reinterpret_cast<const uint8_t*>(dataPtr);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
stream.avail_out = CHUNK;
|
stream.avail_out = CHUNK;
|
||||||
stream.next_out = dest;
|
stream.next_out = dest;
|
||||||
|
|
||||||
ret = inflate(&stream, Z_NO_FLUSH);
|
ret = inflate(&stream, Z_NO_FLUSH);
|
||||||
if (ret == Z_STREAM_ERROR)
|
if (ret == Z_STREAM_ERROR)
|
||||||
{
|
{
|
||||||
inflateEnd(&stream);
|
inflateEnd(&stream);
|
||||||
Utils::Memory::Free(dest);
|
Utils::Memory::Free(dest);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out);
|
buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out);
|
||||||
|
|
||||||
} while (stream.avail_out == 0);
|
} while (stream.avail_out == 0);
|
||||||
|
|
||||||
} while (ret != Z_STREAM_END);
|
} while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
inflateEnd(&stream);
|
inflateEnd(&stream);
|
||||||
|
|
||||||
Utils::Memory::Free(dest);
|
Utils::Memory::Free(dest);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,261 +1,261 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf
|
/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
namespace Cryptography
|
namespace Cryptography
|
||||||
{
|
{
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
TDES::Initialize();
|
TDES::Initialize();
|
||||||
Rand::Initialize();
|
Rand::Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region Rand
|
#pragma region Rand
|
||||||
|
|
||||||
prng_state Rand::State;
|
prng_state Rand::State;
|
||||||
|
|
||||||
uint32_t Rand::GenerateInt()
|
uint32_t Rand::GenerateInt()
|
||||||
{
|
{
|
||||||
uint32_t number = 0;
|
uint32_t number = 0;
|
||||||
fortuna_read(reinterpret_cast<uint8_t*>(&number), sizeof(number), &Rand::State);
|
fortuna_read(reinterpret_cast<uint8_t*>(&number), sizeof(number), &Rand::State);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rand::Initialize()
|
void Rand::Initialize()
|
||||||
{
|
{
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
register_prng(&fortuna_desc);
|
register_prng(&fortuna_desc);
|
||||||
rng_make_prng(128, find_prng("fortuna"), &Rand::State, NULL);
|
rng_make_prng(128, find_prng("fortuna"), &Rand::State, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region ECC
|
#pragma region ECC
|
||||||
|
|
||||||
ECC::Key ECC::GenerateKey(int bits)
|
ECC::Key ECC::GenerateKey(int bits)
|
||||||
{
|
{
|
||||||
ECC::Key key;
|
ECC::Key key;
|
||||||
|
|
||||||
register_prng(&sprng_desc);
|
register_prng(&sprng_desc);
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
ecc_make_key(NULL, find_prng("sprng"), bits / 8, key.GetKeyPtr());
|
ecc_make_key(NULL, find_prng("sprng"), bits / 8, key.GetKeyPtr());
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ECC::SignMessage(Key key, std::string message)
|
std::string ECC::SignMessage(Key key, std::string message)
|
||||||
{
|
{
|
||||||
if (!key.IsValid()) return "";
|
if (!key.IsValid()) return "";
|
||||||
|
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
DWORD length = sizeof(buffer);
|
DWORD length = sizeof(buffer);
|
||||||
|
|
||||||
register_prng(&sprng_desc);
|
register_prng(&sprng_desc);
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, NULL, find_prng("sprng"), key.GetKeyPtr());
|
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, NULL, find_prng("sprng"), key.GetKeyPtr());
|
||||||
|
|
||||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ECC::VerifyMessage(Key key, std::string message, std::string signature)
|
bool ECC::VerifyMessage(Key key, std::string message, std::string signature)
|
||||||
{
|
{
|
||||||
if (!key.IsValid()) return false;
|
if (!key.IsValid()) return false;
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result, key.GetKeyPtr()) == CRYPT_OK && result != 0);
|
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result, key.GetKeyPtr()) == CRYPT_OK && result != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region RSA
|
#pragma region RSA
|
||||||
|
|
||||||
RSA::Key RSA::GenerateKey(int bits)
|
RSA::Key RSA::GenerateKey(int bits)
|
||||||
{
|
{
|
||||||
RSA::Key key;
|
RSA::Key key;
|
||||||
|
|
||||||
register_prng(&sprng_desc);
|
register_prng(&sprng_desc);
|
||||||
register_hash(&sha1_desc);
|
register_hash(&sha1_desc);
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
rsa_make_key(NULL, find_prng("sprng"), bits / 8, 65537, key.GetKeyPtr());
|
rsa_make_key(NULL, find_prng("sprng"), bits / 8, 65537, key.GetKeyPtr());
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RSA::SignMessage(RSA::Key key, std::string message)
|
std::string RSA::SignMessage(RSA::Key key, std::string message)
|
||||||
{
|
{
|
||||||
if (!key.IsValid()) return "";
|
if (!key.IsValid()) return "";
|
||||||
|
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
DWORD length = sizeof(buffer);
|
DWORD length = sizeof(buffer);
|
||||||
|
|
||||||
register_prng(&sprng_desc);
|
register_prng(&sprng_desc);
|
||||||
register_hash(&sha1_desc);
|
register_hash(&sha1_desc);
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
rsa_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, NULL, find_prng("sprng"), find_hash("sha1"), 0, key.GetKeyPtr());
|
rsa_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, NULL, find_prng("sprng"), find_hash("sha1"), 0, key.GetKeyPtr());
|
||||||
|
|
||||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RSA::VerifyMessage(Key key, std::string message, std::string signature)
|
bool RSA::VerifyMessage(Key key, std::string message, std::string signature)
|
||||||
{
|
{
|
||||||
if (!key.IsValid()) return false;
|
if (!key.IsValid()) return false;
|
||||||
|
|
||||||
register_hash(&sha1_desc);
|
register_hash(&sha1_desc);
|
||||||
|
|
||||||
ltc_mp = ltm_desc;
|
ltc_mp = ltm_desc;
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
return (rsa_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(message.data()), message.size(), find_hash("sha1"), 0, &result, key.GetKeyPtr()) == CRYPT_OK && result != 0);
|
return (rsa_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(message.data()), message.size(), find_hash("sha1"), 0, &result, key.GetKeyPtr()) == CRYPT_OK && result != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region TDES
|
#pragma region TDES
|
||||||
|
|
||||||
void TDES::Initialize()
|
void TDES::Initialize()
|
||||||
{
|
{
|
||||||
register_cipher(&des3_desc);
|
register_cipher(&des3_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TDES::Encrypt(std::string text, std::string iv, std::string key)
|
std::string TDES::Encrypt(std::string text, std::string iv, std::string key)
|
||||||
{
|
{
|
||||||
std::string encData;
|
std::string encData;
|
||||||
encData.resize(text.size());
|
encData.resize(text.size());
|
||||||
|
|
||||||
symmetric_CBC cbc;
|
symmetric_CBC cbc;
|
||||||
int des3 = find_cipher("3des");
|
int des3 = find_cipher("3des");
|
||||||
|
|
||||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()), key.size(), 0, &cbc);
|
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()), key.size(), 0, &cbc);
|
||||||
cbc_encrypt(reinterpret_cast<const uint8_t*>(text.data()), reinterpret_cast<uint8_t*>(const_cast<char*>(encData.data())), text.size(), &cbc);
|
cbc_encrypt(reinterpret_cast<const uint8_t*>(text.data()), reinterpret_cast<uint8_t*>(const_cast<char*>(encData.data())), text.size(), &cbc);
|
||||||
cbc_done(&cbc);
|
cbc_done(&cbc);
|
||||||
|
|
||||||
return encData;
|
return encData;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TDES::Decrpyt(std::string data, std::string iv, std::string key)
|
std::string TDES::Decrpyt(std::string data, std::string iv, std::string key)
|
||||||
{
|
{
|
||||||
std::string decData;
|
std::string decData;
|
||||||
decData.resize(data.size());
|
decData.resize(data.size());
|
||||||
|
|
||||||
symmetric_CBC cbc;
|
symmetric_CBC cbc;
|
||||||
int des3 = find_cipher("3des");
|
int des3 = find_cipher("3des");
|
||||||
|
|
||||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()), key.size(), 0, &cbc);
|
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()), key.size(), 0, &cbc);
|
||||||
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()), reinterpret_cast<uint8_t*>(const_cast<char*>(decData.data())), data.size(), &cbc);
|
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()), reinterpret_cast<uint8_t*>(const_cast<char*>(decData.data())), data.size(), &cbc);
|
||||||
cbc_done(&cbc);
|
cbc_done(&cbc);
|
||||||
|
|
||||||
return decData;
|
return decData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Tiger
|
#pragma region Tiger
|
||||||
|
|
||||||
std::string Tiger::Compute(std::string data, bool hex)
|
std::string Tiger::Compute(std::string data, bool hex)
|
||||||
{
|
{
|
||||||
return Tiger::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
return Tiger::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Tiger::Compute(const uint8_t* data, size_t length, bool hex)
|
std::string Tiger::Compute(const uint8_t* data, size_t length, bool hex)
|
||||||
{
|
{
|
||||||
uint8_t buffer[24] = { 0 };
|
uint8_t buffer[24] = { 0 };
|
||||||
|
|
||||||
hash_state state;
|
hash_state state;
|
||||||
tiger_init(&state);
|
tiger_init(&state);
|
||||||
tiger_process(&state, data, length);
|
tiger_process(&state, data, length);
|
||||||
tiger_done(&state, buffer);
|
tiger_done(&state, buffer);
|
||||||
|
|
||||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||||
if (!hex) return hash;
|
if (!hex) return hash;
|
||||||
|
|
||||||
return Utils::DumpHex(hash, "");
|
return Utils::String::DumpHex(hash, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region SHA256
|
#pragma region SHA256
|
||||||
|
|
||||||
std::string SHA256::Compute(std::string data, bool hex)
|
std::string SHA256::Compute(std::string data, bool hex)
|
||||||
{
|
{
|
||||||
return SHA256::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
return SHA256::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SHA256::Compute(const uint8_t* data, size_t length, bool hex)
|
std::string SHA256::Compute(const uint8_t* data, size_t length, bool hex)
|
||||||
{
|
{
|
||||||
uint8_t buffer[32] = { 0 };
|
uint8_t buffer[32] = { 0 };
|
||||||
|
|
||||||
hash_state state;
|
hash_state state;
|
||||||
sha256_init(&state);
|
sha256_init(&state);
|
||||||
sha256_process(&state, data, length);
|
sha256_process(&state, data, length);
|
||||||
sha256_done(&state, buffer);
|
sha256_done(&state, buffer);
|
||||||
|
|
||||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||||
if (!hex) return hash;
|
if (!hex) return hash;
|
||||||
|
|
||||||
return Utils::DumpHex(hash, "");
|
return Utils::String::DumpHex(hash, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region SHA512
|
#pragma region SHA512
|
||||||
|
|
||||||
std::string SHA512::Compute(std::string data, bool hex)
|
std::string SHA512::Compute(std::string data, bool hex)
|
||||||
{
|
{
|
||||||
return SHA512::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
return SHA512::Compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SHA512::Compute(const uint8_t* data, size_t length, bool hex)
|
std::string SHA512::Compute(const uint8_t* data, size_t length, bool hex)
|
||||||
{
|
{
|
||||||
uint8_t buffer[64] = { 0 };
|
uint8_t buffer[64] = { 0 };
|
||||||
|
|
||||||
hash_state state;
|
hash_state state;
|
||||||
sha512_init(&state);
|
sha512_init(&state);
|
||||||
sha512_process(&state, data, length);
|
sha512_process(&state, data, length);
|
||||||
sha512_done(&state, buffer);
|
sha512_done(&state, buffer);
|
||||||
|
|
||||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||||
if (!hex) return hash;
|
if (!hex) return hash;
|
||||||
|
|
||||||
return Utils::DumpHex(hash, "");
|
return Utils::String::DumpHex(hash, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region JenkinsOneAtATime
|
#pragma region JenkinsOneAtATime
|
||||||
|
|
||||||
unsigned int JenkinsOneAtATime::Compute(std::string data)
|
unsigned int JenkinsOneAtATime::Compute(std::string data)
|
||||||
{
|
{
|
||||||
return JenkinsOneAtATime::Compute(data.data(), data.size());
|
return JenkinsOneAtATime::Compute(data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int JenkinsOneAtATime::Compute(const char *key, size_t len)
|
unsigned int JenkinsOneAtATime::Compute(const char *key, size_t len)
|
||||||
{
|
{
|
||||||
unsigned int hash, i;
|
unsigned int hash, i;
|
||||||
for (hash = i = 0; i < len; ++i)
|
for (hash = i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
hash += key[i];
|
hash += key[i];
|
||||||
hash += (hash << 10);
|
hash += (hash << 10);
|
||||||
hash ^= (hash >> 6);
|
hash ^= (hash >> 6);
|
||||||
}
|
}
|
||||||
hash += (hash << 3);
|
hash += (hash << 3);
|
||||||
hash ^= (hash >> 11);
|
hash ^= (hash >> 11);
|
||||||
hash += (hash << 15);
|
hash += (hash << 15);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/Utils/IO.cpp
Normal file
51
src/Utils/IO.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace IO
|
||||||
|
{
|
||||||
|
bool FileExists(std::string file)
|
||||||
|
{
|
||||||
|
return std::ifstream(file).good();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteFile(std::string file, std::string data)
|
||||||
|
{
|
||||||
|
std::ofstream stream(file, std::ios::binary);
|
||||||
|
|
||||||
|
if (stream.is_open())
|
||||||
|
{
|
||||||
|
stream.write(data.data(), data.size());
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ReadFile(std::string file)
|
||||||
|
{
|
||||||
|
std::string buffer;
|
||||||
|
|
||||||
|
if (FileExists(file))
|
||||||
|
{
|
||||||
|
std::streamsize size = 0;
|
||||||
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
if (!stream.is_open()) return buffer;
|
||||||
|
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
size = stream.tellg();
|
||||||
|
stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
if (size > -1)
|
||||||
|
{
|
||||||
|
buffer.clear();
|
||||||
|
buffer.resize((uint32_t)size);
|
||||||
|
|
||||||
|
stream.read(const_cast<char*>(buffer.data()), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/Utils/IO.hpp
Normal file
9
src/Utils/IO.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace IO
|
||||||
|
{
|
||||||
|
bool FileExists(std::string file);
|
||||||
|
void WriteFile(std::string file, std::string data);
|
||||||
|
std::string ReadFile(std::string file);
|
||||||
|
}
|
||||||
|
}
|
67
src/Utils/InfoString.cpp
Normal file
67
src/Utils/InfoString.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
// Infostring class
|
||||||
|
void InfoString::Set(std::string key, std::string value)
|
||||||
|
{
|
||||||
|
this->KeyValuePairs[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string InfoString::Get(std::string key)
|
||||||
|
{
|
||||||
|
if (this->KeyValuePairs.find(key) != this->KeyValuePairs.end())
|
||||||
|
{
|
||||||
|
return this->KeyValuePairs[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoString::Parse(std::string buffer)
|
||||||
|
{
|
||||||
|
if (buffer[0] == '\\')
|
||||||
|
{
|
||||||
|
buffer = buffer.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> KeyValues = Utils::String::Explode(buffer, '\\');
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (KeyValues.size() - 1); i += 2)
|
||||||
|
{
|
||||||
|
this->KeyValuePairs[KeyValues[i]] = KeyValues[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string InfoString::Build()
|
||||||
|
{
|
||||||
|
std::string infoString;
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); ++i)
|
||||||
|
{
|
||||||
|
if (first) first = false;
|
||||||
|
else infoString.append("\\");
|
||||||
|
|
||||||
|
infoString.append(i->first); // Key
|
||||||
|
infoString.append("\\");
|
||||||
|
infoString.append(i->second); // Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return infoString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoString::Dump()
|
||||||
|
{
|
||||||
|
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); ++i)
|
||||||
|
{
|
||||||
|
OutputDebugStringA(Utils::String::VA("%s: %s", i->first.data(), i->second.data()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json11::Json InfoString::to_json()
|
||||||
|
{
|
||||||
|
return this->KeyValuePairs;
|
||||||
|
}
|
||||||
|
}
|
25
src/Utils/InfoString.hpp
Normal file
25
src/Utils/InfoString.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#define ARR_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
class InfoString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InfoString() {};
|
||||||
|
InfoString(std::string buffer) : InfoString() { this->Parse(buffer); };
|
||||||
|
InfoString(const InfoString &obj) : KeyValuePairs(obj.KeyValuePairs) {};
|
||||||
|
|
||||||
|
void Set(std::string key, std::string value);
|
||||||
|
std::string Get(std::string key);
|
||||||
|
|
||||||
|
std::string Build();
|
||||||
|
|
||||||
|
void Dump();
|
||||||
|
|
||||||
|
json11::Json to_json();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::string> KeyValuePairs;
|
||||||
|
void Parse(std::string buffer);
|
||||||
|
};
|
||||||
|
}
|
@ -1,306 +1,306 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
std::string Stream::Reader::ReadString()
|
std::string Stream::Reader::ReadString()
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
|
|
||||||
while (char byte = Stream::Reader::ReadByte())
|
while (char byte = Stream::Reader::ReadByte())
|
||||||
{
|
{
|
||||||
str.append(&byte, 1);
|
str.append(&byte, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Stream::Reader::ReadCString()
|
const char* Stream::Reader::ReadCString()
|
||||||
{
|
{
|
||||||
return Stream::Reader::Allocator->DuplicateString(Stream::Reader::ReadString());
|
return Stream::Reader::Allocator->DuplicateString(Stream::Reader::ReadString());
|
||||||
}
|
}
|
||||||
|
|
||||||
char Stream::Reader::ReadByte()
|
char Stream::Reader::ReadByte()
|
||||||
{
|
{
|
||||||
if ((Stream::Reader::Position + 1) <= Stream::Reader::Buffer.size())
|
if ((Stream::Reader::Position + 1) <= Stream::Reader::Buffer.size())
|
||||||
{
|
{
|
||||||
return Stream::Reader::Buffer[Stream::Reader::Position++];
|
return Stream::Reader::Buffer[Stream::Reader::Position++];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Stream::Reader::Read(size_t size, size_t count)
|
void* Stream::Reader::Read(size_t size, size_t count)
|
||||||
{
|
{
|
||||||
size_t bytes = size * count;
|
size_t bytes = size * count;
|
||||||
|
|
||||||
if ((Stream::Reader::Position + bytes) <= Stream::Reader::Buffer.size())
|
if ((Stream::Reader::Position + bytes) <= Stream::Reader::Buffer.size())
|
||||||
{
|
{
|
||||||
void* buffer = Stream::Reader::Allocator->Allocate(bytes);
|
void* buffer = Stream::Reader::Allocator->Allocate(bytes);
|
||||||
|
|
||||||
std::memcpy(buffer, Stream::Reader::Buffer.data() + Stream::Reader::Position, bytes);
|
std::memcpy(buffer, Stream::Reader::Buffer.data() + Stream::Reader::Position, bytes);
|
||||||
Stream::Reader::Position += bytes;
|
Stream::Reader::Position += bytes;
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::Reader::End()
|
bool Stream::Reader::End()
|
||||||
{
|
{
|
||||||
return (Stream::Reader::Buffer.size() == Stream::Reader::Position);
|
return (Stream::Reader::Buffer.size() == Stream::Reader::Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::Reader::Seek(unsigned int position)
|
void Stream::Reader::Seek(unsigned int position)
|
||||||
{
|
{
|
||||||
if (Stream::Reader::Buffer.size() >= position)
|
if (Stream::Reader::Buffer.size() >= position)
|
||||||
{
|
{
|
||||||
Stream::Reader::Position = position;
|
Stream::Reader::Position = position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream() : CriticalSectionState(0)
|
Stream::Stream() : CriticalSectionState(0)
|
||||||
{
|
{
|
||||||
memset(Stream::BlockSize, 0, sizeof(Stream::BlockSize));
|
memset(Stream::BlockSize, 0, sizeof(Stream::BlockSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream(size_t size) : Stream()
|
Stream::Stream(size_t size) : Stream()
|
||||||
{
|
{
|
||||||
Stream::Buffer.reserve(size);
|
Stream::Buffer.reserve(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::~Stream()
|
Stream::~Stream()
|
||||||
{
|
{
|
||||||
Stream::Buffer.clear();
|
Stream::Buffer.clear();
|
||||||
|
|
||||||
if (Stream::CriticalSectionState != 0)
|
if (Stream::CriticalSectionState != 0)
|
||||||
{
|
{
|
||||||
MessageBoxA(0, Utils::VA("Invalid critical section state '%i' for stream destruction!", Stream::CriticalSectionState), "WARNING", MB_ICONEXCLAMATION);
|
MessageBoxA(0, Utils::String::VA("Invalid critical section state '%i' for stream destruction!", Stream::CriticalSectionState), "WARNING", MB_ICONEXCLAMATION);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t Stream::Length()
|
size_t Stream::Length()
|
||||||
{
|
{
|
||||||
return Stream::Buffer.length();
|
return Stream::Buffer.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Stream::Capacity()
|
size_t Stream::Capacity()
|
||||||
{
|
{
|
||||||
return Stream::Buffer.capacity();
|
return Stream::Buffer.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::Save(const void* _str, size_t size, size_t count)
|
char* Stream::Save(const void* _str, size_t size, size_t count)
|
||||||
{
|
{
|
||||||
return Stream::Save(Stream::GetCurrentBlock(), _str, size, count);
|
return Stream::Save(Stream::GetCurrentBlock(), _str, size, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::Save(Game::XFILE_BLOCK_TYPES stream, const void * _str, size_t size, size_t count)
|
char* Stream::Save(Game::XFILE_BLOCK_TYPES stream, const void * _str, size_t size, size_t count)
|
||||||
{
|
{
|
||||||
//if (stream == XFILE_BLOCK_TEMP || stream == XFILE_BLOCK_VIRTUAL || stream == XFILE_BLOCK_PHYSICAL) // Only those seem to actually write data.
|
//if (stream == XFILE_BLOCK_TEMP || stream == XFILE_BLOCK_VIRTUAL || stream == XFILE_BLOCK_PHYSICAL) // Only those seem to actually write data.
|
||||||
// As I'm not sure though, I'll still write the data
|
// As I'm not sure though, I'll still write the data
|
||||||
// Use IncreaseBlockSize to fill virtual streams
|
// Use IncreaseBlockSize to fill virtual streams
|
||||||
auto data = Stream::Data();
|
auto data = Stream::Data();
|
||||||
|
|
||||||
if (Stream::IsCriticalSection() && Stream::Length() + (size * count) > Stream::Capacity())
|
if (Stream::IsCriticalSection() && Stream::Length() + (size * count) > Stream::Capacity())
|
||||||
{
|
{
|
||||||
MessageBoxA(0, Utils::VA("Potential stream reallocation during critical operation detected! Writing data of the length 0x%X exceeds the allocated stream size of 0x%X\n", (size * count), Stream::Capacity()), "ERROR", MB_ICONERROR);
|
MessageBoxA(0, Utils::String::VA("Potential stream reallocation during critical operation detected! Writing data of the length 0x%X exceeds the allocated stream size of 0x%X\n", (size * count), Stream::Capacity()), "ERROR", MB_ICONERROR);
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Buffer.append(static_cast<const char*>(_str), size * count);
|
Stream::Buffer.append(static_cast<const char*>(_str), size * count);
|
||||||
|
|
||||||
if (Stream::Data() != data && Stream::IsCriticalSection())
|
if (Stream::Data() != data && Stream::IsCriticalSection())
|
||||||
{
|
{
|
||||||
MessageBoxA(0, "Stream reallocation during critical operations not permitted!\nPlease increase the initial memory size or reallocate memory during non-critical sections!", "ERROR", MB_ICONERROR);
|
MessageBoxA(0, "Stream reallocation during critical operations not permitted!\nPlease increase the initial memory size or reallocate memory during non-critical sections!", "ERROR", MB_ICONERROR);
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::IncreaseBlockSize(stream, size * count);
|
Stream::IncreaseBlockSize(stream, size * count);
|
||||||
|
|
||||||
return Stream::At() - (size * count);
|
return Stream::At() - (size * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::Save(Game::XFILE_BLOCK_TYPES stream, int value, size_t count)
|
char* Stream::Save(Game::XFILE_BLOCK_TYPES stream, int value, size_t count)
|
||||||
{
|
{
|
||||||
auto ret = Stream::Length();
|
auto ret = Stream::Length();
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
Stream::Save(stream, &value, 4, 1);
|
Stream::Save(stream, &value, 4, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Stream::Data() + ret;
|
return Stream::Data() + ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveString(std::string string)
|
char* Stream::SaveString(std::string string)
|
||||||
{
|
{
|
||||||
return Stream::SaveString(string.data()/*, string.size()*/);
|
return Stream::SaveString(string.data()/*, string.size()*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveString(const char* string)
|
char* Stream::SaveString(const char* string)
|
||||||
{
|
{
|
||||||
return Stream::SaveString(string, strlen(string));
|
return Stream::SaveString(string, strlen(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveString(const char* string, size_t len)
|
char* Stream::SaveString(const char* string, size_t len)
|
||||||
{
|
{
|
||||||
auto ret = Stream::Length();
|
auto ret = Stream::Length();
|
||||||
|
|
||||||
if (string)
|
if (string)
|
||||||
{
|
{
|
||||||
Stream::Save(string, len);
|
Stream::Save(string, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::SaveNull();
|
Stream::SaveNull();
|
||||||
|
|
||||||
return Stream::Data() + ret;
|
return Stream::Data() + ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveText(std::string string)
|
char* Stream::SaveText(std::string string)
|
||||||
{
|
{
|
||||||
return Stream::Save(string.data(), string.length());
|
return Stream::Save(string.data(), string.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveByte(unsigned char byte, size_t count)
|
char* Stream::SaveByte(unsigned char byte, size_t count)
|
||||||
{
|
{
|
||||||
auto ret = Stream::Length();
|
auto ret = Stream::Length();
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
Stream::Save(&byte, 1);
|
Stream::Save(&byte, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Stream::Data() + ret;
|
return Stream::Data() + ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveNull(size_t count)
|
char* Stream::SaveNull(size_t count)
|
||||||
{
|
{
|
||||||
return Stream::SaveByte(0, count);
|
return Stream::SaveByte(0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::SaveMax(size_t count)
|
char* Stream::SaveMax(size_t count)
|
||||||
{
|
{
|
||||||
return Stream::SaveByte(static_cast<unsigned char>(-1), count);
|
return Stream::SaveByte(static_cast<unsigned char>(-1), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::Align(Stream::Alignment align)
|
void Stream::Align(Stream::Alignment align)
|
||||||
{
|
{
|
||||||
uint32_t size = 2 << align;
|
uint32_t size = 2 << align;
|
||||||
|
|
||||||
// Not power of 2!
|
// Not power of 2!
|
||||||
if (!size || (size & (size - 1))) return;
|
if (!size || (size & (size - 1))) return;
|
||||||
--size;
|
--size;
|
||||||
|
|
||||||
Game::XFILE_BLOCK_TYPES stream = Stream::GetCurrentBlock();
|
Game::XFILE_BLOCK_TYPES stream = Stream::GetCurrentBlock();
|
||||||
Stream::BlockSize[stream] = ~size & (Stream::GetBlockSize(stream) + size);
|
Stream::BlockSize[stream] = ~size & (Stream::GetBlockSize(stream) + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::PushBlock(Game::XFILE_BLOCK_TYPES stream)
|
bool Stream::PushBlock(Game::XFILE_BLOCK_TYPES stream)
|
||||||
{
|
{
|
||||||
Stream::StreamStack.push_back(stream);
|
Stream::StreamStack.push_back(stream);
|
||||||
return Stream::IsValidBlock(stream);
|
return Stream::IsValidBlock(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::PopBlock()
|
bool Stream::PopBlock()
|
||||||
{
|
{
|
||||||
if (!Stream::StreamStack.empty())
|
if (!Stream::StreamStack.empty())
|
||||||
{
|
{
|
||||||
Stream::StreamStack.pop_back();
|
Stream::StreamStack.pop_back();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::IsValidBlock(Game::XFILE_BLOCK_TYPES stream)
|
bool Stream::IsValidBlock(Game::XFILE_BLOCK_TYPES stream)
|
||||||
{
|
{
|
||||||
return (stream < Game::MAX_XFILE_COUNT && stream >= Game::XFILE_BLOCK_TEMP);
|
return (stream < Game::MAX_XFILE_COUNT && stream >= Game::XFILE_BLOCK_TEMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::IncreaseBlockSize(Game::XFILE_BLOCK_TYPES stream, unsigned int size)
|
void Stream::IncreaseBlockSize(Game::XFILE_BLOCK_TYPES stream, unsigned int size)
|
||||||
{
|
{
|
||||||
if (Stream::IsValidBlock(stream))
|
if (Stream::IsValidBlock(stream))
|
||||||
{
|
{
|
||||||
Stream::BlockSize[stream] += size;
|
Stream::BlockSize[stream] += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::IncreaseBlockSize(unsigned int size)
|
void Stream::IncreaseBlockSize(unsigned int size)
|
||||||
{
|
{
|
||||||
return IncreaseBlockSize(Stream::GetCurrentBlock(), size);
|
return IncreaseBlockSize(Stream::GetCurrentBlock(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::XFILE_BLOCK_TYPES Stream::GetCurrentBlock()
|
Game::XFILE_BLOCK_TYPES Stream::GetCurrentBlock()
|
||||||
{
|
{
|
||||||
if (!Stream::StreamStack.empty())
|
if (!Stream::StreamStack.empty())
|
||||||
{
|
{
|
||||||
return Stream::StreamStack.back();
|
return Stream::StreamStack.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Game::XFILE_BLOCK_INVALID;
|
return Game::XFILE_BLOCK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::At()
|
char* Stream::At()
|
||||||
{
|
{
|
||||||
return reinterpret_cast<char*>(Stream::Data() + Stream::Length());
|
return reinterpret_cast<char*>(Stream::Data() + Stream::Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Stream::Data()
|
char* Stream::Data()
|
||||||
{
|
{
|
||||||
return const_cast<char*>(Stream::Buffer.data());
|
return const_cast<char*>(Stream::Buffer.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Stream::GetBlockSize(Game::XFILE_BLOCK_TYPES stream)
|
unsigned int Stream::GetBlockSize(Game::XFILE_BLOCK_TYPES stream)
|
||||||
{
|
{
|
||||||
if (Stream::IsValidBlock(stream))
|
if (Stream::IsValidBlock(stream))
|
||||||
{
|
{
|
||||||
return Stream::BlockSize[stream];
|
return Stream::BlockSize[stream];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Stream::GetPackedOffset()
|
DWORD Stream::GetPackedOffset()
|
||||||
{
|
{
|
||||||
Game::XFILE_BLOCK_TYPES block = Stream::GetCurrentBlock();
|
Game::XFILE_BLOCK_TYPES block = Stream::GetCurrentBlock();
|
||||||
|
|
||||||
Stream::Offset offset;
|
Stream::Offset offset;
|
||||||
offset.block = block;
|
offset.block = block;
|
||||||
offset.offset = Stream::GetBlockSize(block);
|
offset.offset = Stream::GetBlockSize(block);
|
||||||
return offset.GetPackedOffset();
|
return offset.GetPackedOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::ToBuffer(std::string& outBuffer)
|
void Stream::ToBuffer(std::string& outBuffer)
|
||||||
{
|
{
|
||||||
outBuffer.clear();
|
outBuffer.clear();
|
||||||
outBuffer.append(Stream::Data(), Stream::Length());
|
outBuffer.append(Stream::Data(), Stream::Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Stream::ToBuffer()
|
std::string Stream::ToBuffer()
|
||||||
{
|
{
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
Stream::ToBuffer(buffer);
|
Stream::ToBuffer(buffer);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::EnterCriticalSection()
|
void Stream::EnterCriticalSection()
|
||||||
{
|
{
|
||||||
++Stream::CriticalSectionState;
|
++Stream::CriticalSectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::LeaveCriticalSection()
|
void Stream::LeaveCriticalSection()
|
||||||
{
|
{
|
||||||
--Stream::CriticalSectionState;
|
--Stream::CriticalSectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::IsCriticalSection()
|
bool Stream::IsCriticalSection()
|
||||||
{
|
{
|
||||||
if (Stream::CriticalSectionState < 0)
|
if (Stream::CriticalSectionState < 0)
|
||||||
{
|
{
|
||||||
MessageBoxA(0, "CriticalSectionState in stream has been overrun!", "ERROR", MB_ICONERROR);
|
MessageBoxA(0, "CriticalSectionState in stream has been overrun!", "ERROR", MB_ICONERROR);
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Stream::CriticalSectionState != 0);
|
return (Stream::CriticalSectionState != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
119
src/Utils/String.cpp
Normal file
119
src/Utils/String.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace String
|
||||||
|
{
|
||||||
|
std::string StrToLower(std::string input)
|
||||||
|
{
|
||||||
|
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StrToUpper(std::string input)
|
||||||
|
{
|
||||||
|
std::transform(input.begin(), input.end(), input.begin(), ::toupper);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndsWith(std::string haystack, std::string needle)
|
||||||
|
{
|
||||||
|
return (strstr(haystack.data(), needle.data()) == (haystack.data() + haystack.size() - needle.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DumpHex(std::string data, std::string separator)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
result.append(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(fmt::sprintf("%02X", data[i] & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string XORString(std::string str, char value)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < str.size(); ++i)
|
||||||
|
{
|
||||||
|
str[i] ^= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Explode(const std::string& str, char delim)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::istringstream iss(str);
|
||||||
|
|
||||||
|
for (std::string token; std::getline(iss, token, delim);)
|
||||||
|
{
|
||||||
|
std::string _entry = std::move(token);
|
||||||
|
|
||||||
|
// Remove trailing 0x0 bytes
|
||||||
|
while (_entry.size() && !_entry[_entry.size() - 1])
|
||||||
|
{
|
||||||
|
_entry = _entry.substr(0, _entry.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Replace(std::string &string, std::string find, std::string replace)
|
||||||
|
{
|
||||||
|
size_t nPos = 0;
|
||||||
|
|
||||||
|
while ((nPos = string.find(find, nPos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
string = string.replace(nPos, find.length(), replace);
|
||||||
|
nPos += replace.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartsWith(std::string haystack, std::string needle)
|
||||||
|
{
|
||||||
|
return (haystack.size() >= needle.size() && !strncmp(needle.data(), haystack.data(), needle.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from start
|
||||||
|
std::string <rim(std::string &s)
|
||||||
|
{
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from end
|
||||||
|
std::string &RTrim(std::string &s)
|
||||||
|
{
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from both ends
|
||||||
|
std::string &Trim(std::string &s)
|
||||||
|
{
|
||||||
|
return LTrim(RTrim(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FormatTimeSpan(int milliseconds)
|
||||||
|
{
|
||||||
|
int secondsTotal = milliseconds / 1000;
|
||||||
|
int seconds = secondsTotal % 60;
|
||||||
|
int minutesTotal = secondsTotal / 60;
|
||||||
|
int minutes = minutesTotal % 60;
|
||||||
|
int hoursTotal = minutesTotal / 60;
|
||||||
|
|
||||||
|
return fmt::sprintf("%02d:%02d:%02d", hoursTotal, minutes, seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/Utils/String.hpp
Normal file
38
src/Utils/String.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
namespace String
|
||||||
|
{
|
||||||
|
template <typename ...Args>
|
||||||
|
const char* VA(std::string message, Args && ...args)
|
||||||
|
{
|
||||||
|
#define VA_BUFFER_COUNT 4
|
||||||
|
#define VA_BUFFER_SIZE 65536
|
||||||
|
|
||||||
|
static char g_vaBuffer[VA_BUFFER_COUNT][VA_BUFFER_SIZE];
|
||||||
|
static int g_vaNextBufferIndex = 0;
|
||||||
|
|
||||||
|
char* buffer = g_vaBuffer[g_vaNextBufferIndex];
|
||||||
|
std::string str = fmt::sprintf(message, std::forward<Args>(args)...);
|
||||||
|
strncpy_s(g_vaBuffer[g_vaNextBufferIndex], str.data(), VA_BUFFER_SIZE);
|
||||||
|
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StrToLower(std::string input);
|
||||||
|
std::string StrToUpper(std::string input);
|
||||||
|
bool EndsWith(std::string haystack, std::string needle);
|
||||||
|
std::vector<std::string> Explode(const std::string& str, char delim);
|
||||||
|
void Replace(std::string &string, std::string find, std::string replace);
|
||||||
|
bool StartsWith(std::string haystack, std::string needle);
|
||||||
|
std::string <rim(std::string &s);
|
||||||
|
std::string &RTrim(std::string &s);
|
||||||
|
std::string &Trim(std::string &s);
|
||||||
|
|
||||||
|
std::string FormatTimeSpan(int milliseconds);
|
||||||
|
|
||||||
|
std::string DumpHex(std::string data, std::string separator = " ");
|
||||||
|
|
||||||
|
std::string XORString(std::string str, char value);
|
||||||
|
}
|
||||||
|
}
|
@ -1,287 +1,41 @@
|
|||||||
#include "STDInclude.hpp"
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
#define VA_BUFFER_COUNT 4
|
namespace Utils
|
||||||
#define VA_BUFFER_SIZE 65536
|
{
|
||||||
|
std::string GetMimeType(std::string url)
|
||||||
namespace Utils
|
{
|
||||||
{
|
wchar_t* mimeType = nullptr;
|
||||||
std::string GetMimeType(std::string url)
|
FindMimeFromData(NULL, std::wstring(url.begin(), url.end()).data(), NULL, 0, NULL, 0, &mimeType, 0);
|
||||||
{
|
|
||||||
wchar_t* mimeType = nullptr;
|
if (mimeType)
|
||||||
FindMimeFromData(NULL, std::wstring(url.begin(), url.end()).data(), NULL, 0, NULL, 0, &mimeType, 0);
|
{
|
||||||
|
std::wstring wMimeType(mimeType);
|
||||||
if (mimeType)
|
return std::string(wMimeType.begin(), wMimeType.end());
|
||||||
{
|
}
|
||||||
std::wstring wMimeType(mimeType);
|
|
||||||
return std::string(wMimeType.begin(), wMimeType.end());
|
return "application/octet-stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "application/octet-stream";
|
// Complementary function for memset, which checks if a memory is set
|
||||||
}
|
bool MemIsSet(void* mem, char chr, size_t length)
|
||||||
|
{
|
||||||
const char *VA(const char *fmt, ...)
|
char* memArr = reinterpret_cast<char*>(mem);
|
||||||
{
|
|
||||||
static char g_vaBuffer[VA_BUFFER_COUNT][VA_BUFFER_SIZE];
|
for (size_t i = 0; i < length; ++i)
|
||||||
static int g_vaNextBufferIndex = 0;
|
{
|
||||||
|
if (memArr[i] != chr)
|
||||||
va_list ap;
|
{
|
||||||
va_start(ap, fmt);
|
return false;
|
||||||
char* dest = g_vaBuffer[g_vaNextBufferIndex];
|
}
|
||||||
vsnprintf(g_vaBuffer[g_vaNextBufferIndex], VA_BUFFER_SIZE, fmt, ap);
|
}
|
||||||
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT;
|
|
||||||
va_end(ap);
|
return true;
|
||||||
return dest;
|
}
|
||||||
}
|
|
||||||
|
std::string ParseChallenge(std::string data)
|
||||||
std::string StrToLower(std::string input)
|
{
|
||||||
{
|
auto pos = data.find_first_of("\n ");
|
||||||
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
|
if (pos == std::string::npos) return data;
|
||||||
return input;
|
return data.substr(0, pos).data();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
std::string StrToUpper(std::string input)
|
|
||||||
{
|
|
||||||
std::transform(input.begin(), input.end(), input.begin(), ::toupper);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EndsWith(std::string haystack, std::string needle)
|
|
||||||
{
|
|
||||||
return (strstr(haystack.data(), needle.data()) == (haystack.data() + haystack.size() - needle.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DumpHex(std::string data, std::string separator)
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data.size(); ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
result.append(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.append(Utils::VA("%02X", data[i] & 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string XORString(std::string str, char value)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < str.size(); ++i)
|
|
||||||
{
|
|
||||||
str[i] ^= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complementary function for memset, which checks if a memory is set
|
|
||||||
bool MemIsSet(void* mem, char chr, size_t length)
|
|
||||||
{
|
|
||||||
char* memArr = reinterpret_cast<char*>(mem);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
|
||||||
{
|
|
||||||
if (memArr[i] != chr)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> Explode(const std::string& str, char delim)
|
|
||||||
{
|
|
||||||
std::vector<std::string> result;
|
|
||||||
std::istringstream iss(str);
|
|
||||||
|
|
||||||
for (std::string token; std::getline(iss, token, delim);)
|
|
||||||
{
|
|
||||||
std::string _entry = std::move(token);
|
|
||||||
|
|
||||||
// Remove trailing 0x0 bytes
|
|
||||||
while (_entry.size() && !_entry[_entry.size() - 1])
|
|
||||||
{
|
|
||||||
_entry = _entry.substr(0, _entry.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push_back(_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Replace(std::string &string, std::string find, std::string replace)
|
|
||||||
{
|
|
||||||
size_t nPos = 0;
|
|
||||||
|
|
||||||
while ((nPos = string.find(find, nPos)) != std::string::npos)
|
|
||||||
{
|
|
||||||
string = string.replace(nPos, find.length(), replace);
|
|
||||||
nPos += replace.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StartsWith(std::string haystack, std::string needle)
|
|
||||||
{
|
|
||||||
return (haystack.size() >= needle.size() && !strncmp(needle.data(), haystack.data(), needle.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim from start
|
|
||||||
std::string <rim(std::string &s)
|
|
||||||
{
|
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim from end
|
|
||||||
std::string &RTrim(std::string &s)
|
|
||||||
{
|
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim from both ends
|
|
||||||
std::string &Trim(std::string &s)
|
|
||||||
{
|
|
||||||
return LTrim(RTrim(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FormatTimeSpan(int milliseconds)
|
|
||||||
{
|
|
||||||
int secondsTotal = milliseconds / 1000;
|
|
||||||
int seconds = secondsTotal % 60;
|
|
||||||
int minutesTotal = secondsTotal / 60;
|
|
||||||
int minutes = minutesTotal % 60;
|
|
||||||
int hoursTotal = minutesTotal / 60;
|
|
||||||
|
|
||||||
return Utils::VA("%02d:%02d:%02d", hoursTotal, minutes, seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ParseChallenge(std::string data)
|
|
||||||
{
|
|
||||||
auto pos = data.find_first_of("\n ");
|
|
||||||
if (pos == std::string::npos) return data;
|
|
||||||
return data.substr(0, pos).data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use modern file reading methods
|
|
||||||
bool FileExists(std::string file)
|
|
||||||
{
|
|
||||||
FILE* fp;
|
|
||||||
fopen_s(&fp, file.data(), "r");
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteFile(std::string file, std::string data)
|
|
||||||
{
|
|
||||||
std::ofstream stream(file, std::ios::binary);
|
|
||||||
|
|
||||||
if (stream.is_open())
|
|
||||||
{
|
|
||||||
stream.write(data.data(), data.size());
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ReadFile(std::string file)
|
|
||||||
{
|
|
||||||
std::string buffer;
|
|
||||||
|
|
||||||
if (FileExists(file))
|
|
||||||
{
|
|
||||||
std::streamsize size = 0;
|
|
||||||
std::ifstream stream(file, std::ios::binary);
|
|
||||||
if (!stream.is_open()) return buffer;
|
|
||||||
|
|
||||||
stream.seekg(0, std::ios::end);
|
|
||||||
size = stream.tellg();
|
|
||||||
stream.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
if (size > -1)
|
|
||||||
{
|
|
||||||
buffer.clear();
|
|
||||||
buffer.resize((uint32_t)size);
|
|
||||||
|
|
||||||
stream.read(const_cast<char*>(buffer.data()), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infostring class
|
|
||||||
void InfoString::Set(std::string key, std::string value)
|
|
||||||
{
|
|
||||||
this->KeyValuePairs[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string InfoString::Get(std::string key)
|
|
||||||
{
|
|
||||||
if (this->KeyValuePairs.find(key) != this->KeyValuePairs.end())
|
|
||||||
{
|
|
||||||
return this->KeyValuePairs[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string InfoString::Build()
|
|
||||||
{
|
|
||||||
std::string infoString;
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); ++i)
|
|
||||||
{
|
|
||||||
if (first) first = false;
|
|
||||||
else infoString.append("\\");
|
|
||||||
|
|
||||||
infoString.append(i->first); // Key
|
|
||||||
infoString.append("\\");
|
|
||||||
infoString.append(i->second); // Value
|
|
||||||
}
|
|
||||||
|
|
||||||
return infoString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfoString::Dump()
|
|
||||||
{
|
|
||||||
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); ++i)
|
|
||||||
{
|
|
||||||
OutputDebugStringA(Utils::VA("%s: %s", i->first.data(), i->second.data()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json11::Json InfoString::to_json()
|
|
||||||
{
|
|
||||||
return this->KeyValuePairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfoString::Parse(std::string buffer)
|
|
||||||
{
|
|
||||||
if (buffer[0] == '\\')
|
|
||||||
{
|
|
||||||
buffer = buffer.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> KeyValues = Utils::Explode(buffer, '\\');
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (KeyValues.size() - 1); i+=2)
|
|
||||||
{
|
|
||||||
this->KeyValuePairs[KeyValues[i]] = KeyValues[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,69 +1,25 @@
|
|||||||
#define ARR_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
namespace Utils
|
||||||
|
{
|
||||||
namespace Utils
|
std::string GetMimeType(std::string url);
|
||||||
{
|
std::string ParseChallenge(std::string data);
|
||||||
std::string GetMimeType(std::string url);
|
bool MemIsSet(void* mem, char chr, size_t length);
|
||||||
const char *VA(const char *fmt, ...);
|
|
||||||
std::string StrToLower(std::string input);
|
template <typename T> void Merge(std::vector<T>* target, T* source, size_t length)
|
||||||
std::string StrToUpper(std::string input);
|
{
|
||||||
bool EndsWith(std::string haystack, std::string needle);
|
if (source)
|
||||||
std::vector<std::string> Explode(const std::string& str, char delim);
|
{
|
||||||
void Replace(std::string &string, std::string find, std::string replace);
|
for (size_t i = 0; i < length; ++i)
|
||||||
bool StartsWith(std::string haystack, std::string needle);
|
{
|
||||||
std::string <rim(std::string &s);
|
target->push_back(source[i]);
|
||||||
std::string &RTrim(std::string &s);
|
}
|
||||||
std::string &Trim(std::string &s);
|
}
|
||||||
|
}
|
||||||
std::string FormatTimeSpan(int milliseconds);
|
|
||||||
std::string ParseChallenge(std::string data);
|
template <typename T> void Merge(std::vector<T>* target, std::vector<T> source)
|
||||||
|
{
|
||||||
bool FileExists(std::string file);
|
for (auto &entry : source)
|
||||||
void WriteFile(std::string file, std::string data);
|
{
|
||||||
std::string ReadFile(std::string file);
|
target->push_back(entry);
|
||||||
|
}
|
||||||
std::string DumpHex(std::string data, std::string separator = " ");
|
}
|
||||||
|
}
|
||||||
std::string XORString(std::string str, char value);
|
|
||||||
|
|
||||||
bool MemIsSet(void* mem, char chr, size_t length);
|
|
||||||
|
|
||||||
class InfoString
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InfoString() {};
|
|
||||||
InfoString(std::string buffer) : InfoString() { this->Parse(buffer); };
|
|
||||||
InfoString(const InfoString &obj) : KeyValuePairs(obj.KeyValuePairs) {};
|
|
||||||
|
|
||||||
void Set(std::string key, std::string value);
|
|
||||||
std::string Get(std::string key);
|
|
||||||
|
|
||||||
std::string Build();
|
|
||||||
|
|
||||||
void Dump();
|
|
||||||
|
|
||||||
json11::Json to_json();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<std::string, std::string> KeyValuePairs;
|
|
||||||
void Parse(std::string buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> void Merge(std::vector<T>* target, T* source, size_t length)
|
|
||||||
{
|
|
||||||
if (source)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
|
||||||
{
|
|
||||||
target->push_back(source[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void Merge(std::vector<T>* target, std::vector<T> source)
|
|
||||||
{
|
|
||||||
for (auto &entry : source)
|
|
||||||
{
|
|
||||||
target->push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user