Merge remote-tracking branch 'upstream/main' into usermaps
This commit is contained in:
commit
9f8537ae7b
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -79,7 +79,7 @@ jobs:
|
|||||||
name: Deploy artifacts
|
name: Deploy artifacts
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- name: Setup environment
|
- name: Setup environment
|
||||||
run: echo "BOIII_MASTER_PATH=${{ secrets.BOIII_MASTER_SSH_PATH }}" >> $GITHUB_ENV
|
run: echo "BOIII_MASTER_PATH=${{ secrets.BOIII_MASTER_SSH_PATH }}" >> $GITHUB_ENV
|
||||||
@ -107,7 +107,7 @@ jobs:
|
|||||||
uses: shimataro/ssh-key-action@v2.5.0
|
uses: shimataro/ssh-key-action@v2.5.0
|
||||||
with:
|
with:
|
||||||
key: ${{ secrets.BOIII_MASTER_SSH_PRIVATE_KEY }}
|
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
|
- name: Add known hosts
|
||||||
run: ssh-keyscan -H ${{ secrets.BOIII_MASTER_SSH_ADDRESS }} >> ~/.ssh/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
|
// Kill lobby system
|
||||||
handle_packet_internal_hook.create(game::select(0x141EF7FE0, 0x1404A5B90), &handle_packet_internal_stub);
|
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,8 @@ namespace party
|
|||||||
}
|
}
|
||||||
|
|
||||||
void connect_stub(const char* address)
|
void connect_stub(const char* address)
|
||||||
|
{
|
||||||
|
if (address)
|
||||||
{
|
{
|
||||||
const auto target = network::address_from_string(address);
|
const auto target = network::address_from_string(address);
|
||||||
if (target.type == game::NA_BAD)
|
if (target.type == game::NA_BAD)
|
||||||
@ -201,7 +203,9 @@ namespace party
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void send_server_query(server_query& query)
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include <utils/finally.hpp>
|
#include <utils/finally.hpp>
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
#include "game/utils.hpp"
|
||||||
|
|
||||||
#include "steam/interface.hpp"
|
#include "steam/interface.hpp"
|
||||||
#include "steam/steam.hpp"
|
#include "steam/steam.hpp"
|
||||||
|
|
||||||
@ -252,7 +254,7 @@ namespace steam_proxy
|
|||||||
return client_friends.invoke<const char*>("GetPersonaName");
|
return client_friends.invoke<const char*>("GetPersonaName");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "boiii";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_subscribed_items()
|
void update_subscribed_items()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
namespace steam_proxy
|
namespace steam_proxy
|
||||||
{
|
{
|
||||||
const utils::nt::library& get_overlay_module();
|
const utils::nt::library& get_overlay_module();
|
||||||
|
@ -10,7 +10,8 @@ namespace game
|
|||||||
|
|
||||||
// CL
|
// CL
|
||||||
WEAK symbol<void(int controllerIndex, XSESSION_INFO* hostInfo, const netadr_t* addr, int numPublicSlots,
|
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};
|
{0x14134C570};
|
||||||
|
|
||||||
// Game
|
// Game
|
||||||
@ -24,7 +25,9 @@ namespace game
|
|||||||
WEAK symbol<void(eNetworkModes networkMode)> Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80};
|
WEAK symbol<void(eNetworkModes networkMode)> Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80};
|
||||||
WEAK symbol<eGameModes(eGameModes gameMode)> Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40};
|
WEAK symbol<eGameModes(eGameModes gameMode)> Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40};
|
||||||
WEAK symbol<eModes(eModes mode)> Com_SessionMode_SetMode{0x1420F7570};
|
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<bool()> Com_IsRunningUILevel{0x142148350};
|
||||||
WEAK symbol<void(int localClientNum, eModes fromMode, eModes toMode, uint32_t flags)> Com_SwitchMode{
|
WEAK symbol<void(int localClientNum, eModes fromMode, eModes toMode, uint32_t flags)> Com_SwitchMode{
|
||||||
0x14214A4D0
|
0x14214A4D0
|
||||||
@ -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_GetString{0x1422BF590, 0x140575E30};
|
||||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x1422BC080};
|
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_DisplayableValue{0x1422BC080};
|
||||||
WEAK symbol<bool(const dvar_t* dvar)> Dvar_GetBool{0x1422BCED0};
|
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
|
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 (void (*callback)(const dvar_t*, void*), void* userData)> Dvar_ForEach{0x1422BCD00};
|
||||||
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
||||||
0x1422C7500
|
0x1422C7500
|
||||||
@ -122,7 +130,8 @@ namespace game
|
|||||||
};
|
};
|
||||||
WEAK symbol<unsigned int(scriptInstance_t inst)> Scr_GetNumParam{0x0, 0x140171320};
|
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};
|
WEAK symbol<void(uint64_t id, bool cancelAll)> Cinematic_StopPlayback{0x1412BEA70};
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
@ -136,7 +145,9 @@ namespace game
|
|||||||
WEAK symbol<void*()> SV_AddTestClient{0x142248F40, 0x14052E3E0};
|
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<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<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
|
// Utils
|
||||||
WEAK symbol<const char*(char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
WEAK symbol<const char*(char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
||||||
@ -184,15 +195,23 @@ namespace game
|
|||||||
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 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<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)>
|
||||||
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{0x141D4ABF0, 0x1403F3750};
|
hks_obj_settable{0x141D4B660, 0x1403F41B0};
|
||||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{0x141D70FE0, 0x140418E40};
|
WEAK symbol<HksObject*(HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)>
|
||||||
WEAK symbol<HashTable* (lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{0x141D3B5F0, 0x1403E46D0};
|
hks_obj_gettable{0x141D4ABF0, 0x1403F3750};
|
||||||
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, 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<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<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, 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<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};
|
WEAK symbol<void(lua_State* s, const char* fmt, ...)> hksi_luaL_error{0x141D4D050, 0x1403F5BA0};
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
enum class component_priority
|
enum class component_priority
|
||||||
{
|
{
|
||||||
min = 0,
|
min = 0,
|
||||||
|
// must run after the steam_proxy
|
||||||
|
name,
|
||||||
// must run after the updater
|
// must run after the updater
|
||||||
steam_proxy,
|
steam_proxy,
|
||||||
updater,
|
updater,
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
#include <utils/nt.hpp>
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
#include "component/steam_proxy.hpp"
|
#include "component/name.hpp"
|
||||||
|
|
||||||
namespace steam
|
namespace steam
|
||||||
{
|
{
|
||||||
const char* friends::GetPersonaName()
|
const char* friends::GetPersonaName()
|
||||||
{
|
{
|
||||||
return steam_proxy::get_player_name();
|
return name::get_player_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long friends::SetPersonaName(const char* pchPersonaName)
|
unsigned long long friends::SetPersonaName(const char* pchPersonaName)
|
||||||
|
@ -380,13 +380,13 @@ namespace updater
|
|||||||
legal_files.reserve(files.size());
|
legal_files.reserve(files.size());
|
||||||
for (const auto& file : files)
|
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));
|
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)
|
for (auto& file : existing_files)
|
||||||
{
|
{
|
||||||
const auto is_file = std::filesystem::is_regular_file(file);
|
const auto is_file = std::filesystem::is_regular_file(file);
|
||||||
|
@ -39,6 +39,12 @@ namespace utils::concurrency
|
|||||||
T& get_raw() { return object_; }
|
T& get_raw() { return object_; }
|
||||||
const T& get_raw() const { return object_; }
|
const T& get_raw() const { return object_; }
|
||||||
|
|
||||||
|
T copy() const
|
||||||
|
{
|
||||||
|
std::unique_lock<MutexType> lock{mutex_};
|
||||||
|
return object_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable MutexType mutex_{};
|
mutable MutexType mutex_{};
|
||||||
T object_{};
|
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 "nt.hpp"
|
||||||
|
|
||||||
|
#include <lmcons.h>
|
||||||
|
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
|
|
||||||
namespace utils::nt
|
namespace utils::nt
|
||||||
@ -310,7 +313,8 @@ namespace utils::nt
|
|||||||
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
|
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
|
||||||
auto* const command_line = GetCommandLineA();
|
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);
|
&startup_info, &process_info);
|
||||||
|
|
||||||
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
|
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
|
||||||
@ -322,4 +326,16 @@ namespace utils::nt
|
|||||||
TerminateProcess(GetCurrentProcess(), code);
|
TerminateProcess(GetCurrentProcess(), code);
|
||||||
_Exit(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();
|
void relaunch_self();
|
||||||
__declspec(noreturn) void terminate(uint32_t code = 0);
|
__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