public static unsafe Version getBTD6Version(string btd6Dir) { // GlobalGameManagers contains version string. // Can move by a few bytes in updates, instead scan for it. Version v; byte[] file = File.ReadAllBytes(btd6Dir + "\\BloonsTD6_Data\\globalgamemanagers"); Int64 VersionStructOffset = 0; fixed(byte *pFile = file) { // The signature is only a few bytes away, the next period should always be the peroid in the version (12.2) VersionStructOffset = MemoryUtils.AOBScan(pFile, file.Length, BTD6VerisonInfoSignature); if (VersionStructOffset == 0) { throw new Exception("Error, failed to find BTD6's version"); } // Now we scan for the peroid (12.2) the . for (Int64 i = VersionStructOffset + BTD6VerisonInfoSignature.Length; i < file.Length; i++) { if (pFile[i] == 0x2E) { byte[] versionBytes = MemoryUtils.BytesBetweenNull(pFile, file.Length, i); int periodPos = 0; for (int k = 0; k < versionBytes.Length; k++) { if (versionBytes[k] == 0x2e) { periodPos = k; break; } } byte[] majorVersionBytes = new byte[periodPos]; byte[] minorVersionBytes = new byte[versionBytes.Length - (periodPos + 1)]; Buffer.BlockCopy(versionBytes, 0, majorVersionBytes, 0, periodPos); Buffer.BlockCopy(versionBytes, periodPos + 1, minorVersionBytes, 0, versionBytes.Length - (periodPos + 1)); string majorVersionString = Encoding.UTF8.GetString(majorVersionBytes); string minorVersionString = Encoding.UTF8.GetString(minorVersionBytes); v = new Version(int.Parse(majorVersionString), int.Parse(minorVersionString)); return(v); } } } throw new Exception("Error, unable to get BTD6 Version"); }