Initial public release of rem-essentials
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "rem/feature_manager.h"
|
||||
|
||||
namespace rem
|
||||
{
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
void Load(HINSTANCE module);
|
||||
|
||||
bool GetBool(const char* section, const char* key, bool fallback) const;
|
||||
int GetInt(const char* section, const char* key, int fallback) const;
|
||||
float GetFloat(const char* section, const char* key, float fallback) const;
|
||||
std::string GetString(const char* section, const char* key, const char* fallback = "") const;
|
||||
|
||||
private:
|
||||
std::string GetValue(const char* section, const char* key) const;
|
||||
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, std::string>> sections_;
|
||||
};
|
||||
|
||||
Config& GetConfig();
|
||||
void ReadConfig(HINSTANCE module, FeatureManager& manager);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace rem
|
||||
{
|
||||
class Config;
|
||||
|
||||
enum class RuntimeSide
|
||||
{
|
||||
Always,
|
||||
Client,
|
||||
Server,
|
||||
};
|
||||
|
||||
struct Feature
|
||||
{
|
||||
std::string name;
|
||||
void (*init)();
|
||||
void (*cleanup)();
|
||||
RuntimeSide side;
|
||||
bool enabled;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
class FeatureManager
|
||||
{
|
||||
public:
|
||||
void Register(const char* name, void (*init)(), void (*cleanup)(), RuntimeSide side, bool defaultEnabled);
|
||||
bool SetEnabled(const char* name, bool enabled);
|
||||
void ApplyConfig(const Config& config);
|
||||
void InitFeatures();
|
||||
void CleanupFeatures();
|
||||
|
||||
private:
|
||||
bool Applies(const Feature& feature) const;
|
||||
|
||||
std::vector<Feature> features_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "rem/st6.h"
|
||||
|
||||
namespace rem::fl
|
||||
{
|
||||
struct EquipDesc
|
||||
{
|
||||
DWORD unknown;
|
||||
UINT archId;
|
||||
};
|
||||
|
||||
struct EquipDescList
|
||||
{
|
||||
st6::list<EquipDesc> list;
|
||||
};
|
||||
|
||||
enum class GoodType : DWORD
|
||||
{
|
||||
Commodity = 0,
|
||||
Hull = 2,
|
||||
Ship = 3,
|
||||
};
|
||||
|
||||
struct GoodInfo
|
||||
{
|
||||
BYTE x00[0x4C];
|
||||
GoodType type;
|
||||
BYTE x50[0x4];
|
||||
UINT shipId;
|
||||
BYTE x58[0x38];
|
||||
UINT shipHullId;
|
||||
EquipDescList equipDescLists[3];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace rem::log
|
||||
{
|
||||
void Info(const char* message);
|
||||
void Warn(const char* message);
|
||||
void Error(const char* message);
|
||||
void ModuleMissing(const char* feature, const char* moduleName);
|
||||
void ProcMissing(const char* feature, const char* procName);
|
||||
void UnknownFeature(const char* featureName);
|
||||
void FeatureInitFailed(const char* featureName, DWORD exceptionCode);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace rem
|
||||
{
|
||||
void Patch(DWORD address, const void* data, UINT length);
|
||||
void PatchBytes(DWORD address, std::initializer_list<BYTE> bytes);
|
||||
void Nop(DWORD address, UINT length);
|
||||
void ReadWriteProtect(DWORD address, DWORD size);
|
||||
|
||||
template <typename Type>
|
||||
inline void Patch(DWORD address, Type value)
|
||||
{
|
||||
Patch(address, &value, sizeof(Type));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type& ValueAt(DWORD address)
|
||||
{
|
||||
ReadWriteProtect(address, sizeof(Type));
|
||||
return *reinterpret_cast<Type*>(address);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline Func FunctionAt(DWORD address)
|
||||
{
|
||||
return reinterpret_cast<Func>(address);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
Func SetRelPointer(DWORD location, Func hook)
|
||||
{
|
||||
DWORD& relative = ValueAt<DWORD>(location);
|
||||
DWORD original = location + relative + 4;
|
||||
DWORD hookAddress = *reinterpret_cast<DWORD*>(&hook);
|
||||
relative = hookAddress - (location + 4);
|
||||
return FunctionAt<Func>(original);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void Hook(DWORD address, Func hook, UINT instructionLength, bool jump = false)
|
||||
{
|
||||
assert(instructionLength >= 5);
|
||||
Patch<BYTE>(address, jump ? 0xE9 : 0xE8);
|
||||
SetRelPointer(address + 1, hook);
|
||||
|
||||
if (instructionLength > 5)
|
||||
Nop(address + 5, instructionLength - 5);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
Func Trampoline(DWORD address, Func hook, UINT instructionLength)
|
||||
{
|
||||
BYTE* gateway = static_cast<BYTE*>(
|
||||
VirtualAlloc(nullptr, instructionLength + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
|
||||
|
||||
ReadWriteProtect(address, instructionLength);
|
||||
memcpy(gateway, reinterpret_cast<void*>(address), instructionLength);
|
||||
|
||||
Hook(address, hook, instructionLength, true);
|
||||
Hook(reinterpret_cast<DWORD>(gateway + instructionLength), FunctionAt<Func>(address + instructionLength), 5, true);
|
||||
|
||||
return FunctionAt<Func>(reinterpret_cast<DWORD>(gateway));
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void CleanupTrampoline(Func trampoline)
|
||||
{
|
||||
VirtualFree(reinterpret_cast<void*>(*reinterpret_cast<DWORD*>(&trampoline)), 0, MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace rem
|
||||
{
|
||||
bool IsServer();
|
||||
bool IsClient();
|
||||
bool IsWine();
|
||||
HMODULE GetModule(const char* moduleName);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace st6
|
||||
{
|
||||
template<class T>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
template <class T, class A = allocator<T>>
|
||||
class list
|
||||
{
|
||||
struct Node;
|
||||
using NodePtr = Node*;
|
||||
|
||||
struct Node
|
||||
{
|
||||
NodePtr next;
|
||||
NodePtr prev;
|
||||
T value;
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator() : ptr_(nullptr) {}
|
||||
explicit iterator(NodePtr ptr) : ptr_(ptr) {}
|
||||
|
||||
T& operator*() const { return ptr_->value; }
|
||||
T* operator->() const { return &ptr_->value; }
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& other) const { return ptr_ == other.ptr_; }
|
||||
bool operator!=(const iterator& other) const { return ptr_ != other.ptr_; }
|
||||
|
||||
private:
|
||||
NodePtr ptr_;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(head_->next); }
|
||||
iterator end() { return iterator(head_); }
|
||||
|
||||
A allocator_;
|
||||
NodePtr head_;
|
||||
size_t size_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace rem
|
||||
{
|
||||
bool IsSupportedGameVersion();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define REM_FILL_VFTABLE(prefix) \
|
||||
virtual void Vftable_##prefix##0(); \
|
||||
virtual void Vftable_##prefix##4(); \
|
||||
virtual void Vftable_##prefix##8(); \
|
||||
virtual void Vftable_##prefix##C();
|
||||
|
||||
Reference in New Issue
Block a user