public static void UpdateConf(ConfBase conf, Record record) { var items = PatchManager.ByRecord(record); var set = items.Keys.ToHashSet(); foreach (var item in conf.allConfBase) { // Narrowing to subtype var it = (ConfBaseItem)Il2CppHelper.Il2CppObjectPtrToIl2CppObjectByType(item.Pointer, record.ItemType); if (!items.TryGetValue(it.id, out var v)) { continue; } set.Remove(it.id); v.ApplyTo(it); } foreach (var item in set.Select(id => items[id])) { conf.allConfBase.Add(item.Construct()); } }
public static void DumpConf(ConfBase conf, Record record) { // Logger.Debug($"{conf.confName}, {record}"); var confPath = Path.Combine(Env.BaseConfPath, $"{conf.confName}.json"); using (var writer = new JsonTextWriter(new StreamWriter(confPath)) { Indentation = 2, Formatting = Formatting.Indented }) { writer.WriteStartArray(); foreach (var item in conf.allConfBase) { if (item == null) { // TODO: Find out why item could be null continue; } // Narrowing to subtype var it = Il2CppHelper.Il2CppObjectPtrToIl2CppObjectByType(item.Pointer, record.ItemType); writer.WriteStartObject(); // `id` is a special case FieldsInfo missed writer.WritePropertyName("id"); writer.WriteValue(item.id); foreach (var p in record.FieldsInfo) { var field = p.Item1; writer.WritePropertyName(field.Name); // Assume all fields are serialized by writer writer.WriteValue(field.GetValue(it)); } writer.WriteEndObject(); } writer.WriteEndArray(); } }
public Value(Type type, JValue value) { IsNone = value == null; @bool = default; @byte = default; @sbyte = default; @short = default; @ushort = default; @int = default; @uint = default; @long = default; @ulong = default; @char = default; @double = default; @float = default; @string = IL2CPP.ManagedStringToIl2Cpp(""); if (type == typeof(string)) { tag = ValueType.String; if (value == null) { return; } // FIXME: // The purpose of intern is to prevent GC from freeing our string to avoid UAF. // But intern will run into some performance problems sometimes. // Maybe making a reference circle is another solution. @string = Il2CppHelper.il2cpp_string_intern( IL2CPP.ManagedStringToIl2Cpp(value.Value <string>())); } else if (type == typeof(bool)) { tag = ValueType.Boolean; if (value == null) { return; } @bool = value.Value <bool>(); } else if (type == typeof(byte)) { tag = ValueType.Byte; if (value == null) { return; } @byte = value.Value <byte>(); } else if (type == typeof(sbyte)) { tag = ValueType.SByte; if (value == null) { return; } @sbyte = value.Value <sbyte>(); } else if (type == typeof(short)) { tag = ValueType.Int16; if (value == null) { return; } @short = value.Value <short>(); } else if (type == typeof(ushort)) { tag = ValueType.UInt16; if (value == null) { return; } @ushort = value.Value <ushort>(); } else if (type == typeof(int)) { tag = ValueType.Int32; if (value == null) { return; } @int = value.Value <int>(); } else if (type == typeof(uint)) { tag = ValueType.UInt32; if (value == null) { return; } @uint = value.Value <uint>(); } else if (type == typeof(long)) { tag = ValueType.Int64; if (value == null) { return; } @long = value.Value <long>(); } else if (type == typeof(ulong)) { tag = ValueType.UInt64; if (value == null) { return; } @ulong = value.Value <ulong>(); } else if (type == typeof(char)) { tag = ValueType.Char; if (value == null) { return; } @char = value.Value <char>(); } else if (type == typeof(double)) { tag = ValueType.Double; if (value == null) { return; } @double = value.Value <double>(); } else if (type == typeof(float)) { tag = ValueType.Single; if (value == null) { return; } @float = value.Value <float>(); } else { throw new NotSupportedException($"Type {type} is not supported"); } }
public static void DumpConf(ConfBase conf, Record record) { // Logger.Debug($"{conf.confName}, {record}"); var confPath = Path.Combine(Env.BaseConfPath, $"{conf.confName}.json"); using (var writer = new JsonTextWriter(new StreamWriter(confPath)) { Indentation = 2, Formatting = Formatting.Indented }) { writer.WriteStartArray(); foreach (var item in conf.allConfBase) { if (item == null) { // TODO: Find out why item could be null continue; } // Narrowing to subtype var it = Il2CppHelper.Il2CppObjectPtrToIl2CppObjectByType(item.Pointer, record.ItemType); writer.WriteStartObject(); // `id` is a special case FieldsInfo missed writer.WritePropertyName("id"); writer.WriteValue(item.id); foreach (var p in record.FieldsInfo) { var field = p.Item1; writer.WritePropertyName(field.Name); var v = field.GetValue(it); // FIXME: It's a temporarily way and should be fixed later if (field.PropertyType == typeof(Il2CppStructArray <int>)) { writer.WriteStartArray(); foreach (var n in (Il2CppStructArray <int>)v) { writer.WriteValue(n); } writer.WriteEndArray(); } else if (field.PropertyType == typeof(Il2CppStringArray)) { writer.WriteStartArray(); foreach (var str in (Il2CppStringArray)v) { writer.WriteValue(str); } writer.WriteEndArray(); } else if (field.PropertyType == typeof(Il2CppReferenceArray <Il2CppStructArray <float> >)) { writer.WriteStartArray(); foreach (var a in (Il2CppReferenceArray <Il2CppStructArray <float> >)v) { writer.WriteStartArray(); foreach (var f in a) { writer.WriteValue(f); } writer.WriteEndArray(); } writer.WriteEndArray(); } else if (field.PropertyType == typeof(Il2CppReferenceArray <Il2CppStructArray <int> >)) { writer.WriteStartArray(); foreach (var ia in (Il2CppReferenceArray <Il2CppStructArray <int> >)v) { writer.WriteStartArray(); foreach (var i in ia) { writer.WriteValue(i); } writer.WriteEndArray(); } writer.WriteEndArray(); } else if (field.PropertyType == typeof(Il2CppReferenceArray <Il2CppStringArray>)) { writer.WriteStartArray(); foreach (var sa in (Il2CppReferenceArray <Il2CppStringArray>)v) { writer.WriteStartArray(); foreach (var s in sa) { writer.WriteValue(s); } writer.WriteEndArray(); } writer.WriteEndArray(); } else { writer.WriteValue(v); } } writer.WriteEndObject(); } writer.WriteEndArray(); } }