Merge remote-tracking branch 'upstream/main' into usermaps
This commit is contained in:
commit
9f8537ae7b
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -79,7 +79,7 @@ jobs:
|
||||
name: Deploy artifacts
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
|
||||
if: github.repository_owner == 'momo5502' && github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
|
||||
steps:
|
||||
- name: Setup environment
|
||||
run: echo "BOIII_MASTER_PATH=${{ secrets.BOIII_MASTER_SSH_PATH }}" >> $GITHUB_ENV
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
uses: actions/download-artifact@v3.0.2
|
||||
with:
|
||||
name: Release Binary
|
||||
|
||||
|
||||
- name: Download Release data artifacts
|
||||
uses: actions/download-artifact@v3.0.2
|
||||
with:
|
||||
@ -107,7 +107,7 @@ jobs:
|
||||
uses: shimataro/ssh-key-action@v2.5.0
|
||||
with:
|
||||
key: ${{ secrets.BOIII_MASTER_SSH_PRIVATE_KEY }}
|
||||
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
||||
known_hosts: "just-a-placeholder-so-we-dont-get-errors"
|
||||
|
||||
- name: Add known hosts
|
||||
run: ssh-keyscan -H ${{ secrets.BOIII_MASTER_SSH_ADDRESS }} >> ~/.ssh/known_hosts
|
||||
|
17
.github/workflows/discord-notify.yml
vendored
Normal file
17
.github/workflows/discord-notify.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Notify Discord
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
issues:
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'momo5502'
|
||||
steps:
|
||||
- name: Send notification to Discord
|
||||
uses: Ilshidur/action-discord@master
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_CI_BOT_WEBHOOK }}
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
||||
Subproject commit 915186f6c5c2f5a4638e5cb97ccc23d741521a64
|
||||
Subproject commit 1098b7d8873777f281e54a84a2b422fec30d91d4
|
2
deps/curl
vendored
2
deps/curl
vendored
@ -1 +1 @@
|
||||
Subproject commit ad4997e5b289c97724fdcbaeb3c8c50222a757c4
|
||||
Subproject commit 93eefa6ba134aceef4f6cd51fc602319b382e629
|
2
deps/rapidjson
vendored
2
deps/rapidjson
vendored
@ -1 +1 @@
|
||||
Subproject commit 012be8528783cdbf4b7a9e64f78bd8f056b97e24
|
||||
Subproject commit 083f359f5c36198accc2b9360ce1e32a333231d9
|
103
src/client/component/name.cpp
Normal file
103
src/client/component/name.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "name.hpp"
|
||||
#include "steam_proxy.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace name
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::concurrency::container<std::string> player_name{};
|
||||
|
||||
void store_player_name(const std::string& name)
|
||||
{
|
||||
utils::properties::store("playerName", name);
|
||||
}
|
||||
|
||||
void activate_player_name(std::string new_name)
|
||||
{
|
||||
player_name.access([&](std::string& name)
|
||||
{
|
||||
name = std::move(new_name);
|
||||
});
|
||||
}
|
||||
|
||||
void update_player_name(const std::string& new_name)
|
||||
{
|
||||
store_player_name(new_name);
|
||||
activate_player_name(new_name);
|
||||
}
|
||||
|
||||
void setup_player_name()
|
||||
{
|
||||
std::string initial_name = steam_proxy::get_player_name();
|
||||
|
||||
if (initial_name.empty())
|
||||
{
|
||||
initial_name = utils::nt::get_user_name();
|
||||
}
|
||||
|
||||
if (initial_name.empty())
|
||||
{
|
||||
initial_name = "Unknown Soldier";
|
||||
}
|
||||
|
||||
update_player_name(initial_name);
|
||||
}
|
||||
|
||||
void load_player_name()
|
||||
{
|
||||
const auto stored_name = utils::properties::load("playerName");
|
||||
|
||||
if (stored_name)
|
||||
{
|
||||
activate_player_name(*stored_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_player_name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct component final : client_component
|
||||
{
|
||||
void post_load() override
|
||||
{
|
||||
load_player_name();
|
||||
}
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
command::add("name", [](const command::params& params)
|
||||
{
|
||||
if (params.size() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update_player_name(params[1]);
|
||||
});
|
||||
}
|
||||
|
||||
component_priority priority() const override
|
||||
{
|
||||
return component_priority::name;
|
||||
}
|
||||
};
|
||||
|
||||
const char* get_player_name()
|
||||
{
|
||||
const auto name = player_name.copy();
|
||||
return utils::string::va("%.*s", static_cast<int>(name.size()), name.data());
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(name::component)
|
6
src/client/component/name.hpp
Normal file
6
src/client/component/name.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace name
|
||||
{
|
||||
const char* get_player_name();
|
||||
}
|
@ -265,6 +265,9 @@ namespace network
|
||||
|
||||
// Kill lobby system
|
||||
handle_packet_internal_hook.create(game::select(0x141EF7FE0, 0x1404A5B90), &handle_packet_internal_stub);
|
||||
|
||||
// Kill voice chat
|
||||
utils::hook::set<uint32_t>(game::select(0x141359310, 0x14018FE40), 0xC3C03148);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -194,14 +194,18 @@ namespace party
|
||||
|
||||
void connect_stub(const char* address)
|
||||
{
|
||||
const auto target = network::address_from_string(address);
|
||||
if (target.type == game::NA_BAD)
|
||||
if (address)
|
||||
{
|
||||
return;
|
||||
const auto target = network::address_from_string(address);
|
||||
if (target.type == game::NA_BAD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
connect_host = target;
|
||||
}
|
||||
|
||||
connect_host = target;
|
||||
query_server(target, handle_connect_query_response);
|
||||
query_server(connect_host, handle_connect_query_response);
|
||||
}
|
||||
|
||||
void send_server_query(server_query& query)
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <utils/finally.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#include "game/utils.hpp"
|
||||
|
||||
#include "steam/interface.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
@ -252,7 +254,7 @@ namespace steam_proxy
|
||||
return client_friends.invoke<const char*>("GetPersonaName");
|
||||
}
|
||||
|
||||
return "boiii";
|
||||
return "";
|
||||
}
|
||||
|
||||
void update_subscribed_items()
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
namespace steam_proxy
|
||||
{
|
||||
const utils::nt::library& get_overlay_module();
|
||||
|
@ -10,7 +10,8 @@ namespace game
|
||||
|
||||
// CL
|
||||
WEAK symbol<void(int controllerIndex, XSESSION_INFO* hostInfo, const netadr_t* addr, int numPublicSlots,
|
||||
int numPrivateSlots, const char* mapname, const char* gametype, const char* somethingWithUserMaps)> CL_ConnectFromLobby
|
||||
int numPrivateSlots, const char* mapname, const char* gametype,
|
||||
const char* somethingWithUserMaps)> CL_ConnectFromLobby
|
||||
{0x14134C570};
|
||||
|
||||
// Game
|
||||
@ -24,7 +25,9 @@ namespace game
|
||||
WEAK symbol<void(eNetworkModes networkMode)> Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80};
|
||||
WEAK symbol<eGameModes(eGameModes gameMode)> Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40};
|
||||
WEAK symbol<eModes(eModes mode)> Com_SessionMode_SetMode{0x1420F7570};
|
||||
WEAK symbol<void(const char* gametype, bool loadDefaultSettings, bool isModified)> Com_GametypeSettings_SetGametype{0x1420F5980};
|
||||
WEAK symbol<void(const char* gametype, bool loadDefaultSettings, bool isModified)> Com_GametypeSettings_SetGametype{
|
||||
0x1420F5980
|
||||
};
|
||||
WEAK symbol<bool()> Com_IsRunningUILevel{0x142148350};
|
||||
WEAK symbol<void(int localClientNum, eModes fromMode, eModes toMode, uint32_t flags)> Com_SwitchMode{
|
||||
0x14214A4D0
|
||||
@ -81,7 +84,7 @@ namespace game
|
||||
WEAK symbol<TLSData*()> Sys_IsDatabaseReady{0x142183A60};
|
||||
|
||||
// Unnamed
|
||||
WEAK symbol<const char* (const char* name)> CopyString{0x1422AC220, 0x14056BD70};
|
||||
WEAK symbol<const char*(const char* name)> CopyString{0x1422AC220, 0x14056BD70};
|
||||
|
||||
WEAK symbol<bool()> isModLoaded{0x1420D5020};
|
||||
WEAK symbol<void(int, const char*, int)> loadMod{0x1420D6930};
|
||||
@ -95,9 +98,14 @@ namespace game
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BF590, 0x140575E30};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x1422BC080};
|
||||
WEAK symbol<bool(const dvar_t* dvar)> Dvar_GetBool{0x1422BCED0};
|
||||
WEAK symbol<dvar_t*(dvarStrHash_t hash, const char* dvarName, bool value, dvarFlags_e flags, const char* description)> Dvar_RegisterBool{
|
||||
WEAK symbol<dvar_t*(dvarStrHash_t hash, const char* dvarName, bool value, dvarFlags_e flags,
|
||||
const char* description)> Dvar_RegisterBool{
|
||||
0x1422D0900
|
||||
};
|
||||
WEAK symbol<dvar_t*(dvarStrHash_t hash, const char* dvarName, const char* value, dvarFlags_e flags,
|
||||
const char* description)> Dvar_RegisterString{
|
||||
0x1422D0B70
|
||||
};
|
||||
WEAK symbol<void (void (*callback)(const dvar_t*, void*), void* userData)> Dvar_ForEach{0x1422BCD00};
|
||||
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
||||
0x1422C7500
|
||||
@ -108,7 +116,7 @@ namespace game
|
||||
WEAK symbol<void()> UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50};
|
||||
WEAK symbol<void()> UI_CoD_Shutdown{0x141F32E10, 0x0};
|
||||
WEAK symbol<void(const char*, const char*, int, game::hks::lua_State*)> UI_AddMenu{0x1427018F0, 0x0};
|
||||
WEAK symbol<const char* (int)> UI_CoD_GetRootNameForController{0x141F28940, 0x0};
|
||||
WEAK symbol<const char*(int)> UI_CoD_GetRootNameForController{0x141F28940, 0x0};
|
||||
WEAK symbol<void(game::hks::lua_State*, const char*)> Lua_CoD_LoadLuaFile{0x141F11A20, 0x0};
|
||||
WEAK symbol<void(int localClientNum)> CG_LUIHUDRestart{0x140F7E970};
|
||||
WEAK symbol<void(int localClientNum)> CL_CheckKeepDrawingConnectScreen{0x1413CCAE0};
|
||||
@ -122,7 +130,8 @@ namespace game
|
||||
};
|
||||
WEAK symbol<unsigned int(scriptInstance_t inst)> Scr_GetNumParam{0x0, 0x140171320};
|
||||
|
||||
WEAK symbol<void(const char* name, const char* key, unsigned int playbackFlags, float volume, void* callbackInfo, int id)> Cinematic_StartPlayback{0x1412BE3A0};
|
||||
WEAK symbol<void(const char* name, const char* key, unsigned int playbackFlags, float volume, void* callbackInfo,
|
||||
int id)> Cinematic_StartPlayback{0x1412BE3A0};
|
||||
WEAK symbol<void(uint64_t id, bool cancelAll)> Cinematic_StopPlayback{0x1412BEA70};
|
||||
|
||||
// Rendering
|
||||
@ -136,10 +145,12 @@ namespace game
|
||||
WEAK symbol<void*()> SV_AddTestClient{0x142248F40, 0x14052E3E0};
|
||||
WEAK symbol<void(client_s* cl_0, svscmd_type type, const char* fmt, ...)> SV_SendServerCommand{0x0, 0x140537F10};
|
||||
WEAK symbol<bool(int clientNum)> SV_IsTestClient{0x14224AB60, 0x14052FF40};
|
||||
WEAK symbol<void(int controllerIndex, const char* server, MapPreload preload, bool savegame)> SV_SpawnServer{0x1422528C0, 0x140535B20};
|
||||
WEAK symbol<void(int controllerIndex, const char* server, MapPreload preload, bool savegame)> SV_SpawnServer{
|
||||
0x1422528C0, 0x140535B20
|
||||
};
|
||||
|
||||
// Utils
|
||||
WEAK symbol<const char* (char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
||||
WEAK symbol<const char*(char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
||||
|
||||
// Variables
|
||||
WEAK symbol<cmd_function_s> cmd_functions{0x15689DF58, 0x14946F860};
|
||||
@ -181,18 +192,26 @@ namespace game
|
||||
|
||||
namespace hks
|
||||
{
|
||||
WEAK symbol<lua_State*> lua_state {0x159C76D88, 0x14858C408};
|
||||
WEAK symbol<lua_State*> lua_state{0x159C76D88, 0x14858C408};
|
||||
WEAK symbol<void(lua_State* s, const char* str, unsigned int l)> hksi_lua_pushlstring{0x140A18430, 0x1401DE6F0};
|
||||
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)> hks_obj_settable{0x141D4B660, 0x1403F41B0};
|
||||
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{0x141D4ABF0, 0x1403F3750};
|
||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{0x141D70FE0, 0x140418E40};
|
||||
WEAK symbol<HashTable* (lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{0x141D3B5F0, 0x1403E46D0};
|
||||
WEAK symbol<cclosure* (lua_State* s, lua_function function, int num_upvalues, int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0x141D3B7E0, 0x1403E48C0};
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)>
|
||||
hks_obj_settable{0x141D4B660, 0x1403F41B0};
|
||||
WEAK symbol<HksObject*(HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)>
|
||||
hks_obj_gettable{0x141D4ABF0, 0x1403F3750};
|
||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{
|
||||
0x141D70FE0, 0x140418E40
|
||||
};
|
||||
WEAK symbol<HashTable*(lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{
|
||||
0x141D3B5F0, 0x1403E46D0
|
||||
};
|
||||
WEAK symbol<cclosure*(lua_State* s, lua_function function, int num_upvalues, int internal_,
|
||||
int profilerTreatClosureAsFunc)> cclosure_Create{0x141D3B7E0, 0x1403E48C0};
|
||||
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{0x141D4D1A0, 0x1403F5CF0};
|
||||
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{0x141D4D320, 0x1403F5E70};
|
||||
|
||||
WEAK symbol<int(lua_State* s, const HksCompilerSettings* options, const char* buff, unsigned __int64 sz, const char* name)> hksi_hksL_loadbuffer{0x141D4BD80, 0x1403F48D0};
|
||||
WEAK symbol<int(lua_State* s, const HksCompilerSettings* options, const char* buff, unsigned __int64 sz,
|
||||
const char* name)> hksi_hksL_loadbuffer{0x141D4BD80, 0x1403F48D0};
|
||||
WEAK symbol<int(lua_State* s, const char* what, lua_Debug* ar)> hksi_lua_getinfo{0x141D4D8D0, 0x1403F64B0};
|
||||
WEAK symbol<int(lua_State* s, int level, lua_Debug* ar)> hksi_lua_getstack{0x141D4DB90, 0x1403F6770};
|
||||
WEAK symbol<void(lua_State* s, const char* fmt, ...)> hksi_luaL_error{0x141D4D050, 0x1403F5BA0};
|
||||
|
@ -3,6 +3,8 @@
|
||||
enum class component_priority
|
||||
{
|
||||
min = 0,
|
||||
// must run after the steam_proxy
|
||||
name,
|
||||
// must run after the updater
|
||||
steam_proxy,
|
||||
updater,
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
#include "component/steam_proxy.hpp"
|
||||
#include "component/name.hpp"
|
||||
|
||||
namespace steam
|
||||
{
|
||||
const char* friends::GetPersonaName()
|
||||
{
|
||||
return steam_proxy::get_player_name();
|
||||
return name::get_player_name();
|
||||
}
|
||||
|
||||
unsigned long long friends::SetPersonaName(const char* pchPersonaName)
|
||||
|
@ -380,13 +380,13 @@ namespace updater
|
||||
legal_files.reserve(files.size());
|
||||
for (const auto& file : files)
|
||||
{
|
||||
if (file.name != UPDATE_HOST_BINARY)
|
||||
if (file.name.starts_with("data"))
|
||||
{
|
||||
legal_files.emplace_back(std::filesystem::absolute(base / file.name));
|
||||
}
|
||||
}
|
||||
|
||||
const auto existing_files = utils::io::list_files(base.string(), true);
|
||||
const auto existing_files = utils::io::list_files(base / "data", true);
|
||||
for (auto& file : existing_files)
|
||||
{
|
||||
const auto is_file = std::filesystem::is_regular_file(file);
|
||||
|
@ -39,6 +39,12 @@ namespace utils::concurrency
|
||||
T& get_raw() { return object_; }
|
||||
const T& get_raw() const { return object_; }
|
||||
|
||||
T copy() const
|
||||
{
|
||||
std::unique_lock<MutexType> lock{mutex_};
|
||||
return object_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable MutexType mutex_{};
|
||||
T object_{};
|
||||
|
44
src/common/utils/named_mutex.cpp
Normal file
44
src/common/utils/named_mutex.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "named_mutex.hpp"
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
named_mutex::named_mutex(const std::string& name)
|
||||
{
|
||||
this->handle_ = CreateMutexA(nullptr, FALSE, name.data());
|
||||
}
|
||||
|
||||
named_mutex::~named_mutex()
|
||||
{
|
||||
if (this->handle_)
|
||||
{
|
||||
CloseHandle(this->handle_);
|
||||
}
|
||||
}
|
||||
|
||||
void named_mutex::lock() const
|
||||
{
|
||||
if (this->handle_)
|
||||
{
|
||||
WaitForSingleObject(this->handle_, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
bool named_mutex::try_lock(const std::chrono::milliseconds timeout) const
|
||||
{
|
||||
if (this->handle_)
|
||||
{
|
||||
return WAIT_OBJECT_0 == WaitForSingleObject(this->handle_, static_cast<DWORD>(timeout.count()));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void named_mutex::unlock() const noexcept
|
||||
{
|
||||
if (this->handle_)
|
||||
{
|
||||
ReleaseMutex(this->handle_);
|
||||
}
|
||||
}
|
||||
}
|
26
src/common/utils/named_mutex.hpp
Normal file
26
src/common/utils/named_mutex.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class named_mutex
|
||||
{
|
||||
public:
|
||||
named_mutex(const std::string& name);
|
||||
~named_mutex();
|
||||
|
||||
named_mutex(named_mutex&&) = delete;
|
||||
named_mutex(const named_mutex&) = delete;
|
||||
named_mutex& operator=(named_mutex&&) = delete;
|
||||
named_mutex& operator=(const named_mutex&) = delete;
|
||||
|
||||
void lock() const;
|
||||
bool try_lock(std::chrono::milliseconds timeout = std::chrono::milliseconds{0}) const;
|
||||
void unlock() const noexcept;
|
||||
|
||||
private:
|
||||
void* handle_{};
|
||||
};
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
#include "nt.hpp"
|
||||
|
||||
#include <lmcons.h>
|
||||
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils::nt
|
||||
@ -234,14 +237,14 @@ namespace utils::nt
|
||||
{
|
||||
registry_key new_key{};
|
||||
if (RegOpenKeyExA(current_key, part.data(), 0,
|
||||
KEY_ALL_ACCESS, &new_key) == ERROR_SUCCESS)
|
||||
KEY_ALL_ACCESS, &new_key) == ERROR_SUCCESS)
|
||||
{
|
||||
current_key = std::move(new_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegCreateKeyExA(current_key, part.data(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
|
||||
nullptr, &new_key, nullptr) != ERROR_SUCCESS)
|
||||
nullptr, &new_key, nullptr) != ERROR_SUCCESS)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@ -310,7 +313,8 @@ namespace utils::nt
|
||||
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
|
||||
auto* const command_line = GetCommandLineA();
|
||||
|
||||
CreateProcessA(self.get_path().generic_string().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir,
|
||||
CreateProcessA(self.get_path().generic_string().data(), command_line, nullptr, nullptr, false, NULL, nullptr,
|
||||
current_dir,
|
||||
&startup_info, &process_info);
|
||||
|
||||
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
|
||||
@ -322,4 +326,16 @@ namespace utils::nt
|
||||
TerminateProcess(GetCurrentProcess(), code);
|
||||
_Exit(code);
|
||||
}
|
||||
|
||||
std::string get_user_name()
|
||||
{
|
||||
char username[UNLEN + 1];
|
||||
DWORD username_len = UNLEN + 1;
|
||||
if (!GetUserNameA(username, &username_len))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::string(username, username_len - 1);
|
||||
}
|
||||
}
|
||||
|
@ -252,4 +252,6 @@ namespace utils::nt
|
||||
|
||||
void relaunch_self();
|
||||
__declspec(noreturn) void terminate(uint32_t code = 0);
|
||||
|
||||
std::string get_user_name();
|
||||
}
|
||||
|
172
src/common/utils/properties.cpp
Normal file
172
src/common/utils/properties.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "properties.hpp"
|
||||
|
||||
#include "finally.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
|
||||
#include "io.hpp"
|
||||
#include "com.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils::properties
|
||||
{
|
||||
namespace
|
||||
{
|
||||
typedef rapidjson::GenericDocument<rapidjson::UTF16LE<>> WDocument;
|
||||
typedef rapidjson::GenericValue<rapidjson::UTF16LE<>> WValue;
|
||||
|
||||
typedef rapidjson::EncodedOutputStream<rapidjson::UTF16LE<>, rapidjson::FileWriteStream> OutputStream;
|
||||
typedef rapidjson::EncodedInputStream<rapidjson::UTF16LE<>, rapidjson::FileReadStream> InputStream;
|
||||
|
||||
std::filesystem::path get_properties_folder()
|
||||
{
|
||||
static auto props = get_appdata_path() / "user";
|
||||
return props;
|
||||
}
|
||||
|
||||
std::filesystem::path get_properties_file()
|
||||
{
|
||||
static auto props = get_properties_folder() / "properties.json";
|
||||
return props;
|
||||
}
|
||||
|
||||
WDocument load_properties()
|
||||
{
|
||||
WDocument default_doc{};
|
||||
default_doc.SetObject();
|
||||
|
||||
char read_buffer[256]; // Raw buffer for reading
|
||||
|
||||
const std::wstring& props = get_properties_file();
|
||||
|
||||
FILE* fp;
|
||||
auto err = _wfopen_s(&fp, props.data(), L"rb");
|
||||
if (err || !fp)
|
||||
{
|
||||
return default_doc;
|
||||
}
|
||||
|
||||
// This will handle the BOM
|
||||
rapidjson::FileReadStream bis(fp, read_buffer, sizeof(read_buffer));
|
||||
InputStream eis(bis);
|
||||
|
||||
WDocument doc{};
|
||||
const rapidjson::ParseResult result = doc.ParseStream<rapidjson::kParseNoFlags, rapidjson::UTF16LE<>>(eis);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!result || !doc.IsObject())
|
||||
{
|
||||
return default_doc;
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
void store_properties(const WDocument& doc)
|
||||
{
|
||||
char write_buffer[256]; // Raw buffer for writing
|
||||
|
||||
const std::wstring& props = get_properties_file();
|
||||
io::create_directory(get_properties_folder());
|
||||
|
||||
FILE* fp;
|
||||
auto err = _wfopen_s(&fp, props.data(), L"wb");
|
||||
if (err || !fp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rapidjson::FileWriteStream bos(fp, write_buffer, sizeof(write_buffer));
|
||||
OutputStream eos(bos, true); // Write BOM
|
||||
|
||||
rapidjson::Writer<OutputStream, rapidjson::UTF16LE<>, rapidjson::UTF16LE<>> writer(eos);
|
||||
doc.Accept(writer);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path get_appdata_path()
|
||||
{
|
||||
PWSTR path;
|
||||
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path)))
|
||||
{
|
||||
throw std::runtime_error("Failed to read APPDATA path!");
|
||||
}
|
||||
|
||||
auto _ = utils::finally([&path]
|
||||
{
|
||||
CoTaskMemFree(path);
|
||||
});
|
||||
|
||||
static auto appdata = std::filesystem::path(path) / "boiii";
|
||||
return appdata;
|
||||
}
|
||||
|
||||
std::unique_lock<named_mutex> lock()
|
||||
{
|
||||
static named_mutex mutex{"boiii-properties-lock"};
|
||||
return std::unique_lock{mutex};
|
||||
}
|
||||
|
||||
std::optional<std::wstring> load(const std::wstring& name)
|
||||
{
|
||||
const auto _ = lock();
|
||||
const auto doc = load_properties();
|
||||
|
||||
if (!doc.HasMember(name))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& value = doc[name];
|
||||
if (!value.IsString())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return {std::wstring{value.GetString()}};
|
||||
}
|
||||
|
||||
std::optional<std::string> load(const std::string& name)
|
||||
{
|
||||
const auto result = load(string::convert(name));
|
||||
if (!result)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return {string::convert(*result)};
|
||||
}
|
||||
|
||||
void store(const std::wstring& name, const std::wstring& value)
|
||||
{
|
||||
const auto _ = lock();
|
||||
auto doc = load_properties();
|
||||
|
||||
while (doc.HasMember(name))
|
||||
{
|
||||
doc.RemoveMember(name);
|
||||
}
|
||||
|
||||
WValue key{};
|
||||
key.SetString(name, doc.GetAllocator());
|
||||
|
||||
WValue member{};
|
||||
member.SetString(value, doc.GetAllocator());
|
||||
|
||||
doc.AddMember(key, member, doc.GetAllocator());
|
||||
|
||||
store_properties(doc);
|
||||
}
|
||||
|
||||
void store(const std::string& name, const std::string& value)
|
||||
{
|
||||
store(string::convert(name), string::convert(value));
|
||||
}
|
||||
}
|
19
src/common/utils/properties.hpp
Normal file
19
src/common/utils/properties.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "named_mutex.hpp"
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <filesystem>
|
||||
|
||||
namespace utils::properties
|
||||
{
|
||||
std::filesystem::path get_appdata_path();
|
||||
|
||||
std::unique_lock<named_mutex> lock();
|
||||
|
||||
std::optional<std::wstring> load(const std::wstring& name);
|
||||
std::optional<std::string> load(const std::string& name);
|
||||
|
||||
void store(const std::wstring& name, const std::wstring& value);
|
||||
void store(const std::string& name, const std::string& value);
|
||||
}
|
Loading…
Reference in New Issue
Block a user