mirror of
https://github.com/diamante0018/MW3ServerFreezer.git
synced 2025-04-19 19:52:53 +00:00
userinfo spam
This commit is contained in:
parent
1119a5e7a2
commit
45d7c3daf5
@ -91,6 +91,11 @@ namespace cheats
|
|||||||
{
|
{
|
||||||
command::execute(utils::string::va("cmd mr %i 2 allies", *game::serverId), true);
|
command::execute(utils::string::va("cmd mr %i 2 allies", *game::serverId), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
key_catcher::on_key_press("8", [](const game::LocalClientNum_t&)
|
||||||
|
{
|
||||||
|
command::execute(utils::string::va("cmd mr %i -1 endround", *game::serverId), true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
170
src/component/scheduler.cpp
Normal file
170
src/component/scheduler.cpp
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#include <stdinc.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "utils/concurrency.hpp"
|
||||||
|
#include "utils/hook.hpp"
|
||||||
|
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
namespace scheduler
|
||||||
|
{
|
||||||
|
std::thread::id async_thread_id;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct task
|
||||||
|
{
|
||||||
|
std::function<bool()> handler{};
|
||||||
|
std::chrono::milliseconds interval{};
|
||||||
|
std::chrono::high_resolution_clock::time_point last_call{};
|
||||||
|
};
|
||||||
|
|
||||||
|
using task_list = std::vector<task>;
|
||||||
|
|
||||||
|
class task_pipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void add(task&& task)
|
||||||
|
{
|
||||||
|
new_callbacks_.access([&task, this](task_list& tasks)
|
||||||
|
{
|
||||||
|
tasks.emplace_back(std::move(task));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
callbacks_.access([&](task_list& tasks)
|
||||||
|
{
|
||||||
|
this->merge_callbacks();
|
||||||
|
tasks.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute()
|
||||||
|
{
|
||||||
|
callbacks_.access([&](task_list& tasks)
|
||||||
|
{
|
||||||
|
this->merge_callbacks();
|
||||||
|
|
||||||
|
for (auto i = tasks.begin(); i != tasks.end();)
|
||||||
|
{
|
||||||
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
const auto diff = now - i->last_call;
|
||||||
|
|
||||||
|
if (diff < i->interval)
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i->last_call = now;
|
||||||
|
|
||||||
|
const auto res = i->handler();
|
||||||
|
if (res == cond_end)
|
||||||
|
{
|
||||||
|
i = tasks.erase(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::concurrency::container<task_list> new_callbacks_;
|
||||||
|
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
|
||||||
|
|
||||||
|
void merge_callbacks()
|
||||||
|
{
|
||||||
|
callbacks_.access([&](task_list& tasks)
|
||||||
|
{
|
||||||
|
new_callbacks_.access([&](task_list& new_tasks)
|
||||||
|
{
|
||||||
|
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end()));
|
||||||
|
new_tasks = {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
task_pipeline pipelines[pipeline::count];
|
||||||
|
|
||||||
|
void execute(const pipeline type)
|
||||||
|
{
|
||||||
|
assert(type >= 0 && type < pipeline::count);
|
||||||
|
pipelines[type].execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cl_frame_stub(game::LocalClientNum_t local)
|
||||||
|
{
|
||||||
|
reinterpret_cast<void (*)(game::LocalClientNum_t)>(0x041C9B0)(local);
|
||||||
|
execute(pipeline::client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_tasks(const pipeline type)
|
||||||
|
{
|
||||||
|
return pipelines[type].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void schedule(const std::function<bool()>& callback, const pipeline type,
|
||||||
|
const std::chrono::milliseconds delay)
|
||||||
|
{
|
||||||
|
assert(type >= 0 && type < pipeline::count);
|
||||||
|
|
||||||
|
task task;
|
||||||
|
task.handler = callback;
|
||||||
|
task.interval = delay;
|
||||||
|
task.last_call = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
pipelines[type].add(std::move(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(const std::function<void()>& callback, const pipeline type,
|
||||||
|
const std::chrono::milliseconds delay)
|
||||||
|
{
|
||||||
|
schedule([callback]()
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
return cond_continue;
|
||||||
|
}, type, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void once(const std::function<void()>& callback, const pipeline type,
|
||||||
|
const std::chrono::milliseconds delay)
|
||||||
|
{
|
||||||
|
schedule([callback]()
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
return cond_end;
|
||||||
|
}, type, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int thread_id;
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
thread = std::thread([]()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
execute(pipeline::async);
|
||||||
|
std::this_thread::sleep_for(10ms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async_thread_id = thread.get_id();
|
||||||
|
|
||||||
|
utils::hook::call(0x04E4A0D, cl_frame_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(scheduler::component)
|
25
src/component/scheduler.hpp
Normal file
25
src/component/scheduler.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace scheduler
|
||||||
|
{
|
||||||
|
extern std::thread::id async_thread_id;
|
||||||
|
|
||||||
|
enum pipeline
|
||||||
|
{
|
||||||
|
client,
|
||||||
|
async,
|
||||||
|
count,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const bool cond_continue = false;
|
||||||
|
static const bool cond_end = true;
|
||||||
|
|
||||||
|
void clear_tasks(const pipeline type);
|
||||||
|
|
||||||
|
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::client,
|
||||||
|
std::chrono::milliseconds delay = 0ms);
|
||||||
|
void loop(const std::function<void()>& callback, pipeline type = pipeline::client,
|
||||||
|
std::chrono::milliseconds delay = 0ms);
|
||||||
|
void once(const std::function<void()>& callback, pipeline type = pipeline::client,
|
||||||
|
std::chrono::milliseconds delay = 0ms);
|
||||||
|
}
|
81
src/component/user_info.cpp
Normal file
81
src/component/user_info.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <stdinc.hpp>
|
||||||
|
|
||||||
|
#include <loader/component_loader.hpp>
|
||||||
|
#include "utils/hook.hpp"
|
||||||
|
#include "utils/info_string.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
namespace user_info
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int a1 = 0;
|
||||||
|
void cl_check_user_info(int _a1, int force)
|
||||||
|
{
|
||||||
|
a1 = _a1;
|
||||||
|
|
||||||
|
if (*game::connectionState <= game::connstate_t::CA_CHALLENGING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (game::cl_paused->current.enabled && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::string infoString = game::Dvar_InfoString(_a1, 0x200);
|
||||||
|
utils::info_string info(infoString);
|
||||||
|
|
||||||
|
const auto colorCode = rand() % 10;
|
||||||
|
|
||||||
|
char numbers[_MAX_U64TOSTR_BASE2_COUNT];
|
||||||
|
char name[16];
|
||||||
|
|
||||||
|
_itoa_s(rand() % 10000, numbers, sizeof(numbers), 10);
|
||||||
|
_snprintf_s(name, sizeof(name), _TRUNCATE, "^%d%s", colorCode, numbers);
|
||||||
|
|
||||||
|
info.set("name", name);
|
||||||
|
|
||||||
|
info.set("ec_usingTag", "1");
|
||||||
|
info.set("ec_TagText", utils::string::va("^%dGG", colorCode));
|
||||||
|
|
||||||
|
char bigTitle[_MAX_U64TOSTR_BASE2_COUNT];
|
||||||
|
_itoa_s(rand() % 512, bigTitle, sizeof(bigTitle), 10);
|
||||||
|
|
||||||
|
info.set("ec_TitleBg", bigTitle);
|
||||||
|
|
||||||
|
game::CL_AddReliableCommand(_a1, utils::string::va("userinfo \"%s\"", info.build().data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void cl_check_user_info_stub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push 0
|
||||||
|
push esi
|
||||||
|
call cl_check_user_info
|
||||||
|
add esp, 8
|
||||||
|
|
||||||
|
popad
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
utils::hook::call(0x41CA53, cl_check_user_info_stub);
|
||||||
|
|
||||||
|
scheduler::loop([]
|
||||||
|
{
|
||||||
|
cl_check_user_info(a1, TRUE);
|
||||||
|
}, scheduler::pipeline::client, 4s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(user_info::component)
|
@ -8,6 +8,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/,
|
|||||||
{
|
{
|
||||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
|
srand(uint32_t(time(nullptr)));
|
||||||
component_loader::post_unpack();
|
component_loader::post_unpack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +204,8 @@ namespace game
|
|||||||
netadrtype_t type;
|
netadrtype_t type;
|
||||||
unsigned char ip[4];
|
unsigned char ip[4];
|
||||||
unsigned __int16 port;
|
unsigned __int16 port;
|
||||||
netsrc_t localNetID;
|
unsigned char ipx[10];
|
||||||
char __pad0[4];
|
unsigned int addrHandleIndex;
|
||||||
unsigned int index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(netadr_s) == 24);
|
static_assert(sizeof(netadr_s) == 24);
|
||||||
@ -278,6 +277,21 @@ namespace game
|
|||||||
LOCAL_CLIENT_COUNT = 4
|
LOCAL_CLIENT_COUNT = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CA_DISCONNECTED = 0,
|
||||||
|
CA_CINEMATIC = 1,
|
||||||
|
CA_LOGO = 2,
|
||||||
|
CA_CONNECTING = 3,
|
||||||
|
CA_CHALLENGING = 4,
|
||||||
|
CA_CONNECTED = 5,
|
||||||
|
CA_SENDINGSTATS = 6,
|
||||||
|
CA_REQUESTING_MATCH_RULES = 7,
|
||||||
|
CA_LOADING = 8,
|
||||||
|
CA_PRIMED = 9,
|
||||||
|
CA_ACTIVE = 10
|
||||||
|
} connstate_t;
|
||||||
|
|
||||||
struct msg_t
|
struct msg_t
|
||||||
{
|
{
|
||||||
int overflowed;
|
int overflowed;
|
||||||
@ -981,45 +995,6 @@ namespace game
|
|||||||
int hintForcedString;
|
int hintForcedString;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct trace_t
|
|
||||||
{
|
|
||||||
float fraction;
|
|
||||||
float normal[3];
|
|
||||||
int surfaceFlags;
|
|
||||||
int contents;
|
|
||||||
char material[4];
|
|
||||||
TraceHitType hitType;
|
|
||||||
unsigned __int16 hitId;
|
|
||||||
float fractionForHitType;
|
|
||||||
unsigned __int16 modelIndex;
|
|
||||||
unsigned __int16 partName;
|
|
||||||
unsigned __int16 partGroup;
|
|
||||||
bool allsolid;
|
|
||||||
bool startsolid;
|
|
||||||
bool walkable;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(trace_t) == 52);
|
|
||||||
|
|
||||||
struct pml_t
|
|
||||||
{
|
|
||||||
float forward[3];
|
|
||||||
float right[3];
|
|
||||||
float up[3];
|
|
||||||
float frametime;
|
|
||||||
int msec;
|
|
||||||
int walking;
|
|
||||||
int groundPlane;
|
|
||||||
int almostGroundPlane;
|
|
||||||
trace_t groundTrace;
|
|
||||||
float impactSpeed;
|
|
||||||
float previous_origin[3];
|
|
||||||
float previous_velocity[3];
|
|
||||||
int holdrand;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(pml_t) == 140);
|
|
||||||
|
|
||||||
struct clientConnection_t
|
struct clientConnection_t
|
||||||
{
|
{
|
||||||
int qport; // 0
|
int qport; // 0
|
||||||
|
@ -29,6 +29,7 @@ namespace game
|
|||||||
Dvar_RegisterFloat{0x4A5CF0};
|
Dvar_RegisterFloat{0x4A5CF0};
|
||||||
WEAK symbol<void(dvar_t* var, bool value)> Dvar_SetBool{0x46DD70};
|
WEAK symbol<void(dvar_t* var, bool value)> Dvar_SetBool{0x46DD70};
|
||||||
WEAK symbol<void(const char* dvarName, bool value)> Dvar_SetBoolByName{0x48C7D0};
|
WEAK symbol<void(const char* dvarName, bool value)> Dvar_SetBoolByName{0x48C7D0};
|
||||||
|
WEAK symbol<const char*(int, int)> Dvar_InfoString{0x4028C0};
|
||||||
|
|
||||||
WEAK symbol<int(const char* cmd)> Key_GetBindingForCmd{0x47D300};
|
WEAK symbol<int(const char* cmd)> Key_GetBindingForCmd{0x47D300};
|
||||||
WEAK symbol<int(const char* keyAsText)> Key_StringToKeynum{0x50A710}; // Virtual-Key Code
|
WEAK symbol<int(const char* keyAsText)> Key_StringToKeynum{0x50A710}; // Virtual-Key Code
|
||||||
@ -49,6 +50,7 @@ namespace game
|
|||||||
WEAK symbol<void(const msg_t*, unsigned __int64)> MSG_WriteInt64{0x4906B0};
|
WEAK symbol<void(const msg_t*, unsigned __int64)> MSG_WriteInt64{0x4906B0};
|
||||||
WEAK symbol<void(const msg_t*, int)> MSG_WriteShort{0x4ACD80};
|
WEAK symbol<void(const msg_t*, int)> MSG_WriteShort{0x4ACD80};
|
||||||
WEAK symbol<void(const msg_t*, const void*, int)> MSG_WriteData{0x4F8C20};
|
WEAK symbol<void(const msg_t*, const void*, int)> MSG_WriteData{0x4F8C20};
|
||||||
|
WEAK symbol<void(int, const char*)> CL_AddReliableCommand{0x4EE3A0};
|
||||||
|
|
||||||
WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050};
|
WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050};
|
||||||
WEAK symbol<int(unsigned __int64, const void*, unsigned int)> LiveSteam_Client_ConnectToSteamServer{0x4D6980};
|
WEAK symbol<int(unsigned __int64, const void*, unsigned int)> LiveSteam_Client_ConnectToSteamServer{0x4D6980};
|
||||||
@ -60,4 +62,6 @@ namespace game
|
|||||||
WEAK symbol<HWND> g_wv_hWnd{0x5A86AF0};
|
WEAK symbol<HWND> g_wv_hWnd{0x5A86AF0};
|
||||||
WEAK symbol<HWND> s_wcd_hWnd{0x5A86330};
|
WEAK symbol<HWND> s_wcd_hWnd{0x5A86330};
|
||||||
WEAK symbol<int> serverId{0xFF5058};
|
WEAK symbol<int> serverId{0xFF5058};
|
||||||
|
WEAK symbol<connstate_t> connectionState{0x1060214};
|
||||||
|
WEAK symbol<dvar_t> cl_paused{0x1CE6190};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <WinSock2.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -10,7 +14,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <queue>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
46
src/utils/concurrency.hpp
Normal file
46
src/utils/concurrency.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace utils::concurrency
|
||||||
|
{
|
||||||
|
template <typename T, typename MutexType = std::mutex>
|
||||||
|
class container
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename R = void, typename F>
|
||||||
|
R access(F&& accessor) const
|
||||||
|
{
|
||||||
|
std::lock_guard<MutexType> _{mutex_};
|
||||||
|
return accessor(object_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R = void, typename F>
|
||||||
|
R access(F&& accessor)
|
||||||
|
{
|
||||||
|
std::lock_guard<MutexType> _{mutex_};
|
||||||
|
return accessor(object_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R = void, typename F>
|
||||||
|
R access_with_lock(F&& accessor) const
|
||||||
|
{
|
||||||
|
std::unique_lock<MutexType> lock{mutex_};
|
||||||
|
return accessor(object_, lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R = void, typename F>
|
||||||
|
R access_with_lock(F&& accessor)
|
||||||
|
{
|
||||||
|
std::unique_lock<MutexType> lock{mutex_};
|
||||||
|
return accessor(object_, lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get_raw() { return object_; }
|
||||||
|
const T& get_raw() const { return object_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable MutexType mutex_{};
|
||||||
|
T object_{};
|
||||||
|
};
|
||||||
|
}
|
66
src/utils/info_string.cpp
Normal file
66
src/utils/info_string.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include <stdinc.hpp>
|
||||||
|
|
||||||
|
#include "info_string.hpp"
|
||||||
|
#include "string.hpp"
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
info_string::info_string(const std::string& buffer)
|
||||||
|
{
|
||||||
|
this->parse(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
info_string::info_string(const std::string_view& buffer)
|
||||||
|
: info_string(std::string{buffer})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void info_string::set(const std::string& key, const std::string& value)
|
||||||
|
{
|
||||||
|
this->key_value_pairs_[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string info_string::get(const std::string& key) const
|
||||||
|
{
|
||||||
|
const auto value = this->key_value_pairs_.find(key);
|
||||||
|
if (value != this->key_value_pairs_.end())
|
||||||
|
{
|
||||||
|
return value->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void info_string::parse(std::string buffer)
|
||||||
|
{
|
||||||
|
if (buffer[0] == '\\')
|
||||||
|
{
|
||||||
|
buffer = buffer.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto key_values = string::split(buffer, '\\');
|
||||||
|
for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2)
|
||||||
|
{
|
||||||
|
const auto& key = key_values[i];
|
||||||
|
const auto& value = key_values[i + 1];
|
||||||
|
this->key_value_pairs_[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string info_string::build() const
|
||||||
|
{
|
||||||
|
//auto first = true;
|
||||||
|
std::string info_string;
|
||||||
|
for (auto i = this->key_value_pairs_.begin(); i != this->key_value_pairs_.end(); ++i)
|
||||||
|
{
|
||||||
|
//if (first) first = false;
|
||||||
|
/*else*/ info_string.append("\\");
|
||||||
|
|
||||||
|
info_string.append(i->first); // Key
|
||||||
|
info_string.append("\\");
|
||||||
|
info_string.append(i->second); // Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return info_string;
|
||||||
|
}
|
||||||
|
}
|
24
src/utils/info_string.hpp
Normal file
24
src/utils/info_string.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
class info_string
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
info_string() = default;
|
||||||
|
info_string(const std::string& buffer);
|
||||||
|
info_string(const std::string_view& buffer);
|
||||||
|
|
||||||
|
void set(const std::string& key, const std::string& value);
|
||||||
|
std::string get(const std::string& key) const;
|
||||||
|
std::string build() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::string> key_value_pairs_{};
|
||||||
|
|
||||||
|
void parse(std::string buffer);
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user