From 8a1e96fc2a7174888e84914b040a29bc8bdf422f Mon Sep 17 00:00:00 2001 From: Carbon Date: Wed, 25 Nov 2020 19:17:42 -0600 Subject: [PATCH] Put the whole GameMemReader in a try catch loop --- AmongUsCapture/Memory/GameMemReader.cs | 698 +++++++++++++------------ 1 file changed, 368 insertions(+), 330 deletions(-) diff --git a/AmongUsCapture/Memory/GameMemReader.cs b/AmongUsCapture/Memory/GameMemReader.cs index ab7da996..ae17a808 100644 --- a/AmongUsCapture/Memory/GameMemReader.cs +++ b/AmongUsCapture/Memory/GameMemReader.cs @@ -76,443 +76,481 @@ public void RunLoop() { while (true) { - if (!ProcessMemory.getInstance().IsHooked || ProcessMemory.getInstance().process is null || ProcessMemory.getInstance().process.HasExited) + try { - if (!ProcessMemory.getInstance().HookProcess("Among Us")) + if (!ProcessMemory.getInstance().IsHooked || ProcessMemory.getInstance().process is null || + ProcessMemory.getInstance().process.HasExited) { - Thread.Sleep(1000); - continue; - } + if (!ProcessMemory.getInstance().HookProcess("Among Us")) + { + Thread.Sleep(1000); + continue; + } - Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, $"Connected to Among Us process ({Color.Red.ToTextColor()}{ProcessMemory.getInstance().process.Id}{Settings.conInterface.getNormalColor().ToTextColor()})"); + Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, + $"Connected to Among Us process ({Color.Red.ToTextColor()}{ProcessMemory.getInstance().process.Id}{Settings.conInterface.getNormalColor().ToTextColor()})"); - var foundModule = false; + var foundModule = false; - while (true) - { - foreach (var module in ProcessMemory.getInstance().modules) - if (module.Name.Equals("GameAssembly.dll", StringComparison.OrdinalIgnoreCase)) - { - GameAssemblyPtr = module.BaseAddress; - if (!GameVerifier.VerifySteamHash(module.FileName)) - { - cracked = true; - Settings.conInterface.WriteModuleTextColored("GameVerifier", Color.Red, - $"Client verification: {Color.Red.ToTextColor()}FAIL{Settings.conInterface.getNormalColor().ToTextColor()}."); - } - else - { - cracked = false; - Settings.conInterface.WriteModuleTextColored("GameVerifier", Color.Red, $"Client verification: {Color.Lime.ToTextColor()}PASS{Settings.conInterface.getNormalColor().ToTextColor()}."); - } - using (SHA256Managed sha256 = new SHA256Managed()) + while (true) + { + foreach (var module in ProcessMemory.getInstance().modules) + if (module.Name.Equals("GameAssembly.dll", StringComparison.OrdinalIgnoreCase)) { - using (FileStream fs = new FileStream(module.FileName, FileMode.Open, FileAccess.Read)) + GameAssemblyPtr = module.BaseAddress; + if (!GameVerifier.VerifySteamHash(module.FileName)) { - using (var bs = new BufferedStream(fs)) - { - var hash = sha256.ComputeHash(bs); - StringBuilder GameAssemblyhashSb = new StringBuilder(2 * hash.Length); - foreach (byte byt in hash) - { - GameAssemblyhashSb.AppendFormat("{0:X2}", byt); - } + cracked = true; + Settings.conInterface.WriteModuleTextColored("GameVerifier", Color.Red, + $"Client verification: {Color.Red.ToTextColor()}FAIL{Settings.conInterface.getNormalColor().ToTextColor()}."); + } + else + { + cracked = false; + Settings.conInterface.WriteModuleTextColored("GameVerifier", Color.Red, + $"Client verification: {Color.Lime.ToTextColor()}PASS{Settings.conInterface.getNormalColor().ToTextColor()}."); + } - Console.WriteLine($"GameAssembly Hash: {GameAssemblyhashSb.ToString()}"); - GameHash = GameAssemblyhashSb.ToString(); - CurrentOffsets = offMan.FetchForHash(GameAssemblyhashSb.ToString()); - if (CurrentOffsets is not null) - { - Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, $"Loaded offsets: {CurrentOffsets.Description}"); - } - else + using (SHA256Managed sha256 = new SHA256Managed()) + { + using (FileStream fs = new FileStream(module.FileName, FileMode.Open, + FileAccess.Read)) + { + using (var bs = new BufferedStream(fs)) { - Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, $"No offsets found for: {Color.Aqua.ToTextColor()}{GameAssemblyhashSb.ToString()}."); + var hash = sha256.ComputeHash(bs); + StringBuilder GameAssemblyhashSb = new StringBuilder(2 * hash.Length); + foreach (byte byt in hash) + { + GameAssemblyhashSb.AppendFormat("{0:X2}", byt); + } + + Console.WriteLine( + $"GameAssembly Hash: {GameAssemblyhashSb.ToString()}"); + GameHash = GameAssemblyhashSb.ToString(); + CurrentOffsets = offMan.FetchForHash(GameAssemblyhashSb.ToString()); + if (CurrentOffsets is not null) + { + Settings.conInterface.WriteModuleTextColored("GameMemReader", + Color.Lime, $"Loaded offsets: {CurrentOffsets.Description}"); + } + else + { + Settings.conInterface.WriteModuleTextColored("GameMemReader", + Color.Lime, + $"No offsets found for: {Color.Aqua.ToTextColor()}{GameAssemblyhashSb.ToString()}."); + + } } - } - } + } + + foundModule = true; + break; } - foundModule = true; - break; + if (!foundModule) + { + Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, + "Still looking for modules..."); + //Program.conInterface.WriteModuleTextColored("GameMemReader", Color.Green, "Still looking for modules..."); // TODO: This still isn't functional, we need to re-hook to reload module addresses + Thread.Sleep(500); // delay and try again + ProcessMemory.getInstance().LoadModules(); } + else + { + break; // we have found all modules + } + } - if (!foundModule) + try { - Settings.conInterface.WriteModuleTextColored("GameMemReader", Color.Lime, - "Still looking for modules..."); - //Program.conInterface.WriteModuleTextColored("GameMemReader", Color.Green, "Still looking for modules..."); // TODO: This still isn't functional, we need to re-hook to reload module addresses - Thread.Sleep(500); // delay and try again - ProcessMemory.getInstance().LoadModules(); + prevChatBubsVersion = ProcessMemory.getInstance().Read(GameAssemblyPtr, + CurrentOffsets.HudManagerOffset, 0x5C, + 0, 0x28, 0xC, 0x14, 0x10); + // prevGameOverReason = ProcessMemory.getInstance().Read(GameAssemblyPtr, _gameOffsets.TempDataOffset, 0x5c, 4); } - else + catch { - break; // we have found all modules + Settings.conInterface.WriteModuleTextColored("ERROR", Color.Red, + "Outdated version of the game."); } - } - try - { - prevChatBubsVersion = ProcessMemory.getInstance().Read(GameAssemblyPtr, - CurrentOffsets.HudManagerOffset, 0x5C, - 0, 0x28, 0xC, 0x14, 0x10); - // prevGameOverReason = ProcessMemory.getInstance().Read(GameAssemblyPtr, _gameOffsets.TempDataOffset, 0x5c, 4); } - catch + + if (cracked && ProcessMemory.getInstance().IsHooked) { - Settings.conInterface.WriteModuleTextColored("ERROR",Color.Red, "Outdated version of the game."); + var result = Settings.conInterface.CrackDetected(); + if (!result) + Environment.Exit(0); + else + cracked = false; + continue; } - - } - if (cracked && ProcessMemory.getInstance().IsHooked) - { - var result = Settings.conInterface.CrackDetected(); - if (!result) - Environment.Exit(0); - else - cracked = false; - continue; - } - GameState state; - //int meetingHudState = /*meetingHud_cachePtr == 0 ? 4 : */ProcessMemory.ReadWithDefault(GameAssemblyPtr, 4, 0xDA58D0, 0x5C, 0, 0x84); // 0 = Discussion, 1 = NotVoted, 2 = Voted, 3 = Results, 4 = Proceeding - var meetingHud = ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.MeetingHudOffset, 0x5C, 0); - var meetingHud_cachePtr = meetingHud == IntPtr.Zero ? 0 : ProcessMemory.getInstance().Read(meetingHud, 0x8); - var meetingHudState = - meetingHud_cachePtr == 0 - ? 4 - : ProcessMemory.getInstance().ReadWithDefault(meetingHud, 4, - 0x84); // 0 = Discussion, 1 = NotVoted, 2 = Voted, 3 = Results, 4 = Proceeding - var gameState = - ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.AmongUsClientOffset, 0x5C, 0, - 0x64); // 0 = NotJoined, 1 = Joined, 2 = Started, 3 = Ended (during "defeat" or "victory" screen only) - - switch (gameState) - { - case 0: - state = GameState.MENU; - exileCausesEnd = false; - break; - case 1: - case 3: - state = GameState.LOBBY; - exileCausesEnd = false; - break; - default: + GameState state; + //int meetingHudState = /*meetingHud_cachePtr == 0 ? 4 : */ProcessMemory.ReadWithDefault(GameAssemblyPtr, 4, 0xDA58D0, 0x5C, 0, 0x84); // 0 = Discussion, 1 = NotVoted, 2 = Voted, 3 = Results, 4 = Proceeding + var meetingHud = ProcessMemory.getInstance() + .Read(GameAssemblyPtr, CurrentOffsets.MeetingHudOffset, 0x5C, 0); + var meetingHud_cachePtr = meetingHud == IntPtr.Zero + ? 0 + : ProcessMemory.getInstance().Read(meetingHud, 0x8); + var meetingHudState = + meetingHud_cachePtr == 0 + ? 4 + : ProcessMemory.getInstance().ReadWithDefault(meetingHud, 4, + 0x84); // 0 = Discussion, 1 = NotVoted, 2 = Voted, 3 = Results, 4 = Proceeding + var gameState = + ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.AmongUsClientOffset, 0x5C, + 0, + 0x64); // 0 = NotJoined, 1 = Joined, 2 = Started, 3 = Ended (during "defeat" or "victory" screen only) + + switch (gameState) { - if (exileCausesEnd) + case 0: + state = GameState.MENU; + exileCausesEnd = false; + break; + case 1: + case 3: state = GameState.LOBBY; - else if (meetingHudState < 4) - state = GameState.DISCUSSION; - else - state = GameState.TASKS; - - break; + exileCausesEnd = false; + break; + default: + { + if (exileCausesEnd) + state = GameState.LOBBY; + else if (meetingHudState < 4) + state = GameState.DISCUSSION; + else + state = GameState.TASKS; + + break; + } } - } - //Console.WriteLine($"Got state: {state}"); + //Console.WriteLine($"Got state: {state}"); - var allPlayersPtr = - ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.GameDataOffset, 0x5C, 0, 0x24); - var allPlayers = ProcessMemory.getInstance().Read(allPlayersPtr, 0x08); - var playerCount = ProcessMemory.getInstance().Read(allPlayersPtr, 0x0C); + var allPlayersPtr = + ProcessMemory.getInstance() + .Read(GameAssemblyPtr, CurrentOffsets.GameDataOffset, 0x5C, 0, 0x24); + var allPlayers = ProcessMemory.getInstance().Read(allPlayersPtr, 0x08); + var playerCount = ProcessMemory.getInstance().Read(allPlayersPtr, 0x0C); - var playerAddrPtr = allPlayers + 0x10; - - // check if exile causes end - if (oldState == GameState.DISCUSSION && state == GameState.TASKS) - { - var exiledPlayerId = ProcessMemory.getInstance().ReadWithDefault(GameAssemblyPtr, 255, - CurrentOffsets.MeetingHudOffset, 0x5C, 0, 0x94, 0x08); - int impostorCount = 0, innocentCount = 0; + var playerAddrPtr = allPlayers + 0x10; - for (var i = 0; i < playerCount; i++) + // check if exile causes end + if (oldState == GameState.DISCUSSION && state == GameState.TASKS) { - var pi = ProcessMemory.getInstance().Read(playerAddrPtr, 0, 0); - playerAddrPtr += 4; + var exiledPlayerId = ProcessMemory.getInstance().ReadWithDefault(GameAssemblyPtr, 255, + CurrentOffsets.MeetingHudOffset, 0x5C, 0, 0x94, 0x08); + int impostorCount = 0, innocentCount = 0; - if (pi.PlayerId == exiledPlayerId) - PlayerChanged?.Invoke(this, new PlayerChangedEventArgs - { - Action = PlayerAction.Exiled, - Name = pi.GetPlayerName(), - IsDead = pi.GetIsDead(), - Disconnected = pi.GetIsDisconnected(), - Color = pi.GetPlayerColor() - }); + for (var i = 0; i < playerCount; i++) + { + var pi = ProcessMemory.getInstance().Read(playerAddrPtr, 0, 0); + playerAddrPtr += 4; - // skip invalid, dead and exiled players - if (pi.PlayerName == 0 || pi.PlayerId == exiledPlayerId || pi.IsDead == 1 || - pi.Disconnected == 1) continue; + if (pi.PlayerId == exiledPlayerId) + PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + { + Action = PlayerAction.Exiled, + Name = pi.GetPlayerName(), + IsDead = pi.GetIsDead(), + Disconnected = pi.GetIsDisconnected(), + Color = pi.GetPlayerColor() + }); + + // skip invalid, dead and exiled players + if (pi.PlayerName == 0 || pi.PlayerId == exiledPlayerId || pi.IsDead == 1 || + pi.Disconnected == 1) continue; + + if (pi.IsImpostor == 1) + impostorCount++; + else + innocentCount++; + } - if (pi.IsImpostor == 1) - impostorCount++; - else - innocentCount++; + if (impostorCount == 0 || impostorCount >= innocentCount) + { + exileCausesEnd = true; + state = GameState.LOBBY; + } } - if (impostorCount == 0 || impostorCount >= innocentCount) + if (state != oldState || shouldForceTransmitState) { - exileCausesEnd = true; - state = GameState.LOBBY; + GameStateChanged?.Invoke(this, new GameStateChangedEventArgs {NewState = state}); + shouldForceTransmitState = false; } - } - if (state != oldState || shouldForceTransmitState) - { - GameStateChanged?.Invoke(this, new GameStateChangedEventArgs {NewState = state}); - shouldForceTransmitState = false; - } + if (state != oldState && state == GameState.LOBBY) + { + shouldReadLobby = true; // will eventually transmit + } - if (state != oldState && state == GameState.LOBBY) - { - shouldReadLobby = true; // will eventually transmit - } - - if ((oldState == GameState.DISCUSSION || oldState == GameState.TASKS) && (state == GameState.LOBBY || state == GameState.MENU)) // game ended - { - int rawGameOverReason = ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.TempDataOffset, 0x5c, 0x4); - GameOverReason gameOverReason = (GameOverReason)rawGameOverReason; + if ((oldState == GameState.DISCUSSION || oldState == GameState.TASKS) && + (state == GameState.LOBBY || state == GameState.MENU)) // game ended + { + int rawGameOverReason = ProcessMemory.getInstance() + .Read(GameAssemblyPtr, CurrentOffsets.TempDataOffset, 0x5c, 0x4); + GameOverReason gameOverReason = (GameOverReason) rawGameOverReason; - bool humansWon = rawGameOverReason <= 1 || rawGameOverReason == 5; + bool humansWon = rawGameOverReason <= 1 || rawGameOverReason == 5; - if (humansWon) // we will be reading humans data, so set all to imps - { - foreach (string playerName in CachedPlayerInfos.Keys) + if (humansWon) // we will be reading humans data, so set all to imps { - CachedPlayerInfos[playerName].IsImpostor = true; + foreach (string playerName in CachedPlayerInfos.Keys) + { + CachedPlayerInfos[playerName].IsImpostor = true; + } } - } - var winningPlayersPtr = ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.TempDataOffset, 0x5C, 0xC); - var winningPlayers = ProcessMemory.getInstance().Read(winningPlayersPtr, 0x08); - var winningPlayerCount = ProcessMemory.getInstance().Read(winningPlayersPtr, 0x0C); + var winningPlayersPtr = ProcessMemory.getInstance() + .Read(GameAssemblyPtr, CurrentOffsets.TempDataOffset, 0x5C, 0xC); + var winningPlayers = ProcessMemory.getInstance().Read(winningPlayersPtr, 0x08); + var winningPlayerCount = ProcessMemory.getInstance().Read(winningPlayersPtr, 0x0C); - var winnerAddrPtr = winningPlayers + 0x10; + var winnerAddrPtr = winningPlayers + 0x10; - for (var i = 0; i < winningPlayerCount; i++) - { - WinningPlayerData wpi = ProcessMemory.getInstance().Read(winnerAddrPtr, 0, 0); - winnerAddrPtr += 4; - CachedPlayerInfos[wpi.GetPlayerName()].IsImpostor = wpi.IsImpostor; - } + for (var i = 0; i < winningPlayerCount; i++) + { + WinningPlayerData wpi = ProcessMemory.getInstance() + .Read(winnerAddrPtr, 0, 0); + winnerAddrPtr += 4; + CachedPlayerInfos[wpi.GetPlayerName()].IsImpostor = wpi.IsImpostor; + } - ImmutablePlayer[] endingPlayerInfos = new ImmutablePlayer[CachedPlayerInfos.Count]; - CachedPlayerInfos.Values.CopyTo(endingPlayerInfos, 0); + ImmutablePlayer[] endingPlayerInfos = new ImmutablePlayer[CachedPlayerInfos.Count]; + CachedPlayerInfos.Values.CopyTo(endingPlayerInfos, 0); - GameOver?.Invoke(this, new GameOverEventArgs - { - GameOverReason = gameOverReason, - PlayerInfos = endingPlayerInfos - }); - } + GameOver?.Invoke(this, new GameOverEventArgs + { + GameOverReason = gameOverReason, + PlayerInfos = endingPlayerInfos + }); + } - GameState cachedOldState = oldState; + GameState cachedOldState = oldState; - oldState = state; + oldState = state; - newPlayerInfos.Clear(); + newPlayerInfos.Clear(); - playerAddrPtr = allPlayers + 0x10; + playerAddrPtr = allPlayers + 0x10; - for (var i = 0; i < playerCount; i++) - { - var pi = ProcessMemory.getInstance().Read(playerAddrPtr, 0, 0); - playerAddrPtr += 4; - if (pi.PlayerName == 0) continue; - var playerName = pi.GetPlayerName(); - if (playerName.Length == 0) continue; + for (var i = 0; i < playerCount; i++) + { + var pi = ProcessMemory.getInstance().Read(playerAddrPtr, 0, 0); + playerAddrPtr += 4; + if (pi.PlayerName == 0) continue; + var playerName = pi.GetPlayerName(); + if (playerName.Length == 0) continue; - newPlayerInfos[playerName] = pi; // add to new playerinfos for comparison later + newPlayerInfos[playerName] = pi; // add to new playerinfos for comparison later - if (!oldPlayerInfos.ContainsKey(playerName)) // player wasn't here before, they just joined - { - PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + if (!oldPlayerInfos.ContainsKey(playerName)) // player wasn't here before, they just joined { - Action = PlayerAction.Joined, - Name = playerName, - IsDead = pi.GetIsDead(), - Disconnected = pi.GetIsDisconnected(), - Color = pi.GetPlayerColor() - }); - } - else - { - // player was here before, we have an old playerInfo to compare against - var oldPlayerInfo = oldPlayerInfos[playerName]; - if (!oldPlayerInfo.GetIsDead() && pi.GetIsDead()) // player just died PlayerChanged?.Invoke(this, new PlayerChangedEventArgs { - Action = PlayerAction.Died, + Action = PlayerAction.Joined, Name = playerName, IsDead = pi.GetIsDead(), Disconnected = pi.GetIsDisconnected(), Color = pi.GetPlayerColor() }); + } + else + { + // player was here before, we have an old playerInfo to compare against + var oldPlayerInfo = oldPlayerInfos[playerName]; + if (!oldPlayerInfo.GetIsDead() && pi.GetIsDead()) // player just died + PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + { + Action = PlayerAction.Died, + Name = playerName, + IsDead = pi.GetIsDead(), + Disconnected = pi.GetIsDisconnected(), + Color = pi.GetPlayerColor() + }); + + if (oldPlayerInfo.ColorId != pi.ColorId) + PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + { + Action = PlayerAction.ChangedColor, + Name = playerName, + IsDead = pi.GetIsDead(), + Disconnected = pi.GetIsDisconnected(), + Color = pi.GetPlayerColor() + }); + + if (!oldPlayerInfo.GetIsDisconnected() && pi.GetIsDisconnected()) + PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + { + Action = PlayerAction.Disconnected, + Name = playerName, + IsDead = pi.GetIsDead(), + Disconnected = pi.GetIsDisconnected(), + Color = pi.GetPlayerColor() + }); + } + } - if (oldPlayerInfo.ColorId != pi.ColorId) + foreach (var kvp in oldPlayerInfos) + { + var pi = kvp.Value; + var playerName = kvp.Key; + if (!newPlayerInfos.ContainsKey(playerName)) // player was here before, isn't now, so they left PlayerChanged?.Invoke(this, new PlayerChangedEventArgs { - Action = PlayerAction.ChangedColor, + Action = PlayerAction.Left, Name = playerName, IsDead = pi.GetIsDead(), Disconnected = pi.GetIsDisconnected(), Color = pi.GetPlayerColor() }); + } - if (!oldPlayerInfo.GetIsDisconnected() && pi.GetIsDisconnected()) - PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + oldPlayerInfos.Clear(); + + var emitAll = false; + if (shouldForceUpdatePlayers) + { + shouldForceUpdatePlayers = false; + emitAll = true; + } + + + if (state != cachedOldState && (state == GameState.DISCUSSION || state == GameState.TASKS) + ) // game started, or at least we're still in game + { + CachedPlayerInfos.Clear(); + foreach (var kvp in newPlayerInfos + ) // do this instead of assignment so they don't point to the same object + { + var pi = kvp.Value; + string playerName = pi.GetPlayerName(); + CachedPlayerInfos[playerName] = new ImmutablePlayer() { - Action = PlayerAction.Disconnected, Name = playerName, + IsImpostor = false + }; + } + } + + foreach (var kvp in newPlayerInfos + ) // do this instead of assignment so they don't point to the same object + { + var pi = kvp.Value; + oldPlayerInfos[kvp.Key] = pi; + if (emitAll) + PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + { + Action = PlayerAction.ForceUpdated, + Name = kvp.Key, IsDead = pi.GetIsDead(), Disconnected = pi.GetIsDisconnected(), Color = pi.GetPlayerColor() }); } - } - foreach (var kvp in oldPlayerInfos) - { - var pi = kvp.Value; - var playerName = kvp.Key; - if (!newPlayerInfos.ContainsKey(playerName)) // player was here before, isn't now, so they left - PlayerChanged?.Invoke(this, new PlayerChangedEventArgs - { - Action = PlayerAction.Left, - Name = playerName, - IsDead = pi.GetIsDead(), - Disconnected = pi.GetIsDisconnected(), - Color = pi.GetPlayerColor() - }); - } + var chatBubblesPtr = ProcessMemory.getInstance().Read(GameAssemblyPtr, + CurrentOffsets.HudManagerOffset, 0x5C, 0, + 0x28, 0xC, 0x14); - oldPlayerInfos.Clear(); + var poolSize = 20; // = ProcessMemory.Read(GameAssemblyPtr, 0xD0B25C, 0x5C, 0, 0x28, 0xC, 0xC) - var emitAll = false; - if (shouldForceUpdatePlayers) - { - shouldForceUpdatePlayers = false; - emitAll = true; - } + var numChatBubbles = ProcessMemory.getInstance().Read(chatBubblesPtr, 0xC); + var chatBubsVersion = ProcessMemory.getInstance().Read(chatBubblesPtr, 0x10); + var chatBubblesAddr = ProcessMemory.getInstance().Read(chatBubblesPtr, 0x8) + 0x10; + var chatBubblePtrs = ProcessMemory.getInstance().ReadArray(chatBubblesAddr, numChatBubbles); + var newMsgs = 0; - if (state != cachedOldState && (state == GameState.DISCUSSION || state == GameState.TASKS)) // game started, or at least we're still in game - { - CachedPlayerInfos.Clear(); - foreach (var kvp in newPlayerInfos) // do this instead of assignment so they don't point to the same object + if (chatBubsVersion > prevChatBubsVersion) // new message has been sent { - var pi = kvp.Value; - string playerName = pi.GetPlayerName(); - CachedPlayerInfos[playerName] = new ImmutablePlayer() + if (chatBubsVersion > poolSize) // increments are twofold (push to and pop from pool) { - Name = playerName, - IsImpostor = false - }; - } - } - - foreach (var kvp in newPlayerInfos - ) // do this instead of assignment so they don't point to the same object - { - var pi = kvp.Value; - oldPlayerInfos[kvp.Key] = pi; - if (emitAll) - PlayerChanged?.Invoke(this, new PlayerChangedEventArgs + if (prevChatBubsVersion > poolSize) + newMsgs = (chatBubsVersion - prevChatBubsVersion) >> 1; + else + newMsgs = poolSize - prevChatBubsVersion + ((chatBubsVersion - poolSize) >> 1); + } + else // single increments { - Action = PlayerAction.ForceUpdated, - Name = kvp.Key, - IsDead = pi.GetIsDead(), - Disconnected = pi.GetIsDisconnected(), - Color = pi.GetPlayerColor() - }); - } - - var chatBubblesPtr = ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.HudManagerOffset, 0x5C, 0, - 0x28, 0xC, 0x14); - - var poolSize = 20; // = ProcessMemory.Read(GameAssemblyPtr, 0xD0B25C, 0x5C, 0, 0x28, 0xC, 0xC) - - var numChatBubbles = ProcessMemory.getInstance().Read(chatBubblesPtr, 0xC); - var chatBubsVersion = ProcessMemory.getInstance().Read(chatBubblesPtr, 0x10); - var chatBubblesAddr = ProcessMemory.getInstance().Read(chatBubblesPtr, 0x8) + 0x10; - var chatBubblePtrs = ProcessMemory.getInstance().ReadArray(chatBubblesAddr, numChatBubbles); - - var newMsgs = 0; - - if (chatBubsVersion > prevChatBubsVersion) // new message has been sent - { - if (chatBubsVersion > poolSize) // increments are twofold (push to and pop from pool) - { - if (prevChatBubsVersion > poolSize) - newMsgs = (chatBubsVersion - prevChatBubsVersion) >> 1; - else - newMsgs = poolSize - prevChatBubsVersion + ((chatBubsVersion - poolSize) >> 1); + newMsgs = chatBubsVersion - prevChatBubsVersion; + } } - else // single increments + else if (chatBubsVersion < prevChatBubsVersion) // reset { - newMsgs = chatBubsVersion - prevChatBubsVersion; + if (chatBubsVersion > poolSize) // increments are twofold (push to and pop from pool) + newMsgs = poolSize + ((chatBubsVersion - poolSize) >> 1); + else // single increments + newMsgs = chatBubsVersion; } - } - else if (chatBubsVersion < prevChatBubsVersion) // reset - { - if (chatBubsVersion > poolSize) // increments are twofold (push to and pop from pool) - newMsgs = poolSize + ((chatBubsVersion - poolSize) >> 1); - else // single increments - newMsgs = chatBubsVersion; - } - prevChatBubsVersion = chatBubsVersion; + prevChatBubsVersion = chatBubsVersion; - for (var i = numChatBubbles - newMsgs; i < numChatBubbles; i++) - { - var msgText = ProcessMemory.getInstance().ReadString(ProcessMemory.getInstance().Read(chatBubblePtrs[i], 0x20, 0x28)); - if (msgText.Length == 0) continue; - var msgSender = ProcessMemory.getInstance().ReadString(ProcessMemory.getInstance().Read(chatBubblePtrs[i], 0x1C, 0x28)); - var oldPlayerInfo = oldPlayerInfos[msgSender]; - ChatMessageAdded?.Invoke(this, new ChatMessageEventArgs + for (var i = numChatBubbles - newMsgs; i < numChatBubbles; i++) { - Sender = msgSender, - Message = msgText, - Color = oldPlayerInfo.GetPlayerColor() - }); - } + var msgText = ProcessMemory.getInstance() + .ReadString(ProcessMemory.getInstance().Read(chatBubblePtrs[i], 0x20, 0x28)); + if (msgText.Length == 0) continue; + var msgSender = ProcessMemory.getInstance() + .ReadString(ProcessMemory.getInstance().Read(chatBubblePtrs[i], 0x1C, 0x28)); + var oldPlayerInfo = oldPlayerInfos[msgSender]; + ChatMessageAdded?.Invoke(this, new ChatMessageEventArgs + { + Sender = msgSender, + Message = msgText, + Color = oldPlayerInfo.GetPlayerColor() + }); + } - if (shouldReadLobby) - { - var gameCode = ProcessMemory.getInstance().ReadString(ProcessMemory.getInstance().Read(GameAssemblyPtr, - CurrentOffsets.GameStartManagerOffset, 0x5c, 0, 0x20, 0x28)); - string[] split; - if (gameCode != null && gameCode.Length > 0 && (split = gameCode.Split('\n')).Length == 2) + if (shouldReadLobby) { - PlayRegion region = (PlayRegion)((4 - (ProcessMemory.getInstance().Read(GameAssemblyPtr, CurrentOffsets.ServerManagerOffset, 0x5c, 0, 0x10, 0x8, 0x8) & 0b11)) % 3); // do NOT ask - - this.latestLobbyEventArgs = new LobbyEventArgs() + var gameCode = ProcessMemory.getInstance().ReadString(ProcessMemory.getInstance().Read( + GameAssemblyPtr, + CurrentOffsets.GameStartManagerOffset, 0x5c, 0, 0x20, 0x28)); + string[] split; + if (gameCode != null && gameCode.Length > 0 && (split = gameCode.Split('\n')).Length == 2) { - LobbyCode = split[1], - Region = region - }; - shouldReadLobby = false; - shouldTransmitLobby = true; // since this is probably new info + PlayRegion region = (PlayRegion) ((4 - (ProcessMemory.getInstance() + .Read(GameAssemblyPtr, CurrentOffsets.ServerManagerOffset, 0x5c, 0, 0x10, 0x8, + 0x8) & 0b11)) % 3); // do NOT ask + + this.latestLobbyEventArgs = new LobbyEventArgs() + { + LobbyCode = split[1], + Region = region + }; + shouldReadLobby = false; + shouldTransmitLobby = true; // since this is probably new info + } } - } - if (shouldTransmitLobby) - { - if (this.latestLobbyEventArgs != null) + if (shouldTransmitLobby) { - JoinedLobby?.Invoke(this, this.latestLobbyEventArgs); + if (this.latestLobbyEventArgs != null) + { + JoinedLobby?.Invoke(this, this.latestLobbyEventArgs); + } + + shouldTransmitLobby = false; } - shouldTransmitLobby = false; - } - Thread.Sleep(250); + Thread.Sleep(250); + + } + catch (Exception e) + { + Settings.conInterface.WriteModuleTextColored("ERROR", Color.Red, e.Message); + Console.WriteLine(e); + } } }