File: Game.cpp

package info (click to toggle)
mumble 1.5.735-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 90,008 kB
  • sloc: cpp: 556,921; ansic: 81,662; python: 3,606; sh: 659; makefile: 506; asm: 371; cs: 306; sql: 228; javascript: 143; perl: 80; xml: 13
file content (134 lines) | stat: -rw-r--r-- 4,491 bytes parent folder | download | duplicates (2)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2020-2023 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "Game.h"

#include "mumble_positional_audio_utils.h"

Game::Game(const procid_t id, const std::string name) : m_proc(id, name) {
}

Mumble_PositionalDataErrorCode Game::init() {
	if (!m_proc.isOk()) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	const auto &modules = m_proc.modules();
	const auto iter     = modules.find("GameAssembly.dll");
	if (iter == modules.cend()) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	// 75 58             jnz    short loc_????????
	// A1 ?? ?? ?? ??    mov    eax, AmongUsClient_c **
	// 8B 40 5C          mov    eax, [eax+5Ch]
	const std::vector< uint8_t > clientPattern = { 0x75, 0x58, 0xA1, '?', '?', '?', '?', 0x8B, 0x40, 0x5C };
	m_client                                   = m_proc.findPattern(clientPattern, iter->second);

	if (!m_client) {
		return MUMBLE_PDEC_ERROR_PERM;
	}

	// +3 in order to skip to the memory address we actually care about
	m_client = m_proc.peekPtr(m_proc.peekPtr(m_client + 3));
	if (!m_client) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	const auto clientC = m_proc.peek< AmongUsClient_c >(m_client);
	if (!clientC.staticFields) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	const auto clientStaticFields = m_proc.peek< AmongUsClient_StaticFields >(clientC.staticFields);
	if (!clientStaticFields.instance) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	m_client = clientStaticFields.instance;

	const auto fields = clientFields();

	const auto playerControlO = m_proc.peek< PlayerControl_o >(fields.playerPrefab);
	if (!playerControlO.klass) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	const auto playerControlC = m_proc.peek< PlayerControl_c >(playerControlO.klass);
	if (!playerControlC.staticFields) {
		return MUMBLE_PDEC_ERROR_TEMP;
	}

	m_playerControlStaticFields = playerControlC.staticFields;

	return MUMBLE_PDEC_OK;
}

PlayerControl_Fields Game::playerControlFields() {
	const auto playerControlStaticFields = m_proc.peek< PlayerControl_StaticFields >(m_playerControlStaticFields);
	if (playerControlStaticFields.localPlayer) {
		return m_proc.peek< PlayerControl_o >(playerControlStaticFields.localPlayer).fields;
	}

	return {};
}

GameData_PlayerOutfit_Fields Game::playerOutfitFields(const GameData_PlayerInfo_Fields &fields) {
	const auto dictFields = m_proc.peek< Dictionary_o >(fields.outfits).fields;
	if (!dictFields.entries || dictFields.count < 1) {
		return {};
	}

	const auto array = m_proc.peek< Dictionary_Array >(dictFields.entries);

	return m_proc.peek< GameData_PlayerOutfit_o >(array.items[0].value).fields;
}

std::string Game::string(const procptr_t address) {
	const auto object = m_proc.peek< String_o >(address);

	std::u16string string;
	string.resize(object.fields.length);
	if (m_proc.peek(address + sizeof(object), &string[0], sizeof(char16_t) * string.size())) {
		return utf16ToUtf8(string.data());
	}

	return {};
}

const std::string &Game::context(const AmongUsClient_Fields &fields) {
	std::ostringstream stream;

	stream << " {\"Game ID\": " << fields.gameId << "}";

	m_context = stream.str();

	return m_context;
}

const std::string &Game::identity(const AmongUsClient_Fields &fields, const PlayerControl_Fields &controlFields) {
	const GameData_PlayerInfo_Fields infoFields     = playerInfoFields(controlFields);
	const GameData_PlayerOutfit_Fields outfitFields = playerOutfitFields(infoFields);

	std::ostringstream stream;

	stream << "ID: " << std::to_string(infoFields.playerId) << '\n';
	stream << "Name: " << string(outfitFields.playerName) << '\n';
	stream << "Level: " << std::to_string(infoFields.playerLevel + 1) << '\n';
	stream << "Color ID: " << std::to_string(outfitFields.colorId) << '\n';
	stream << "Skin: " << string(outfitFields.skinId) << '\n';
	stream << "Hat: " << string(outfitFields.hatId) << '\n';
	stream << "Visor: " << string(outfitFields.visorId) << '\n';
	stream << "Pet: " << string(outfitFields.petId) << '\n';
	stream << "Nameplate: " << string(outfitFields.namePlateId) << '\n';
	stream << "Dead: " << (infoFields.isDead ? "true" : "false") << '\n';
	stream << "Client ID: " << std::to_string(fields.clientId) << '\n';
	stream << "Host ID: " << std::to_string(fields.hostId) << '\n';
	stream << "Public game: " << (fields.isGamePublic ? "true" : "false");

	m_identity = stream.str();

	return m_identity;
}