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: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491:
| using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq;
namespace NPx { public static class StatFileHandler { public static void Register() { RPCStorageWriteUserFileMessage.AddFileHandler("stat", HandleIW4Stats); }
private static int HandleIW4Stats(byte[] data, string fileName, out string backupName) { var newData = new StructuredData("data/playerdata.xml"); newData.SetData(data);
backupName = null;
if (File.Exists(fileName)) { var oldData = new StructuredData("data/playerdata.xml");
oldData.SetData(File.ReadAllBytes(fileName));
var oldExperience = oldData.Get("experience").Get<int>(); var newExperience = newData.Get("experience").Get<int>();
var difference = newExperience - oldExperience;
if (difference > 200000) { }
var oldPrestige = oldData.Get("prestige").Get<int>(); var newPrestige = newData.Get("prestige").Get<int>();
difference = newPrestige - oldPrestige;
if (newPrestige > 10) { return 1; }
backupName = string.Format("{2}/iw4_{0}_{1}.stat", newPrestige, DateTime.UtcNow.ToString("yyyyMMdd"), Path.GetDirectoryName(fileName)); }
var has10th = newData.Get("iconUnlocked.cardicon_prestige10_02").Get<bool>();
if (has10th) { return 1; }
return 0; } }
public class StructuredDataValue { private object _object;
public StructuredDataValue(object value) { _object = value; }
public T Get<T>() { return (T)Convert.ChangeType(_object, typeof(T)); } }
public class StructuredData { private int _version; private Dictionary<string, Dictionary<string, StructItemDef>> _structs; private Dictionary<string, Dictionary<string, int>> _enums; private Dictionary<string, StructEnumArray> _enumArrays; private byte[] _data;
public bool IW5 { get; set; }
private class StructuredDataElement { public string Type { get; set; } public int Offset { get; set; }
public int Length { get; set; } public string ChildType { get; set; } public int ChildSize { get; set; } public int Bit { get; set; }
public void ResetData() { Length = 0; ChildType = null; ChildSize = 0; Bit = 0; } }
public StructuredData(string definitionFile) { LoadDefinition(definitionFile); }
public void SetData(byte[] data) { _data = data;
}
public StructuredDataValue Get(string path) { var elements = path.Split('.'); var element = Trace(elements);
return ReadItem(element); }
private StructuredDataValue ReadItem(StructuredDataElement element) { var offset = element.Offset + ((IW5) ? 4 : 4); object item = null;
switch (GetActualType(element.Type)) { case "int": item = ReadInt32(offset); break; case "short": item = ReadInt16(offset); break; case "byte": item = ReadInt8(offset); break; case "float": item = ReadFloat(offset); break; case "enum": var value = ReadInt16(offset);
foreach (var enumItem in _enums[element.Type]) { if (enumItem.Value == value) { item = enumItem.Key; break; } }
break; case "string": item = ReadString(offset, element.Length); break; case "bool": var bvalue = ReadInt8(offset);
if (element.Bit > 0) { bvalue >>= element.Bit; bvalue &= 1; }
item = (bvalue == 1) ? true : false; break; }
return new StructuredDataValue(item); }
private int ReadInt32(int offset) { return BitConverter.ToInt32(_data, offset); }
private short ReadInt16(int offset) { return BitConverter.ToInt16(_data, offset); }
private byte ReadInt8(int offset) { return _data[offset]; }
private float ReadFloat(int offset) { return BitConverter.ToSingle(_data, offset); }
private string ReadString(int offset, int length) { return Encoding.ASCII.GetString(_data, offset, length).Split('\0')[0]; }
private StructuredDataElement Trace(string[] path) { var element = new StructuredDataElement(); element.Type = "playerdata"; element.Offset = 0;
foreach (var name in path) { switch (GetActualType(element.Type)) { case "struct": element = GetStructChild(element, name); break; case "indexedarr": element = GetArrayIndex(element, name); break; case "enumarr": element = GetArrayEnum(element, name); break; } }
return element; }
private StructuredDataElement GetArrayEnum(StructuredDataElement item, string name) { var found = false; var enumArray = _enumArrays[item.Type]; var enumeration = _enums[enumArray.Enum];
foreach (var enumItem in enumeration) { if (enumItem.Key == name) { var index = enumItem.Value;
item.ResetData(); item.Type = enumArray.Type;
if (item.Type == "bool") { item.Offset += (index / 8); item.Bit = (index % 8); } else { item.Offset += (index * enumArray.Size); }
found = true; } }
if (!found) { throw new KeyNotFoundException("Could not find any such key in the specified enum."); }
return item; }
private StructuredDataElement GetArrayIndex(StructuredDataElement item, string name) { var index = int.Parse(name);
if (index >= item.Length) { throw new IndexOutOfRangeException("Index is outside of the indexedarr's bounds."); }
var childSize = item.ChildSize; item.Type = item.ChildType;
item.ResetData();
if (item.Type == "bool") { item.Offset += (index / 8); item.Bit = (index % 8); } else { item.Offset += (index * childSize); }
return item; }
private StructuredDataElement GetStructChild(StructuredDataElement item, string name) { var found = false; var structure = _structs[item.Type];
foreach (var element in structure) { if (element.Key == name) { item.Type = element.Value.Type; item.Offset += element.Value.Offset;
item.ResetData();
if (element.Value.Length > 0) { item.Length = element.Value.Length; }
if (element.Value.ChildType != null) { item.ChildType = element.Value.ChildType; item.ChildSize = element.Value.ChildSize; }
found = true; } }
if (!found) { throw new KeyNotFoundException("Could not find any such key in the specified struct."); }
return item; }
private string GetActualType(string type) { if (_structs.ContainsKey(type)) { return "struct"; } else if (_enumArrays.ContainsKey(type)) { return "enumarr"; } else if (_enums.ContainsKey(type)) { return "enum"; } else { return type; } }
private void LoadDefinition(string filename) { var document = XDocument.Load(filename);
_version = int.Parse(document.Root.Attribute("version").Value); _enums = LoadEnums(document); _structs = LoadStructs(document); _enumArrays = LoadEnumArrays(document); }
private class StructItemDef { public string Type { get; set; } public string Name { get; set; } public int Offset { get; set; } public int Length { get; set; } public string ChildType { get; set; } public int ChildSize { get; set; } }
private class StructEnumArray { public string Enum { get; set; } public string Type { get; set; } public int Size { get; set; } }
private Dictionary<string, Dictionary<string, StructItemDef>> LoadStructs(XDocument document) { var structs = new Dictionary<string, Dictionary<string, StructItemDef>>();
var documentStructs = from structure in document.Descendants("structs").First().Descendants("struct") select new { Name = structure.Attribute("name").Value, Items = from item in structure.Elements() select new { Type = item.Name.LocalName, Name = item.Attribute("name").Value, Offset = int.Parse(item.Attribute("offset").Value), Node = item } };
foreach (var structure in documentStructs) { var structureItems = new Dictionary<string, StructItemDef>();
foreach (var item in structure.Items) { var structItem = new StructItemDef() { Name = item.Name, Offset = item.Offset, Type = item.Type };
if (item.Type == "string" || item.Type == "indexedarr") { structItem.Length = int.Parse(item.Node.Attribute("length").Value); }
var descendants = item.Node.Descendants();
if (descendants.Count() > 0) { var descendant = descendants.First(); structItem.ChildType = descendant.Name.LocalName; structItem.ChildSize = int.Parse(descendant.Attribute("size").Value); }
structureItems.Add(structItem.Name, structItem); }
structs.Add(structure.Name, structureItems); }
return structs; }
private Dictionary<string, Dictionary<string, int>> LoadEnums(XDocument document) { var enums = new Dictionary<string, Dictionary<string, int>>(); var documentEnums = from enumeration in document.Descendants("enums").First().Descendants("enum") select new { Name = enumeration.Attribute("name").Value, Items = from item in enumeration.Descendants("index") select new { Name = item.Attribute("name").Value, Index = int.Parse(item.Attribute("index").Value) } };
foreach (var enumeration in documentEnums) { var enumerationItems = new Dictionary<string, int>();
foreach (var item in enumeration.Items) { enumerationItems.Add(item.Name, item.Index); }
enums.Add(enumeration.Name, enumerationItems); }
return enums; }
private Dictionary<string, StructEnumArray> LoadEnumArrays(XDocument document) { var enumArrays = new Dictionary<string, StructEnumArray>();
var documentEnumArrays = from enumArray in document.Descendants("enumarrays").First().Descendants("enumarray") select new { Name = enumArray.Attribute("name").Value, Enum = enumArray.Attribute("enum").Value, Type = enumArray.Descendants().First().Name.LocalName, Size = int.Parse(enumArray.Descendants().First().Attribute("size").Value) };
foreach (var enumArray in documentEnumArrays) { enumArrays.Add(enumArray.Name, new StructEnumArray() { Enum = enumArray.Enum, Size = enumArray.Size, Type = enumArray.Type }); }
return enumArrays; } } } |