[Chat]: New save feature (#732)
This commit is contained in:
parent
5805331bfd
commit
bd7d2fe059
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
|
const char* Bans::BanListFile = "userraw/bans.json";
|
||||||
|
|
||||||
// Have only one instance of IW4x read/write the file
|
// Have only one instance of IW4x read/write the file
|
||||||
std::unique_lock<Utils::NamedMutex> Bans::Lock()
|
std::unique_lock<Utils::NamedMutex> Bans::Lock()
|
||||||
{
|
{
|
||||||
@ -89,7 +91,7 @@ namespace Components
|
|||||||
|
|
||||||
void Bans::SaveBans(const BanList* list)
|
void Bans::SaveBans(const BanList* list)
|
||||||
{
|
{
|
||||||
assert(list != nullptr);
|
assert(list);
|
||||||
|
|
||||||
const auto _ = Lock();
|
const auto _ = Lock();
|
||||||
|
|
||||||
@ -107,7 +109,8 @@ namespace Components
|
|||||||
ipEntry.bytes[0] & 0xFF,
|
ipEntry.bytes[0] & 0xFF,
|
||||||
ipEntry.bytes[1] & 0xFF,
|
ipEntry.bytes[1] & 0xFF,
|
||||||
ipEntry.bytes[2] & 0xFF,
|
ipEntry.bytes[2] & 0xFF,
|
||||||
ipEntry.bytes[3] & 0xFF));
|
ipEntry.bytes[3] & 0xFF)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nlohmann::json bans = nlohmann::json
|
const nlohmann::json bans = nlohmann::json
|
||||||
@ -116,18 +119,17 @@ namespace Components
|
|||||||
{ "id", idVector },
|
{ "id", idVector },
|
||||||
};
|
};
|
||||||
|
|
||||||
FileSystem::FileWriter ("bans.json").write(bans.dump());
|
Utils::IO::WriteFile(BanListFile, bans.dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bans::LoadBans(BanList* list)
|
void Bans::LoadBans(BanList* list)
|
||||||
{
|
{
|
||||||
assert(list != nullptr);
|
assert(list);
|
||||||
|
|
||||||
const auto _ = Lock();
|
const auto _ = Lock();
|
||||||
|
|
||||||
FileSystem::File bans("bans.json");
|
const auto bans = Utils::IO::ReadFile(BanListFile);
|
||||||
|
if (bans.empty())
|
||||||
if (!bans.exists())
|
|
||||||
{
|
{
|
||||||
Logger::Debug("bans.json does not exist");
|
Logger::Debug("bans.json does not exist");
|
||||||
return;
|
return;
|
||||||
@ -136,14 +138,20 @@ namespace Components
|
|||||||
nlohmann::json banData;
|
nlohmann::json banData;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
banData = nlohmann::json::parse(bans.getBuffer());
|
banData = nlohmann::json::parse(bans);
|
||||||
}
|
}
|
||||||
catch (const nlohmann::json::parse_error& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!banData.contains("id") || !banData.contains("ip"))
|
||||||
|
{
|
||||||
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "bans.json contains invalid data\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto& idList = banData["id"];
|
const auto& idList = banData["id"];
|
||||||
const auto& ipList = banData["ip"];
|
const auto& ipList = banData["ip"];
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ namespace Components
|
|||||||
|
|
||||||
Bans();
|
Bans();
|
||||||
|
|
||||||
static std::unique_lock<Utils::NamedMutex> Lock();
|
|
||||||
|
|
||||||
static void BanClient(Game::client_t* cl, const std::string& reason);
|
static void BanClient(Game::client_t* cl, const std::string& reason);
|
||||||
static void UnbanClient(SteamID id);
|
static void UnbanClient(SteamID id);
|
||||||
static void UnbanClient(Game::netIP_t ip);
|
static void UnbanClient(Game::netIP_t ip);
|
||||||
@ -25,6 +23,10 @@ namespace Components
|
|||||||
std::vector<Game::netIP_t> ipList;
|
std::vector<Game::netIP_t> ipList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char* BanListFile;
|
||||||
|
|
||||||
|
static std::unique_lock<Utils::NamedMutex> Lock();
|
||||||
|
|
||||||
static void LoadBans(BanList* list);
|
static void LoadBans(BanList* list);
|
||||||
static void SaveBans(const BanList* list);
|
static void SaveBans(const BanList* list);
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "GSC/Script.hpp"
|
#include "GSC/Script.hpp"
|
||||||
|
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Dvar::Var Chat::cg_chatWidth;
|
Dvar::Var Chat::cg_chatWidth;
|
||||||
@ -14,10 +16,19 @@ namespace Components
|
|||||||
bool Chat::SendChat;
|
bool Chat::SendChat;
|
||||||
|
|
||||||
Utils::Concurrency::Container<Chat::muteList> Chat::MutedList;
|
Utils::Concurrency::Container<Chat::muteList> Chat::MutedList;
|
||||||
|
const char* Chat::MutedListFile = "userraw/muted-users.json";
|
||||||
|
|
||||||
bool Chat::CanAddCallback = true;
|
bool Chat::CanAddCallback = true;
|
||||||
std::vector<Scripting::Function> Chat::SayCallbacks;
|
std::vector<Scripting::Function> Chat::SayCallbacks;
|
||||||
|
|
||||||
|
// Have only one instance of IW4x read/write the file
|
||||||
|
std::unique_lock<Utils::NamedMutex> Chat::Lock()
|
||||||
|
{
|
||||||
|
static Utils::NamedMutex mutex{"iw4x-mute-list-lock"};
|
||||||
|
std::unique_lock lock{mutex};
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player, int mode)
|
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player, int mode)
|
||||||
{
|
{
|
||||||
SendChat = true;
|
SendChat = true;
|
||||||
@ -236,8 +247,10 @@ namespace Components
|
|||||||
|
|
||||||
Game::cgsArray[0].teamChatPos++;
|
Game::cgsArray[0].teamChatPos++;
|
||||||
if (Game::cgsArray[0].teamChatPos - Game::cgsArray[0].teamLastChatPos > chatHeight)
|
if (Game::cgsArray[0].teamChatPos - Game::cgsArray[0].teamLastChatPos > chatHeight)
|
||||||
|
{
|
||||||
Game::cgsArray[0].teamLastChatPos = Game::cgsArray[0].teamChatPos + 1 - chatHeight;
|
Game::cgsArray[0].teamLastChatPos = Game::cgsArray[0].teamChatPos + 1 - chatHeight;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__declspec(naked) void Chat::CG_AddToTeamChat_Stub()
|
__declspec(naked) void Chat::CG_AddToTeamChat_Stub()
|
||||||
{
|
{
|
||||||
@ -259,7 +272,20 @@ namespace Components
|
|||||||
const auto clientNum = ent - Game::g_entities;
|
const auto clientNum = ent - Game::g_entities;
|
||||||
const auto xuid = Game::svs_clients[clientNum].steamID;
|
const auto xuid = Game::svs_clients[clientNum].steamID;
|
||||||
|
|
||||||
const auto result = MutedList.access<bool>([&](muteList& clients)
|
const auto result = MutedList.access<bool>([&](const muteList& clients)
|
||||||
|
{
|
||||||
|
return clients.contains(xuid);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Chat::IsMuted(const Game::client_t* cl)
|
||||||
|
{
|
||||||
|
const auto clientNum = cl - Game::svs_clients;
|
||||||
|
const auto xuid = Game::svs_clients[clientNum].steamID;
|
||||||
|
|
||||||
|
const auto result = MutedList.access<bool>([&](const muteList& clients)
|
||||||
{
|
{
|
||||||
return clients.contains(xuid);
|
return clients.contains(xuid);
|
||||||
});
|
});
|
||||||
@ -273,6 +299,7 @@ namespace Components
|
|||||||
MutedList.access([&](muteList& clients)
|
MutedList.access([&](muteList& clients)
|
||||||
{
|
{
|
||||||
clients.insert(xuid);
|
clients.insert(xuid);
|
||||||
|
SaveMutedList(clients);
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger::Print("{} was muted\n", client->name);
|
Logger::Print("{} was muted\n", client->name);
|
||||||
@ -295,6 +322,67 @@ namespace Components
|
|||||||
clients.clear();
|
clients.clear();
|
||||||
else
|
else
|
||||||
clients.erase(id);
|
clients.erase(id);
|
||||||
|
|
||||||
|
SaveMutedList(clients);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chat::SaveMutedList(const muteList& list)
|
||||||
|
{
|
||||||
|
const auto _ = Lock();
|
||||||
|
|
||||||
|
const nlohmann::json mutedUsers = nlohmann::json
|
||||||
|
{
|
||||||
|
{ "SteamID", list },
|
||||||
|
};
|
||||||
|
|
||||||
|
Utils::IO::WriteFile(MutedListFile, mutedUsers.dump());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chat::LoadMutedList()
|
||||||
|
{
|
||||||
|
const auto _ = Lock();
|
||||||
|
|
||||||
|
const auto mutedUsers = Utils::IO::ReadFile(MutedListFile);
|
||||||
|
if (mutedUsers.empty())
|
||||||
|
{
|
||||||
|
Logger::Debug("muted-users.json does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json mutedUsersData;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mutedUsersData = nlohmann::json::parse(mutedUsers);
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutedUsersData.contains("SteamID"))
|
||||||
|
{
|
||||||
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "muted-users.json contains invalid data\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& list = mutedUsersData["SteamID"];
|
||||||
|
if (!list.is_array())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutedList.access([&](muteList& clients)
|
||||||
|
{
|
||||||
|
const nlohmann::json::array_t arr = list;
|
||||||
|
for (auto& entry : arr)
|
||||||
|
{
|
||||||
|
if (entry.is_number_unsigned())
|
||||||
|
{
|
||||||
|
clients.insert(entry.get<std::uint64_t>());
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,6 +610,8 @@ namespace Components
|
|||||||
sv_disableChat = Dvar::Register<bool>("sv_disableChat", false, Game::DVAR_NONE, "Disable chat messages from clients");
|
sv_disableChat = Dvar::Register<bool>("sv_disableChat", false, Game::DVAR_NONE, "Disable chat messages from clients");
|
||||||
Events::OnSVInit(AddChatCommands);
|
Events::OnSVInit(AddChatCommands);
|
||||||
|
|
||||||
|
LoadMutedList();
|
||||||
|
|
||||||
// Intercept chat sending
|
// Intercept chat sending
|
||||||
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();
|
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();
|
||||||
Utils::Hook(0x4D00D4, PostSayStub, HOOK_CALL).install()->quick();
|
Utils::Hook(0x4D00D4, PostSayStub, HOOK_CALL).install()->quick();
|
||||||
|
@ -8,6 +8,9 @@ namespace Components
|
|||||||
public:
|
public:
|
||||||
Chat();
|
Chat();
|
||||||
|
|
||||||
|
static bool IsMuted(const Game::gentity_s* ent);
|
||||||
|
static bool IsMuted(const Game::client_t* cl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Dvar::Var cg_chatWidth;
|
static Dvar::Var cg_chatWidth;
|
||||||
static Dvar::Var sv_disableChat;
|
static Dvar::Var sv_disableChat;
|
||||||
@ -17,10 +20,13 @@ namespace Components
|
|||||||
|
|
||||||
using muteList = std::unordered_set<std::uint64_t>;
|
using muteList = std::unordered_set<std::uint64_t>;
|
||||||
static Utils::Concurrency::Container<muteList> MutedList;
|
static Utils::Concurrency::Container<muteList> MutedList;
|
||||||
|
static const char* MutedListFile;
|
||||||
|
|
||||||
static bool CanAddCallback; // ClientCommand & GSC thread are the same
|
static bool CanAddCallback; // ClientCommand & GSC thread are the same
|
||||||
static std::vector<Scripting::Function> SayCallbacks;
|
static std::vector<Scripting::Function> SayCallbacks;
|
||||||
|
|
||||||
|
static std::unique_lock<Utils::NamedMutex> Lock();
|
||||||
|
|
||||||
static const char* EvaluateSay(char* text, Game::gentity_t* player, int mode);
|
static const char* EvaluateSay(char* text, Game::gentity_t* player, int mode);
|
||||||
|
|
||||||
static void PreSayStub();
|
static void PreSayStub();
|
||||||
@ -30,10 +36,12 @@ namespace Components
|
|||||||
static void CG_AddToTeamChat(const char* text);
|
static void CG_AddToTeamChat(const char* text);
|
||||||
static void CG_AddToTeamChat_Stub();
|
static void CG_AddToTeamChat_Stub();
|
||||||
|
|
||||||
static bool IsMuted(const Game::gentity_s* ent);
|
|
||||||
static void MuteClient(const Game::client_t* client);
|
static void MuteClient(const Game::client_t* client);
|
||||||
static void UnmuteClient(const Game::client_t* client);
|
static void UnmuteClient(const Game::client_t* client);
|
||||||
static void UnmuteInternal(std::uint64_t id, bool everyone = false);
|
static void UnmuteInternal(std::uint64_t id, bool everyone = false);
|
||||||
|
static void SaveMutedList(const muteList& list);
|
||||||
|
static void LoadMutedList();
|
||||||
|
|
||||||
static void AddChatCommands();
|
static void AddChatCommands();
|
||||||
|
|
||||||
static int GetCallbackReturn();
|
static int GetCallbackReturn();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
Utils::Signal<Events::ClientCallback> Events::ClientDisconnectSignal;
|
Utils::Signal<Events::ClientCallback> Events::ClientDisconnectSignal;
|
||||||
|
Utils::Signal<Events::ClientConnectCallback> Events::ClientConnectSignal;
|
||||||
Utils::Signal<Events::Callback> Events::SteamDisconnectSignal;
|
Utils::Signal<Events::Callback> Events::SteamDisconnectSignal;
|
||||||
Utils::Signal<Events::Callback> Events::ShutdownSystemSignal;
|
Utils::Signal<Events::Callback> Events::ShutdownSystemSignal;
|
||||||
Utils::Signal<Events::Callback> Events::ClientInitSignal;
|
Utils::Signal<Events::Callback> Events::ClientInitSignal;
|
||||||
@ -13,6 +14,11 @@ namespace Components
|
|||||||
ClientDisconnectSignal.connect(callback);
|
ClientDisconnectSignal.connect(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::OnClientConnect(const Utils::Slot<ClientConnectCallback>& callback)
|
||||||
|
{
|
||||||
|
ClientConnectSignal.connect(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void Events::OnSteamDisconnect(const Utils::Slot<Callback>& callback)
|
void Events::OnSteamDisconnect(const Utils::Slot<Callback>& callback)
|
||||||
{
|
{
|
||||||
SteamDisconnectSignal.connect(callback);
|
SteamDisconnectSignal.connect(callback);
|
||||||
@ -44,6 +50,13 @@ namespace Components
|
|||||||
Utils::Hook::Call<void(int)>(0x4AA430)(clientNum); // ClientDisconnect
|
Utils::Hook::Call<void(int)>(0x4AA430)(clientNum); // ClientDisconnect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::SV_UserinfoChanged_Hk(Game::client_t* cl)
|
||||||
|
{
|
||||||
|
ClientConnectSignal(cl);
|
||||||
|
|
||||||
|
Utils::Hook::Call<void(Game::client_t*)>(0x401950)(cl); // SV_UserinfoChanged
|
||||||
|
}
|
||||||
|
|
||||||
void Events::SteamDisconnect_Hk()
|
void Events::SteamDisconnect_Hk()
|
||||||
{
|
{
|
||||||
SteamDisconnectSignal();
|
SteamDisconnectSignal();
|
||||||
@ -78,6 +91,8 @@ namespace Components
|
|||||||
{
|
{
|
||||||
Utils::Hook(0x625235, ClientDisconnect_Hk, HOOK_CALL).install()->quick(); // SV_FreeClient
|
Utils::Hook(0x625235, ClientDisconnect_Hk, HOOK_CALL).install()->quick(); // SV_FreeClient
|
||||||
|
|
||||||
|
Utils::Hook(0x4612BD, SV_UserinfoChanged_Hk, HOOK_CALL).install()->quick(); // SV_DirectConnect
|
||||||
|
|
||||||
Utils::Hook(0x403582, SteamDisconnect_Hk, HOOK_CALL).install()->quick(); // CL_Disconnect
|
Utils::Hook(0x403582, SteamDisconnect_Hk, HOOK_CALL).install()->quick(); // CL_Disconnect
|
||||||
|
|
||||||
Utils::Hook(0x47548B, Scr_ShutdownSystem_Hk, HOOK_CALL).install()->quick(); // G_LoadGame
|
Utils::Hook(0x47548B, Scr_ShutdownSystem_Hk, HOOK_CALL).install()->quick(); // G_LoadGame
|
||||||
|
@ -6,6 +6,7 @@ namespace Components
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef void(ClientCallback)(int clientNum);
|
typedef void(ClientCallback)(int clientNum);
|
||||||
|
typedef void(ClientConnectCallback)(Game::client_t* cl);
|
||||||
typedef void(Callback)();
|
typedef void(Callback)();
|
||||||
|
|
||||||
Events();
|
Events();
|
||||||
@ -13,6 +14,9 @@ namespace Components
|
|||||||
// Server side
|
// Server side
|
||||||
static void OnClientDisconnect(const Utils::Slot<ClientCallback>& callback);
|
static void OnClientDisconnect(const Utils::Slot<ClientCallback>& callback);
|
||||||
|
|
||||||
|
// Server side
|
||||||
|
static void OnClientConnect(const Utils::Slot<ClientConnectCallback>& callback);
|
||||||
|
|
||||||
// Client side
|
// Client side
|
||||||
static void OnSteamDisconnect(const Utils::Slot<Callback>& callback);
|
static void OnSteamDisconnect(const Utils::Slot<Callback>& callback);
|
||||||
|
|
||||||
@ -25,12 +29,14 @@ namespace Components
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static Utils::Signal<ClientCallback> ClientDisconnectSignal;
|
static Utils::Signal<ClientCallback> ClientDisconnectSignal;
|
||||||
|
static Utils::Signal<ClientConnectCallback> ClientConnectSignal;
|
||||||
static Utils::Signal<Callback> SteamDisconnectSignal;
|
static Utils::Signal<Callback> SteamDisconnectSignal;
|
||||||
static Utils::Signal<Callback> ShutdownSystemSignal;
|
static Utils::Signal<Callback> ShutdownSystemSignal;
|
||||||
static Utils::Signal<Callback> ClientInitSignal;
|
static Utils::Signal<Callback> ClientInitSignal;
|
||||||
static Utils::Signal<Callback> ServerInitSignal;
|
static Utils::Signal<Callback> ServerInitSignal;
|
||||||
|
|
||||||
static void ClientDisconnect_Hk(int clientNum);
|
static void ClientDisconnect_Hk(int clientNum);
|
||||||
|
static void SV_UserinfoChanged_Hk(Game::client_t* cl);
|
||||||
static void SteamDisconnect_Hk();
|
static void SteamDisconnect_Hk();
|
||||||
static void Scr_ShutdownSystem_Hk(unsigned char sys);
|
static void Scr_ShutdownSystem_Hk(unsigned char sys);
|
||||||
static void CL_InitOnceForAllClients_HK();
|
static void CL_InitOnceForAllClients_HK();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
#include "Chat.hpp"
|
||||||
#include "Voice.hpp"
|
#include "Voice.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
@ -381,6 +382,13 @@ namespace Components
|
|||||||
|
|
||||||
Events::OnSteamDisconnect(CL_ClearMutedList);
|
Events::OnSteamDisconnect(CL_ClearMutedList);
|
||||||
Events::OnClientDisconnect(SV_UnmuteClient);
|
Events::OnClientDisconnect(SV_UnmuteClient);
|
||||||
|
Events::OnClientConnect([](Game::client_t* cl) -> void
|
||||||
|
{
|
||||||
|
if (Chat::IsMuted(cl))
|
||||||
|
{
|
||||||
|
SV_MuteClient(cl - Game::svs_clients);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Write voice packets to the server instead of other clients
|
// Write voice packets to the server instead of other clients
|
||||||
Utils::Hook(0x487935, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick();
|
Utils::Hook(0x487935, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick();
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
namespace Utils::IO
|
namespace Utils::IO
|
||||||
{
|
{
|
||||||
bool FileExists(const std::string& file);
|
[[nodiscard]] bool FileExists(const std::string& file);
|
||||||
bool WriteFile(const std::string& file, const std::string& data, bool append = false);
|
bool WriteFile(const std::string& file, const std::string& data, bool append = false);
|
||||||
bool ReadFile(const std::string& file, std::string* data);
|
bool ReadFile(const std::string& file, std::string* data);
|
||||||
std::string ReadFile(const std::string& file);
|
[[nodiscard]] std::string ReadFile(const std::string& file);
|
||||||
bool RemoveFile(const std::string& file);
|
bool RemoveFile(const std::string& file);
|
||||||
std::size_t FileSize(const std::string& file);
|
[[nodiscard]] std::size_t FileSize(const std::string& file);
|
||||||
bool CreateDir(const std::string& dir);
|
bool CreateDir(const std::string& dir);
|
||||||
bool DirectoryExists(const std::filesystem::path& directory);
|
[[nodiscard]] bool DirectoryExists(const std::filesystem::path& directory);
|
||||||
bool DirectoryIsEmpty(const std::filesystem::path& directory);
|
[[nodiscard]] bool DirectoryIsEmpty(const std::filesystem::path& directory);
|
||||||
std::vector<std::string> ListFiles(const std::filesystem::path& directory, bool recursive = false);
|
[[nodiscard]] std::vector<std::string> ListFiles(const std::filesystem::path& directory, bool recursive = false);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user