private void ReadFromMemory(object state) { lock (_memoryTimerLock) { var timer = state as Timer; if (timer != _memoryTimer || _memoryTimer == null) { return; } var spideyData = MemoryScanner.ReadSpideyData(); var levelData = MemoryScanner.ReadLevelData(); var message = SpideyUdpMessage.CreateSpidermanMessage(_myInfo.Number, spideyData, levelData); foreach (var udpClient in udpWebSwing) { udpClient.Send(message, message.Length); } var spideyLevel = SpideyLevels.GetSpideyLevel(levelData); var location = spideyLevel.Name.TrimEnd(); _onLocationUpdate.Report(new ConnectedPlayerInformation(_myInfo.Number, location)); _udpBase.MyLastLocation = location; } }
// TODO - looks like 0xC0 is not so straightforward - not just an array count // e.g. MJ = FF 04, Rat = C0 81?? public static void WriteSpideyData(byte[] spideyData, SpideyLevel playerSpideyLevel, int playerOffset, int playerCount) { var dosBoxProcess = Interlocked.Read(ref _dosBoxProcess); var enemyCountAddress = Interlocked.Read(ref _enemyCountAddress); var spideyAddress = Interlocked.Read(ref _spideyAddress); int bytesWritten; var mySpideyLevel = SpideyLevels.GetSpideyLevel(ReadLevelData(dosBoxProcess)); // TODO - fix teleporting enemy issue - prolly to do with how they get stored in array if (enemyCountAddress != 0 && spideyAddress != 0) { var desiredEnemyCount = Convert.ToByte(_highestEnemyCount + playerCount); var enemyCountBuffer = new byte[ENEMY_COUNT_DATA_SIZE]; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(enemyCountAddress), enemyCountBuffer, ENEMY_COUNT_DATA_SIZE, out int bytesRead); var enemyCountNeedsUpdate = false; if (enemyCountBuffer[0] < desiredEnemyCount) { enemyCountNeedsUpdate = true; // Null out any extra enemy data that shouldn't be there var invalidEnemies = _highestEnemyCount - mySpideyLevel.EnemyCount; var enemyData = new byte[ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE]; //enemyData[0] = 0xC0; Buffer.BlockCopy(DEAD_ENEMY_PLACEHOLDER, 0, enemyData, ENEMY_HEADER_SIZE, SPIDEY_DATA_SIZE); while (invalidEnemies > 0) { // TODO - Try copy the first enemy to other spots as well so it loads the right values? var enemyIndex = _highestEnemyCount - invalidEnemies - 1; var enemyMemoryOffset = (ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE) * enemyIndex; //WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset), new byte[] { 0xC0 }, 1, out bytesWritten); //WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 1), new byte[] { 0x01 }, 1, out bytesWritten); var singleByteBuffer = new byte[1]; // Just the essential enemy bits // Blank sprite var lSpriteAddress = spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 8; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lSpriteAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] < 0x50 || singleByteBuffer[0] > 0x5F) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lSpriteAddress), new byte[] { 0x5F }, 1, out bytesWritten); } // To avoid corruption var lCorruptionOneAddress = spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 31; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionOneAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] == 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionOneAddress), new byte[] { 0x01 }, 1, out bytesWritten); } // To avoid corruption var lCorruptionTwoAddress = spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 34; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionTwoAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] == 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionTwoAddress), new byte[] { 0x01 }, 1, out bytesWritten); } // Enemy health var lEnemyHealthAddress = spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 41; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lEnemyHealthAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] != 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lEnemyHealthAddress), new byte[] { 0x00 }, 1, out bytesWritten); } /* * //enemyData[1] = Convert.ToByte(enemyIndex); * if (enemyIndex == 3) * { * // TODO - tidy up, need to skip bytes 3 and 4 as they contain web swing data * // TODO - also seems to cause instant win when going to end screen, maybe just need to send bare minimum? * //WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset), enemyData, 3, out bytesWritten); * //WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 5), enemyData.Skip(5).ToArray(), 45, out bytesWritten); * WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 8), new byte[] { 0x5F }, 1, out bytesWritten); * WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 31), new byte[] { 0x01 }, 1, out bytesWritten); * WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset + 34), new byte[] { 0x01 }, 1, out bytesWritten); * } * else * { * WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + enemyMemoryOffset), enemyData, ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE, out bytesWritten); * }*/ --invalidEnemies; } } var playerIndex = _highestEnemyCount + playerOffset - 1; var playerMemoryOffset = (ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE) * playerIndex; var playerData = new byte[ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE]; //playerData[0] = 0xC0; //playerData[1] = Convert.ToByte(playerIndex); if (playerSpideyLevel.Number == mySpideyLevel.Number) { Buffer.BlockCopy(spideyData, 0, playerData, ENEMY_HEADER_SIZE, SPIDEY_DATA_SIZE); //WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset), playerData, ENEMY_HEADER_SIZE + SPIDEY_DATA_SIZE, out bytesWritten); // Cutting out half the data seems to fix graphical glitching issues and disables interaction with other player's game WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset), playerData, ENEMY_HEADER_SIZE + (SPIDEY_DATA_SIZE / 2), out bytesWritten); } else { var singleByteBuffer = new byte[1]; // Just the essential enemy bits // Blank sprite var lSpriteAddress = spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset + 8; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lSpriteAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] < 0x50 || singleByteBuffer[0] > 0x5F) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lSpriteAddress), new byte[] { 0x5F }, 1, out bytesWritten); } // To avoid corruption var lCorruptionOneAddress = spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset + 31; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionOneAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] == 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionOneAddress), new byte[] { 0x01 }, 1, out bytesWritten); } // To avoid corruption var lCorruptionTwoAddress = spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset + 34; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionTwoAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] == 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lCorruptionTwoAddress), new byte[] { 0x01 }, 1, out bytesWritten); } // Enemy health var lEnemyHealthAddress = spideyAddress + SPIDEY_DATA_SIZE + playerMemoryOffset + 41; ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lEnemyHealthAddress), singleByteBuffer, 1, out bytesRead); if (singleByteBuffer[0] != 0x00) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(lEnemyHealthAddress), new byte[] { 0x00 }, 1, out bytesWritten); } } if (enemyCountNeedsUpdate) { WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(enemyCountAddress), new byte[] { desiredEnemyCount }, ENEMY_COUNT_DATA_SIZE, out bytesWritten); } } /* * // If first time doing this, needs to be done slowly (one by one + write enemy data first) * if (enemyCountAddress != 0) * { * var desiredEnemyCount = Convert.ToByte(_highestEnemyCount + playerCount); * var enemyCountBuffer = new byte[ENEMY_COUNT_DATA_SIZE]; * ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(enemyCountAddress), enemyCountBuffer, ENEMY_COUNT_DATA_SIZE, out int bytesRead); * while((enemyCountBuffer[0] < desiredEnemyCount) && (bytesRead == ENEMY_COUNT_DATA_SIZE)) * { * // TODO - detect level change while doing this? * WriteProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(enemyCountAddress), new byte[] { Convert.ToByte(enemyCountBuffer[0] + 1) }, ENEMY_COUNT_DATA_SIZE, out bytesWritten); * ReadProcessMemory(new IntPtr(dosBoxProcess), new IntPtr(enemyCountAddress), enemyCountBuffer, ENEMY_COUNT_DATA_SIZE, out bytesRead); * Thread.Sleep(5000); * } * }*/ }