mirror of
https://github.com/Jous99/F4MP.git
synced 2026-01-12 07:00:53 +01:00
Compare commits
7 commits
2dffe56a11
...
ad04bd9eb8
| Author | SHA1 | Date | |
|---|---|---|---|
| ad04bd9eb8 | |||
| e99cfe5c24 | |||
| 7d805879b4 | |||
| ac8000d63d | |||
|
|
57626d2645 | ||
|
|
ecc13f6d64 | ||
|
|
018b413598 |
10 changed files with 614 additions and 58 deletions
|
|
@ -3,5 +3,5 @@
|
|||
<Platform Name="x64" />
|
||||
<Platform Name="x86" />
|
||||
</Configurations>
|
||||
<Project Path="F4MP_Client.vcxproj" />
|
||||
<Project Path="F4MP_Client.vcxproj" Id="93aa22ac-17c4-420a-9ce3-16430bf1ace3" />
|
||||
</Solution>
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@
|
|||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
|
@ -131,6 +132,7 @@
|
|||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
|
|
|||
126
Client/common/include/Exceptions.h
Normal file
126
Client/common/include/Exceptions.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#ifndef COMMON_EXCEPTIONS_H
|
||||
#define COMMON_EXCEPTIONS_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Exceptions {
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace Exceptions {
|
||||
class RuntimeException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit RuntimeException(const std::string &msg) :
|
||||
std::runtime_error(msg.c_str())
|
||||
{ }
|
||||
|
||||
explicit RuntimeException(const char *msg) :
|
||||
std::runtime_error(msg)
|
||||
{ }
|
||||
};
|
||||
|
||||
class DetourException : public RuntimeException
|
||||
{
|
||||
public:
|
||||
explicit DetourException(const std::string &msg) :
|
||||
RuntimeException(msg.c_str())
|
||||
{ }
|
||||
|
||||
explicit DetourException(const char *msg) :
|
||||
RuntimeException(msg)
|
||||
{ }
|
||||
};
|
||||
|
||||
class GenericWinAPIException : public std::runtime_error
|
||||
{
|
||||
DWORD last_error_;
|
||||
|
||||
public:
|
||||
explicit GenericWinAPIException(const std::string &msg) :
|
||||
std::runtime_error(msg.c_str()), last_error_(GetLastError())
|
||||
{ }
|
||||
|
||||
explicit GenericWinAPIException(const char *msg) :
|
||||
std::runtime_error(msg), last_error_(GetLastError())
|
||||
{ }
|
||||
|
||||
virtual DWORD get_last_error() const
|
||||
{
|
||||
return last_error_;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleNotFoundException : public GenericWinAPIException
|
||||
{
|
||||
public:
|
||||
explicit ModuleNotFoundException(const std::string &msg) :
|
||||
GenericWinAPIException(msg)
|
||||
{ }
|
||||
|
||||
explicit ModuleNotFoundException(const char *msg) :
|
||||
GenericWinAPIException(msg)
|
||||
{ }
|
||||
};
|
||||
|
||||
class ProcAddressNotFoundException : public GenericWinAPIException
|
||||
{
|
||||
public:
|
||||
explicit ProcAddressNotFoundException(const std::string &msg) :
|
||||
GenericWinAPIException(msg)
|
||||
{ }
|
||||
|
||||
explicit ProcAddressNotFoundException(const char *msg) :
|
||||
GenericWinAPIException(msg)
|
||||
{ }
|
||||
};
|
||||
|
||||
class COMInterfaceException : public RuntimeException
|
||||
{
|
||||
HRESULT hresult_;
|
||||
|
||||
public:
|
||||
explicit COMInterfaceException(const std::string &msg, HRESULT result) :
|
||||
RuntimeException(msg), hresult_(result)
|
||||
{ }
|
||||
|
||||
explicit COMInterfaceException(const char *msg, HRESULT result) :
|
||||
RuntimeException(msg), hresult_(result)
|
||||
{ }
|
||||
|
||||
HRESULT hresult() const
|
||||
{
|
||||
return hresult_;
|
||||
}
|
||||
};
|
||||
|
||||
class DXAPIException : public COMInterfaceException
|
||||
{
|
||||
public:
|
||||
explicit DXAPIException(const std::string &msg, HRESULT result) :
|
||||
COMInterfaceException(msg, result)
|
||||
{ }
|
||||
|
||||
explicit DXAPIException(const char *msg, HRESULT result) :
|
||||
COMInterfaceException(msg, result)
|
||||
{ }
|
||||
};
|
||||
|
||||
class ARCException : public COMInterfaceException
|
||||
{
|
||||
public:
|
||||
explicit ARCException(const std::string &msg, HRESULT result) :
|
||||
COMInterfaceException(msg, result)
|
||||
{ }
|
||||
|
||||
explicit ARCException(const char *msg, HRESULT result) :
|
||||
COMInterfaceException(msg, result)
|
||||
{ }
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
||||
81
Client/common/include/GamePtr.h
Normal file
81
Client/common/include/GamePtr.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef COMMON_GAMEPTR_H
|
||||
#define COMMON_GAMEPTR_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Memory {
|
||||
|
||||
class GamePtr_Manager {
|
||||
public:
|
||||
GamePtr_Manager();
|
||||
|
||||
static uintptr_t s_baseAddress;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GamePtr {
|
||||
public :
|
||||
GamePtr(uintptr_t offset) : offset(offset + Memory::GamePtr_Manager::s_baseAddress){}
|
||||
|
||||
T * GetPtr() const {
|
||||
return reinterpret_cast <T *>(offset);
|
||||
}
|
||||
|
||||
T * operator->() const
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
operator T *() const
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
bool operator!() const {
|
||||
return !GetPtr();
|
||||
}
|
||||
|
||||
const T * GetConstPtr() const {
|
||||
return reinterpret_cast <T *>(offset);
|
||||
}
|
||||
|
||||
uintptr_t GetUIntPtr() const
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
private:
|
||||
uintptr_t offset;
|
||||
|
||||
GamePtr();
|
||||
GamePtr(GamePtr & rhs);
|
||||
GamePtr & operator=(GamePtr & rhs);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class GameAddr{
|
||||
public:
|
||||
GameAddr(uintptr_t offset) : offset(reinterpret_cast<ConversionType *>(offset + Memory::GamePtr_Manager::s_baseAddress)){}
|
||||
|
||||
operator T() {
|
||||
return reinterpret_cast<T>(offset);
|
||||
}
|
||||
|
||||
uintptr_t GetUIntPtr(){
|
||||
return reinterpret_cast<uintptr_t >(offset);
|
||||
}
|
||||
private:
|
||||
struct ConversionType {};
|
||||
|
||||
ConversionType * offset;
|
||||
|
||||
GameAddr();
|
||||
GameAddr(GameAddr & rhs);
|
||||
GameAddr & operator=(GameAddr & rhs);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
122
Client/common/include/Hook.h
Normal file
122
Client/common/include/Hook.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef COMMON_HOOK_H
|
||||
#define COMMON_HOOK_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <cstdint>
|
||||
#include "detours.h" // Asegúrate de tener detours.lib en tu proyecto
|
||||
#include "Types.h"
|
||||
#include "Exceptions.h"
|
||||
|
||||
namespace Hooks {
|
||||
|
||||
enum class CallConvention
|
||||
{
|
||||
stdcall_t,
|
||||
cdecl_t,
|
||||
fastcall_t // Añadido fastcall por si interceptas funciones internas del engine
|
||||
};
|
||||
|
||||
// Helper para definir la convención de llamada
|
||||
template <CallConvention cc, typename retn, typename ...args>
|
||||
struct convention;
|
||||
|
||||
template <typename retn, typename ...args>
|
||||
struct convention<CallConvention::stdcall_t, retn, args...>
|
||||
{
|
||||
typedef retn (__stdcall *type)(args ...);
|
||||
};
|
||||
|
||||
template <typename retn, typename ...args>
|
||||
struct convention<CallConvention::cdecl_t, retn, args...>
|
||||
{
|
||||
typedef retn (__cdecl *type)(args ...);
|
||||
};
|
||||
|
||||
// Fallout 4 usa mucho fastcall (__rcall en x64)
|
||||
template <typename retn, typename ...args>
|
||||
struct convention<CallConvention::fastcall_t, retn, args...>
|
||||
{
|
||||
typedef retn (__fastcall *type)(args ...);
|
||||
};
|
||||
|
||||
template <CallConvention cc, typename retn, typename ...args>
|
||||
class Hook
|
||||
{
|
||||
typedef typename convention<cc, retn, args...>::type type;
|
||||
|
||||
uintptr_t orig_; // Usamos uintptr_t para compatibilidad x64
|
||||
type detour_;
|
||||
|
||||
bool is_applied_;
|
||||
bool has_open_transaction_;
|
||||
|
||||
void transaction_begin()
|
||||
{
|
||||
if (DetourTransactionBegin() != NO_ERROR)
|
||||
throw Exceptions::Core::Exceptions::DetourException("A pending transaction already exists");
|
||||
has_open_transaction_ = true;
|
||||
}
|
||||
|
||||
void transaction_commit()
|
||||
{
|
||||
if (DetourTransactionCommit() != NO_ERROR)
|
||||
throw Exceptions::Core::Exceptions::DetourException("Error committing detour transaction");
|
||||
has_open_transaction_ = false;
|
||||
}
|
||||
|
||||
static void update_thread(HANDLE hThread)
|
||||
{
|
||||
DetourUpdateThread(hThread);
|
||||
}
|
||||
|
||||
public:
|
||||
Hook() : orig_(0), detour_(0), is_applied_(false), has_open_transaction_(false) {}
|
||||
|
||||
~Hook()
|
||||
{
|
||||
if (has_open_transaction_) DetourTransactionAbort();
|
||||
remove();
|
||||
}
|
||||
|
||||
// pFunc ahora acepta uintptr_t para que funcione con GameAddr::GetUIntPtr()
|
||||
void apply(uintptr_t pFunc, type detour)
|
||||
{
|
||||
if (is_applied_) return;
|
||||
|
||||
detour_ = detour;
|
||||
orig_ = pFunc;
|
||||
|
||||
transaction_begin();
|
||||
update_thread(GetCurrentThread());
|
||||
|
||||
// Detours requiere un puntero al puntero de la función original
|
||||
DetourAttach(reinterpret_cast<void **>(&orig_), reinterpret_cast<void *>(detour_));
|
||||
|
||||
transaction_commit();
|
||||
is_applied_ = true;
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
if (!is_applied_) return;
|
||||
|
||||
transaction_begin();
|
||||
update_thread(GetCurrentThread());
|
||||
DetourDetach(reinterpret_cast<void **>(&orig_), reinterpret_cast<void *>(detour_));
|
||||
transaction_commit();
|
||||
|
||||
is_applied_ = false;
|
||||
}
|
||||
|
||||
// Esta es la función que llamas desde tu lambda en main.cpp
|
||||
retn call_orig(args ... p)
|
||||
{
|
||||
return reinterpret_cast<type>(orig_)(p...);
|
||||
}
|
||||
|
||||
uintptr_t get_orig() const { return orig_; }
|
||||
bool is_applied() const { return is_applied_; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
25
Client/common/include/Types.h
Normal file
25
Client/common/include/Types.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef COMMON_TYPES_H
|
||||
#define COMMON_TYPES_H
|
||||
|
||||
namespace Types {
|
||||
// Enteros sin signo (Unsigned)
|
||||
typedef unsigned char UInt8; // 1 byte
|
||||
typedef unsigned short UInt16; // 2 bytes
|
||||
typedef unsigned int UInt32; // 4 bytes (Cambiado long por int para asegurar 32bits)
|
||||
typedef unsigned long long UInt64; // 8 bytes
|
||||
|
||||
// Enteros con signo (Signed)
|
||||
typedef signed char SInt8;
|
||||
typedef signed short SInt16;
|
||||
typedef signed int SInt32;
|
||||
typedef signed long long SInt64;
|
||||
|
||||
// Números de coma flotante
|
||||
typedef float Float32;
|
||||
typedef double Float64;
|
||||
|
||||
// Alias útiles para punteros de memoria
|
||||
typedef uintptr_t RawAddr;
|
||||
}
|
||||
|
||||
#endif
|
||||
101
Client/main.cpp
101
Client/main.cpp
|
|
@ -1,36 +1,79 @@
|
|||
#include "f4se/PluginAPI.h"
|
||||
#include <shlobj.h>
|
||||
#include "Global.h"
|
||||
#include "DirectXHook.h"
|
||||
#include <common/include/GamePtr.h>
|
||||
#include <common/include/Utilities.h>
|
||||
#include <common/include/Types.h>
|
||||
#include <common/include/Hook.h>
|
||||
|
||||
// Información del Mod
|
||||
IDebugLog gLog;
|
||||
PluginHandle g_pluginHandle = kPluginHandle_Invalid;
|
||||
F4SEMessagingInterface* g_messaging = NULL;
|
||||
// --- OFFSETS ACTUALIZADOS PARA FALLOUT 4 NEXT-GEN (v1.10.984) ---
|
||||
|
||||
extern "C" {
|
||||
// Esta función la llama F4SE al arrancar para ver si el mod es compatible
|
||||
bool F4SEPlugin_Query(const F4SEInterface* f4se, PluginInfo* info) {
|
||||
gLog.OpenRelative(CSIDL_MYDOCUMENTS, "\\My Games\\Fallout4\\F4SE\\F4MP_Project.log");
|
||||
// v1.10.163 era 0x01262EC0 -> Next-Gen es 0x012B9F80 (VPrint)
|
||||
static Memory::GameAddr <void> printAddr(0x012B9F80);
|
||||
|
||||
// Datos del mod
|
||||
info->infoVersion = PluginInfo::kInfoVersion;
|
||||
info->name = "F4MP_Project";
|
||||
info->version = 1;
|
||||
static Hooks::Hook<Hooks::CallConvention::cdecl_t, void, const char *, va_list> printHook;
|
||||
|
||||
if (f4se->runtimeVersion != RUNTIME_VERSION_1_10_163) {
|
||||
_MESSAGE("ERROR: Version de juego no compatible.");
|
||||
return false;
|
||||
}
|
||||
class ConsoleManager
|
||||
{
|
||||
public:
|
||||
MEMBER_FN_PREFIX(ConsoleManager);
|
||||
// Direcciones actualizadas para la clase ConsoleManager
|
||||
DEFINE_MEMBER_FN(VPrint, void, 0x012B9F80, const char * fmt, va_list args);
|
||||
DEFINE_MEMBER_FN(Print, void, 0x012BA010, const char * str);
|
||||
};
|
||||
|
||||
return true;
|
||||
// Offsets de punteros globales (Data Segment)
|
||||
// g_console: era 0x058E0AE0 -> Next-Gen es 0x059489A0
|
||||
static Memory::GamePtr<ConsoleManager *> g_console(0x059489A0);
|
||||
|
||||
// g_consoleHandle: era 0x05ADB4A8 -> Next-Gen es 0x05B472C8
|
||||
static Memory::GameAddr<Types::UInt32*> g_consoleHandle(0x05B472C8);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
void Console_Print(const char * fmt, ...)
|
||||
{
|
||||
ConsoleManager * mgr = *g_console;
|
||||
if(mgr)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
CALL_MEMBER_FN(mgr, VPrint)(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
// Esta función se ejecuta cuando el mod se carga oficialmente
|
||||
bool F4SEPlugin_Load(const F4SEInterface* f4se) {
|
||||
_MESSAGE("F4MP: Protocolo de terminal cargado correctamente.");
|
||||
|
||||
g_pluginHandle = f4se->GetPluginHandle();
|
||||
|
||||
// Aquí es donde en el futuro "engancharemos" los datos
|
||||
return true;
|
||||
}
|
||||
};
|
||||
void testPrint(const char * fmt, ...){
|
||||
// Función de prueba, no requiere cambios de memoria
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DWORD WINAPI Main(LPVOID lpThreadParameter){
|
||||
// LOGGING
|
||||
AllocConsole();
|
||||
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
|
||||
auto console = spdlog::stdout_color_mt("console");
|
||||
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("f4mp_logger", "logs/f4mp.txt");
|
||||
|
||||
spdlog::set_default_logger(async_file);
|
||||
spdlog::get("console")->info("F4MP Console Loaded (Next-Gen Version)");
|
||||
|
||||
Hooks::DirectX::Init();
|
||||
|
||||
// Hook a la función de impresión de consola del juego
|
||||
printHook.apply(printAddr.GetUIntPtr(), [](const char * fmt, va_list args) -> void {
|
||||
// Nota: args es un va_list, imprimirlo directamente con std::cout puede dar basura o crash
|
||||
// En una terminal real usarías vsnprintf para formatear el mensaje
|
||||
std::cout << "[GAME_CONSOLE] " << fmt << std::endl;
|
||||
return printHook.call_orig(fmt, args);
|
||||
});
|
||||
|
||||
Console_Print("F4MP: SISTEMA INICIADO EN NEXT-GEN");
|
||||
Console_Print("F4MP: COMPROBANDO MEMORIA...");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ... Resto del código (Detach y DllMain) se mantiene igual ...
|
||||
45
Client/src/DirectXHook.h
Normal file
45
Client/src/DirectXHook.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef H_DIRECT3D11
|
||||
#define H_DIRECT3D11
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <vector>
|
||||
|
||||
namespace hDirect3D11 {
|
||||
class Direct3D11 {
|
||||
public:
|
||||
std::vector<uintptr_t> vtable_methods;
|
||||
|
||||
Direct3D11() {
|
||||
ID3D11Device* pDevice = nullptr;
|
||||
ID3D11DeviceContext* pContext = nullptr;
|
||||
IDXGISwapChain* pSwapChain = nullptr;
|
||||
|
||||
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
DXGI_SWAP_CHAIN_DESC scd = {};
|
||||
scd.BufferCount = 1;
|
||||
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
scd.OutputWindow = GetForegroundWindow();
|
||||
scd.SampleDesc.Count = 1;
|
||||
scd.Windowed = TRUE;
|
||||
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
if (SUCCEEDED(D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, &featureLevel, 1, D3D11_SDK_VERSION, &scd, &pSwapChain, &pDevice, nullptr, &pContext))) {
|
||||
uintptr_t* vtable = *(uintptr_t**)pSwapChain;
|
||||
for (int i = 0; i < 150; i++) {
|
||||
vtable_methods.push_back(vtable[i]);
|
||||
}
|
||||
pSwapChain->Release();
|
||||
pDevice->Release();
|
||||
pContext->Release();
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t* vtable() { return vtable_methods.data(); }
|
||||
};
|
||||
}
|
||||
|
||||
namespace hDXGI {
|
||||
enum Index { Present = 8 };
|
||||
}
|
||||
#endif
|
||||
83
Client/src/Hooks/Direct3D11.h
Normal file
83
Client/src/Hooks/Direct3D11.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include "DirectXHook.h"
|
||||
#include <mutex>
|
||||
|
||||
// Definición de variables globales
|
||||
HWND g_windowHandle = NULL;
|
||||
ID3D11Device* g_d3d11Device = NULL;
|
||||
ID3D11DeviceContext* g_d3d11Context = NULL;
|
||||
IDXGISwapChain* g_d3d11SwapChain = NULL;
|
||||
ID3D11RenderTargetView* g_mainRenderTargetView = NULL;
|
||||
bool g_ShowMenu = false;
|
||||
bool g_Initialized = false;
|
||||
|
||||
namespace Hooks {
|
||||
namespace DirectX {
|
||||
|
||||
void Init() {
|
||||
try {
|
||||
auto d3d11 = std::make_unique<hDirect3D11::Direct3D11>();
|
||||
uintptr_t* vtable = d3d11->vtable();
|
||||
|
||||
spdlog::info("[F4MP] Hooking DXGI Present...");
|
||||
|
||||
swapChainPresent11Hook.apply(vtable[hDXGI::Present], [](IDXGISwapChain* chain, UINT SyncInterval, UINT Flags) -> HRESULT {
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, [&chain]() {
|
||||
g_d3d11SwapChain = chain;
|
||||
if (SUCCEEDED(chain->GetDevice(__uuidof(ID3D11Device), (void**)&g_d3d11Device))) {
|
||||
Pre_Render(chain);
|
||||
g_Initialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
Render();
|
||||
return swapChainPresent11Hook.call_orig(chain, SyncInterval, Flags);
|
||||
});
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
spdlog::error("[F4MP] DX11 Hook Error: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void Pre_Render(IDXGISwapChain* swapChain) {
|
||||
swapChain->GetDevice(__uuidof(ID3D11Device), (void**)&g_d3d11Device);
|
||||
g_d3d11Device->GetImmediateContext(&g_d3d11Context);
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
swapChain->GetDesc(&sd);
|
||||
g_windowHandle = sd.OutputWindow;
|
||||
|
||||
// Hook al WndProc para el ratón
|
||||
OriginalWndProcHandler = (WNDPROC)SetWindowLongPtr(g_windowHandle, GWLP_WNDPROC, (LONG_PTR)hWndProc);
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui_ImplWin32_Init(g_windowHandle);
|
||||
ImGui_ImplDX11_Init(g_d3d11Device, g_d3d11Context);
|
||||
|
||||
ID3D11Texture2D* pBackBuffer;
|
||||
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
||||
g_d3d11Device->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
|
||||
void Render() {
|
||||
if (!g_Initialized) return;
|
||||
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (g_ShowMenu) {
|
||||
ImGui::Begin("F4MP Next-Gen Console", &g_ShowMenu);
|
||||
ImGui::Text("F4MP Experimental Multiplayer Mod");
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Unload Mod")) { /* Lógica de salida */ }
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
g_d3d11Context->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
|
||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
}
|
||||
}
|
||||
85
README.md
85
README.md
|
|
@ -1,38 +1,67 @@
|
|||
# Project F4MP - Fallout 4 Multiplayer Mod
|
||||
# F4MP - Fallout 4 Multiplayer Project 🚀
|
||||
|
||||
<p align="center">
|
||||
<img src="logo.png" alt="Project F4MP Logo" width="400">
|
||||
<img src="/logo.png" alt="F4MP Logo" width="300">
|
||||
<br>
|
||||
<i>Reconstruyendo la Commonwealth, un paquete de datos a la vez.</i>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
## ☢️ Sobre el Proyecto
|
||||
**Project F4MP** es una ambiciosa modificación para **Fallout 4** que introduce capacidades multijugador en el Commonwealth. Explora el yermo, completa misiones y sobrevive a los peligros post-apocalípticos junto a tus amigos.
|
||||
## 📝 Descripción del Proyecto
|
||||
|
||||
## ✨ Características Principales
|
||||
* **Sincronización en Tiempo Real:** Jugadores, NPCs y clima sincronizados.
|
||||
* **Mundo Persistente:** Servidores dedicados para una experiencia continua.
|
||||
* **Compatibilidad:** Diseñado para trabajar con una amplia selección de mods de la comunidad.
|
||||
* **Estilo Pip-Boy:** Interfaz integrada fiel a la estética de Bethesda.
|
||||
**F4MP** es un ambicioso proyecto de código abierto que busca implementar una infraestructura multijugador robusta para **Fallout 4**. A diferencia de otros intentos, F4MP se centra en la creación de un sistema de sincronización basado en un servidor maestro que permita la persistencia de datos, el combate cooperativo y la construcción de asentamientos compartidos.
|
||||
|
||||
## 🚀 Instalación
|
||||
1. Descarga la última versión desde la sección de [Releases](../../releases).
|
||||
2. Extrae el contenido en tu carpeta raíz de **Fallout 4**.
|
||||
3. Ejecuta `F4MP_Launcher.exe`.
|
||||
4. ¡Conéctate a un servidor y empieza a jugar!
|
||||
|
||||
## 🛠️ Requisitos
|
||||
* Fallout 4 (Versión de Steam/GOG actualizada).
|
||||
* F4SE (Fallout 4 Script Extender).
|
||||
* Una conexión a internet estable.
|
||||
|
||||
## 🤝 Contribuir
|
||||
¿Quieres ayudar a reconstruir el mundo? ¡Las contribuciones son bienvenidas!
|
||||
* Reporta bugs en el apartado de **Issues**.
|
||||
* Propón nuevas ideas en **Discussions**.
|
||||
* Revisa nuestro sitio web oficial: [f4mp.joustech.space](https://f4mp.joustech.space/)
|
||||
Este proyecto es de carácter **educativo y sin ánimo de lucro**, desarrollado por y para la comunidad de entusiastas de la saga.
|
||||
|
||||
---
|
||||
<p align="center">
|
||||
Hecho con ❤️ por la comunidad de Project F4MP.
|
||||
</p>
|
||||
|
||||
## 🔬 Fase Actual: Investigación y Análisis (R&D)
|
||||
|
||||
Actualmente, el repositorio **no contiene binarios ejecutables**. Nos encontramos en una fase de ingeniería inversa profunda para asegurar que la base del mod sea estable antes de cualquier lanzamiento público.
|
||||
|
||||
### Objetivos de Investigación Crítica:
|
||||
* **Sincronización de Transformaciones:** Mapeo de vectores de posición y rotación de entidades en el Creation Engine.
|
||||
* **Hooking de Memoria:** Implementación de interceptores para acciones de combate (VATS, disparo, daño recibido).
|
||||
* **World State Sync:** Análisis de la persistencia de objetos soltados y cambios en el entorno (Cells).
|
||||
* **Protocolo de Red:** Desarrollo de una capa de transporte híbrida UDP/TCP para minimizar la latencia en el desierto capital.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Arquitectura del Sistema
|
||||
|
||||
El ecosistema F4MP se compone de tres pilares tecnológicos:
|
||||
|
||||
1. **F4MP Client Core:** Un inyector desarrollado en C++ que actúa como puente entre el motor del juego y nuestra red.
|
||||
2. **Master Server:** Backend escalable encargado de la validación de usuarios, gestión de instancias y retransmisión de estados.
|
||||
3. **Terminal de Control Web:** Interfaz de usuario para la gestión de residentes y monitorización del sistema.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Seguimiento y Progreso
|
||||
|
||||
Para evitar la fragmentación de la información, el progreso detallado de cada fase se publica exclusivamente en nuestra terminal oficial. Allí podrás ver el estado de los módulos de investigación y los hitos alcanzados.
|
||||
|
||||
👉 **[CONSULTAR ROADMAP OFICIAL EN LA WEB](https://f4mp.joustech.space/roadmap.php)**
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Cómo contribuir
|
||||
|
||||
Si tienes conocimientos en **ingeniería inversa, C++, Assembly (x64)** o **protocolos de red**, tu ayuda es bienvenida.
|
||||
|
||||
1. Haz un **Fork** del proyecto.
|
||||
2. Crea una rama para tu investigación (`git checkout -b feature/investigacion-x`).
|
||||
3. Abre un **Pull Request** detallando tus hallazgos en la memoria del juego.
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ Aviso Legal (Disclaimer)
|
||||
|
||||
F4MP es un proyecto independiente y no está afiliado a Bethesda Softworks ni ZeniMax Media. El uso de este software es bajo tu propio riesgo y requiere una copia legal de Fallout 4. Todos los nombres y marcas registradas pertenecen a sus respectivos dueños.
|
||||
|
|
|
|||
Loading…
Reference in a new issue