aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/mods/reload/reloadmodweapons.cpp
blob: 297c3d4821c337543e9f5bf2a25283b3326444ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "mods/modmanager.h"

AUTOHOOK_INIT()

OFFSET_STRUCT(WeaponDefinition)
{
	FIELD(5, bool bUnk); // this controls whether we reload script funcs
	FIELD(6, char pWeaponName[]); // this probably has a max length but i do not know what it is
};

OFFSET_STRUCT(GlobalWeaponDefs)
{
	// each entry is 24 bytes, but no clue what the bytes after the def are, so just ignore atm
	// need the full struct so we iterate properly
	OFFSET_STRUCT(WeaponDefContainer)
	{
		STRUCT_SIZE(24);
		WeaponDefinition* pWeaponDef;
	};

	FIELD(16, WeaponDefContainer m_Weapons[]);
};

uint16_t* g_pnClientWeaponsLoaded;
GlobalWeaponDefs** g_ppClientWeaponDefs;

void (*ClientReparseWeapon)(WeaponDefinition* pWeapon);
void (*ClientReloadWeaponCallbacks)(int nWeaponIndex);
int (*ClientWeaponIndexByName)(const char* pWeaponName);

uint16_t* g_pnServerWeaponsLoaded;
GlobalWeaponDefs** g_ppServerWeaponDefs;

void (*ServerReparseWeapon)(WeaponDefinition* pWeapon);
void (*ServerReloadWeaponCallbacks)(int nWeaponIndex);
int (*ServerWeaponIndexByName)(const char* pWeaponName);

// used for passing client/server funcs/data/pointers to TryReloadWeapon
struct SidedWeaponReloadPointers
{
	// data pointers
	uint16_t* m_pnWeaponsLoaded;
	GlobalWeaponDefs** m_ppWeaponDefs;

	// funcs
	void (*m_fnReparseWeapon)(WeaponDefinition* pWeapon);
	void (*m_fnReloadWeaponCallbacks)(int nWeaponIndex);
	int (*m_fnWeaponIndexByName)(const char* pWeaponName);

	SidedWeaponReloadPointers(
		uint16_t* pnWeaponsLoaded,
		GlobalWeaponDefs** ppWeaponDefs,
		void (*fnReparseWeapon)(WeaponDefinition*),
		void (*fnReloadWeaponCallbacks)(int),
		int (*fnWeaponIndexByName)(const char*))
	{
		m_pnWeaponsLoaded = pnWeaponsLoaded;
		m_ppWeaponDefs = ppWeaponDefs;
		m_fnReparseWeapon = fnReparseWeapon;
		m_fnReloadWeaponCallbacks = fnReloadWeaponCallbacks;
		m_fnWeaponIndexByName = fnWeaponIndexByName;
	}
};

bool ModManager::TryReloadWeapon(const char* pWeaponName, const SidedWeaponReloadPointers* pReloadPointers)
{
	if (!m_AssetTypesToReload.setsWeaponSettings.contains(pWeaponName))
		return false; // don't reload

	int nWeaponIndex = pReloadPointers->m_fnWeaponIndexByName(pWeaponName);
	if (nWeaponIndex == -1) // weapon isn't loaded at all, no need to reload!
		return false;

	spdlog::info("ModManager::TryReloadWeapon reloading weapon {}", pWeaponName);

	WeaponDefinition* pWeapon = (*pReloadPointers->m_ppWeaponDefs)->m_Weapons->pWeaponDef;
	pReloadPointers->m_fnReparseWeapon(pWeapon);
	if (pWeapon->bUnk)
		pReloadPointers->m_fnReloadWeaponCallbacks(nWeaponIndex);

	m_AssetTypesToReload.setsWeaponSettings.erase(pWeaponName);
	return true;
}

// TODO: server implementation for this?
AUTOHOOK(ClientPrecacheWeaponFromStringtable, client.dll + 0x195A60,
bool, __fastcall, (void* a1, void* a2, void* a3, const char* pWeaponName))
{
	static SidedWeaponReloadPointers clientReloadPointers(
		g_pnClientWeaponsLoaded, g_ppClientWeaponDefs, ClientReparseWeapon, ClientReloadWeaponCallbacks, ClientWeaponIndexByName);

	if (g_pModManager->TryReloadWeapon(pWeaponName, &clientReloadPointers))
		return true;

	spdlog::info("PrecacheWeaponFromStringtable: {}", pWeaponName);
	return ClientPrecacheWeaponFromStringtable(a1, a2, a3, pWeaponName);
}

ON_DLL_LOAD_CLIENT("client.dll", ModReloadWeaponsClient, (CModule module))
{
	AUTOHOOK_DISPATCH()

	g_pnClientWeaponsLoaded = module.Offset(0xB33A02).As<uint16_t*>();
	g_ppClientWeaponDefs = module.Offset(0xB339E8).As<GlobalWeaponDefs**>();

	ClientReparseWeapon = module.Offset(0x3D2FB0).As<void(*)(WeaponDefinition*)>();
	ClientReloadWeaponCallbacks = module.Offset(0x3CE270).As<void(*)(int)>();
}