Skip to content

Commit c52ef39

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents ba01e6e + aac1bb1 commit c52ef39

File tree

15 files changed

+182
-40
lines changed

15 files changed

+182
-40
lines changed

GeometryDashAPI.Tests/TypeDescriptorTests.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
using System;
22
using System.Linq;
3+
using System.Text;
4+
using FluentAssertions;
5+
using GeometryDashAPI.Levels.Enums;
6+
using GeometryDashAPI.Levels.GameObjects.Default;
7+
using GeometryDashAPI.Levels.GameObjects.Specific;
38
using GeometryDashAPI.Serialization;
49
using NUnit.Framework;
510
using TestObjects;
@@ -60,4 +65,91 @@ public void ShouldParseEnumItself()
6065

6166
Assert.AreEqual(SimpleEnum.X, instance.Value);
6267
}
68+
69+
[Test]
70+
public void ProtectedVirtualFieldGet()
71+
{
72+
var descriptor = new TypeDescriptor<BaseBlock>();
73+
74+
var builder = new StringBuilder();
75+
descriptor.CopyTo(new BaseBlock(1)
76+
{
77+
ZLayer = Layer.B4
78+
}, builder);
79+
80+
builder.ToString().Should().Be("1,1,2,0,3,0,24,-3");
81+
}
82+
83+
[Test]
84+
public void ProtectedVirtualFieldSet()
85+
{
86+
var input = "1,1,2,0,3,0,24,-3";
87+
var descriptor = new TypeDescriptor<BaseBlock>();
88+
89+
var block = descriptor.Create(input.AsSpan());
90+
91+
block.ZLayer.Should().Be(Layer.B4);
92+
}
93+
94+
[Test]
95+
public void OverrideVirtualFieldGet_Default()
96+
{
97+
var descriptor = new TypeDescriptor<JumpPlate>();
98+
99+
var builder = new StringBuilder();
100+
descriptor.CopyTo(new JumpPlate(JumpPlateId.Red)
101+
{
102+
ZLayer = Layer.B1
103+
}, builder);
104+
105+
builder.ToString().Should().Be("1,1332,2,0,3,0");
106+
}
107+
108+
[Test]
109+
public void OverrideVirtualFieldGet_Specific()
110+
{
111+
var descriptor = new TypeDescriptor<JumpPlate>();
112+
113+
var builder = new StringBuilder();
114+
descriptor.CopyTo(new JumpPlate(JumpPlateId.Red)
115+
{
116+
ZLayer = Layer.B4
117+
}, builder);
118+
119+
builder.ToString().Should().Be("1,1332,2,0,3,0,24,-3");
120+
}
121+
122+
[Test]
123+
public void OverrideVirtualFieldSet_Default()
124+
{
125+
var input = "1,1332,2,0,3,0";
126+
var descriptor = new TypeDescriptor<JumpPlate>();
127+
128+
var block = descriptor.Create(input.AsSpan());
129+
130+
block.ZLayer.Should().Be(Layer.B1);
131+
}
132+
133+
[Test]
134+
public void OverrideVirtualFieldSet_Specific()
135+
{
136+
var input = "1,1332,2,0,3,0,24,-3";
137+
var descriptor = new TypeDescriptor<JumpPlate>();
138+
139+
var block = descriptor.Create(input.AsSpan());
140+
141+
block.ZLayer.Should().Be(Layer.B4);
142+
}
143+
144+
[Test]
145+
public void PrivateFieldFromInheritedClass()
146+
{
147+
var input = "1,10,2,20,3,333";
148+
var descriptor = new TypeDescriptor<InheritField>();
149+
150+
var actual = descriptor.Create(input.AsSpan());
151+
152+
actual.X.Should().Be(10);
153+
actual.Y.Should().Be(20);
154+
}
63155
}

GeometryDashAPI/Attributes/GamePropertyAttribute.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ public class GamePropertyAttribute : Attribute
1010
public bool AlwaysSet { get; }
1111
public int KeyOverride { get; set; }
1212
public int Order { get; set; } = int.MaxValue;
13-
public bool IgnoreField = false;
1413

15-
public GamePropertyAttribute(string key, object? defaultDefaultValue = null, bool alwaysSet = false)
14+
public GamePropertyAttribute(string key, object? defaultValue = null, bool alwaysSet = false)
1615
{
1716
Key = key;
18-
DefaultValue = defaultDefaultValue;
17+
DefaultValue = defaultValue;
1918
AlwaysSet = alwaysSet;
2019
}
2120
}

GeometryDashAPI/Crypt.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public static byte[] GZipCompress(byte[] data)
4848
using var memory = new MemoryStream();
4949
using (var destination = new GZipStream(memory, CompressionMode.Compress))
5050
{
51-
using (var memoryStream2 = new MemoryStream(data))
52-
memoryStream2.CopyTo(destination);
51+
using var memoryStream2 = new MemoryStream(data);
52+
memoryStream2.CopyTo(destination);
5353
}
5454
return memory.ToArray();
5555
}

GeometryDashAPI/Data/LocalLevels.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace GeometryDashAPI.Data
1010
{
11-
public class LocalLevels : GameData, IEnumerable<LevelCreatorModel>
11+
public class LocalLevels : GameData, IReadOnlyCollection<LevelCreatorModel>
1212
{
1313
private List<LevelCreatorModel> levels { get; set; }
1414
private Dictionary<string, Dictionary<int, int>> index;
@@ -19,6 +19,7 @@ public int BinaryVersion
1919
set => DataPlist["LLM_02"] = value;
2020
}
2121

22+
[Obsolete("Use Count instead", true)]
2223
public int LevelCount => levels.Count;
2324

2425
protected LocalLevels() : base(GameDataType.LocalLevels)
@@ -104,6 +105,8 @@ public bool Remove(LevelCreatorModel levelInfo)
104105
return true;
105106
}
106107

108+
public int Count => levels.Count;
109+
107110
public IEnumerator<LevelCreatorModel> GetEnumerator()
108111
{
109112
foreach (var level in levels)
@@ -152,7 +155,7 @@ public static LocalLevels CreateNew()
152155
public void AddLevel(LevelCreatorModel levelInfo)
153156
{
154157
var all = DataPlist["LLM_01"];
155-
for (var i = LevelCount - 1; i >= 0; i--)
158+
for (var i = Count - 1; i >= 0; i--)
156159
all[$"k_{i + 1}"] = all[$"k_{i}"];
157160
all["k_0"] = levelInfo.DataLevel;
158161
LoadLevels();

GeometryDashAPI/Levels/GameObjects/Default/Block.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ public class Block : GameObject, IBlock
1919
[GameProperty("36", false, Order = Trigger.OrderTriggerBase)] public bool IsTrigger { get; set; }
2020

2121
[GameProperty("6", 0)] public int Rotation { get; set; }
22+
2223
public bool Glow
2324
{
2425
get => !glow;
2526
set => glow = !value;
2627
}
28+
2729
[GameProperty("96", true)] private bool glow = true;
2830
[GameProperty("108", 0)] public int LinkControl { get; set; }
2931
[GameProperty("20", (short)0)] public short EditorL { get; set; }
@@ -32,11 +34,13 @@ public bool Glow
3234
[GameProperty("57")] [ArraySeparator(".")] public int[] Groups { get; set; }
3335
[GameProperty("67", false)] public bool DontEnter { get; set; }
3436
[GameProperty("25", 2)] public virtual int ZOrder { get; set; } = 2;
37+
3538
public Layer ZLayer
3639
{
3740
get => (Layer)zLayer;
3841
set => zLayer = (short)value;
3942
}
43+
4044
[GameProperty("24", (short)Layer.T1)] protected virtual short zLayer { get; set; } = (int)Layer.T1;
4145
[GameProperty("32", 1f)] public float Scale { get; set; } = 1f;
4246
[GameProperty("34", false)] public bool GroupParent { get; set; }

GeometryDashAPI/Levels/GameObjects/Default/Trigger.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ public abstract class Trigger : Block, ITrigger
88

99
[GameProperty("11", false, Order = 100)] public bool TouchTrigger { get; set; } = false;
1010
[GameProperty("62", false, Order = 101)] public bool SpawnTrigger { get; set; } = false;
11-
[GameProperty("87", false, Order = 102)] public virtual bool MultiTrigger { get; set; } = false;
11+
[GameProperty("87", false, Order = 102)] protected bool multiTrigger;
12+
13+
public virtual bool MultiTrigger
14+
{
15+
get => multiTrigger;
16+
set => multiTrigger = value;
17+
}
1218

1319
public Trigger()
1420
{

GeometryDashAPI/Levels/GameObjects/Triggers/ShakeTrigger.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ public class ShakeTrigger : Trigger
1010
[GameProperty("75", 0f, false, Order = OrderTriggerBase + 2)] public float Strength { get; set; }
1111
[GameProperty("84", 0f, false, Order = OrderTriggerBase + 3)] public float Interval { get; set; }
1212

13-
// robtop 300iq coder
14-
[GameProperty("87", false, Order = 102)]
15-
private bool multiTrigger;
16-
17-
[GameProperty("87", false, Order = 102, IgnoreField = true)]
1813
public override bool MultiTrigger
1914
{
2015
get => !multiTrigger;

GeometryDashAPI/Levels/GameObjects/Triggers/TouchTrigger.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ public class TouchTrigger : Trigger
1212
[GameProperty("82", ToggleMode.None, false, Order = OrderTriggerBase + 3)] public ToggleMode ToggleMode { get; set; } = ToggleMode.None;
1313
[GameProperty("89", false, false, Order = OrderTriggerBase + 4)] public bool DualMode { get; set; } = false;
1414

15-
// robtop 300iq coder
16-
[GameProperty("87", false, Order = 102)]
17-
private bool multiTrigger;
18-
19-
[GameProperty("87", false, Order = 102, IgnoreField = true)]
2015
public override bool MultiTrigger
2116
{
2217
get => !multiTrigger;

GeometryDashAPI/Serialization/PrinterInfo.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ internal class PrinterInfo<T>
1212
#if DEBUG
1313
public Expression<TypeDescriptorHelper.Printer<T>> PrinterExp { get; set; }
1414
public Expression<TypeDescriptorHelper.Getter<T, bool>> IsDefaultExp { get; set; }
15+
public string Name { get; set; }
1516
#endif
1617

1718
public PrinterInfo(
@@ -23,5 +24,9 @@ public PrinterInfo(
2324
IsDefault = isDefault;
2425
Attribute = attribute;
2526
}
27+
28+
#if DEBUG
29+
public override string ToString() => Name;
30+
#endif
2631
}
2732
}

GeometryDashAPI/Serialization/TypeDescriptor.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class TypeDescriptor<T> : IDescriptor<T>, ICopyDescriptor<T> where T : IG
1212
{
1313
private readonly SetterInfo<T>[] setters;
1414
private readonly PrinterInfo<T>[] printers;
15-
private readonly Dictionary<string, int> mappings;
15+
private readonly Dictionary<string, int>? mappings;
1616
private readonly string sense;
1717
private readonly Func<T> create;
1818
private readonly bool isStruct;
@@ -21,7 +21,7 @@ public class TypeDescriptor<T> : IDescriptor<T>, ICopyDescriptor<T> where T : IG
2121
public TypeDescriptor()
2222
{
2323
var type = typeof(T);
24-
create = CreateInstanceExpression<T>(type).Compile();
24+
create = CreateInstanceExpression<T>().Compile();
2525

2626
var senseAttribute = type.GetCustomAttribute<SenseAttribute>();
2727
if (senseAttribute == null)
@@ -33,7 +33,6 @@ public TypeDescriptor()
3333
var members = GetPropertiesAndFields(type)
3434
.Select(member => (member, attribute: member.GetCustomAttribute<GamePropertyAttribute>()))
3535
.Where(x => x.attribute != null)
36-
.Where(x => !x.attribute.IgnoreField)
3736
.ToArray();
3837
var createSetter = typeof(TypeDescriptorHelper)
3938
.GetMethod(nameof(TypeDescriptorHelper.CreateSetter), BindingFlags.Static | BindingFlags.NonPublic);
@@ -91,14 +90,13 @@ public T Create(ReadOnlySpan<char> raw)
9190
if (!int.TryParse(key.ToString(), out var index))
9291
#endif
9392
{
94-
var keyString = key.ToString();
95-
if (!mappings.TryGetValue(keyString, out var mapped))
93+
if (mappings == null || !mappings.TryGetValue(key.ToString(), out var mapped))
9694
{
9795
instance.WithoutLoaded.Add($"{key.ToString()}{sense}{value.ToString()}");
9896
continue;
9997
}
10098
if (!TrySet(instance, mapped, value))
101-
instance.WithoutLoaded.Add($"{keyString}{sense}{value.ToString()}");
99+
instance.WithoutLoaded.Add($"{key.ToString()}{sense}{value.ToString()}");
102100
continue;
103101
}
104102
if (!TrySet(instance, baseIndex + index, value))
@@ -177,6 +175,7 @@ private PrinterInfo<T>[] InitPrinters(IEnumerable<(MemberInfo member, GameProper
177175
x.attribute)
178176
#if DEBUG
179177
{
178+
Name = x.member.Name,
180179
PrinterExp = printerExp,
181180
IsDefaultExp = isDefaultExp
182181
}
@@ -186,19 +185,19 @@ private PrinterInfo<T>[] InitPrinters(IEnumerable<(MemberInfo member, GameProper
186185
.ToArray();
187186
}
188187

189-
private static Expression<Func<TB>> CreateInstanceExpression<TB>(Type type)
188+
private static Expression<Func<TB>> CreateInstanceExpression<TB>()
190189
{
191-
var ctor = Expression.New(type);
190+
var ctor = Expression.New(typeof(TB));
192191
var memberInit = Expression.MemberInit(ctor);
193192

194193
return Expression.Lambda<Func<TB>>(memberInit);
195194
}
196195

197-
private static (SetterInfo<T>[], int baseIndex, Dictionary<string, int> mappings) InitSetters(Type type, IEnumerable<(MemberInfo member, GamePropertyAttribute attribute)> members)
196+
private static (SetterInfo<T>[], int baseIndex, Dictionary<string, int>? mappings) InitSetters(Type type, IEnumerable<(MemberInfo member, GamePropertyAttribute attribute)> members)
198197
{
199198
var keys = new HashSet<string>();
200199
var maxKeyValue = 0;
201-
Dictionary<string, int> mappings = null;
200+
Dictionary<string, int>? mappings = null;
202201
foreach (var (member, attribute) in members)
203202
{
204203
if (int.TryParse(attribute.Key, out var key))
@@ -211,9 +210,9 @@ private static (SetterInfo<T>[], int baseIndex, Dictionary<string, int> mappings
211210
continue;
212211
}
213212

214-
mappings ??= new Dictionary<string, int>();
215213
if (attribute.KeyOverride == -1)
216214
throw new InvalidOperationException($"Key override for member '{attribute.Key}' in {type.Name} is not set");
215+
mappings ??= new Dictionary<string, int>();
217216
mappings.Add(attribute.Key, attribute.KeyOverride);
218217
}
219218

@@ -233,12 +232,12 @@ private static (SetterInfo<T>[], int baseIndex, Dictionary<string, int> mappings
233232

234233
private static IEnumerable<MemberInfo> GetPropertiesAndFields(Type type)
235234
{
236-
foreach (var property in type.GetProperties())
235+
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
237236
yield return property;
238237
var current = type;
239238
while (current != null && current != typeof(object))
240239
{
241-
foreach (var field in current.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
240+
foreach (var field in current.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
242241
yield return field;
243242
current = current.BaseType;
244243
}
@@ -518,12 +517,12 @@ private static Expression<Setter<TInstance>> CreateEnumSetter<TProp, TInstance>(
518517
);
519518
}
520519

521-
private static MethodInfo GetParserMethod<TProp>(out Expression instanceExpression)
520+
private static MethodInfo GetParserMethod<TProp>(out Expression? instanceExpression)
522521
{
523522
return GetParserMethod(typeof(TProp), out instanceExpression);
524523
}
525524

526-
private static MethodInfo GetParserMethod(Type propType, out Expression serializerExp)
525+
private static MethodInfo GetParserMethod(Type propType, out Expression? serializerExp)
527526
{
528527
if (typeof(IGameObject).IsAssignableFrom(propType))
529528
{

0 commit comments

Comments
 (0)