Skip to content

Commit 7ac8459

Browse files
authored
Protocol Bump and Command ArgumentParser Refactor (#488)
1 parent a7e788f commit 7ac8459

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+24778
-21125
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Obsidian.API.Commands.ArgumentParsers;
2+
3+
[ArgumentParser("brigadier:bool")]
4+
public sealed partial class BoolArgumentParser(bool value) : BaseArgumentParser<bool>
5+
{
6+
public bool Value { get; } = value;
7+
8+
public BoolArgumentParser() : this(false) { }
9+
10+
public override bool TryParseArgument(string input, CommandContext ctx, out bool result)
11+
=> bool.TryParse(input, out result);
12+
13+
public override void Write(INetStreamWriter writer)
14+
{
15+
base.Write(writer);
16+
17+
writer.WriteBoolean(this.Value);
18+
}
19+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace Obsidian.API.Commands.ArgumentParsers;
2+
3+
[ArgumentParser("minecraft:entity")]
4+
public sealed partial class EntityArgumentParser(EntityFilter mask) : BaseArgumentParser<IEntity>
5+
{
6+
public EntityFilter Mask { get; set; } = mask;
7+
8+
public EntityArgumentParser() : this(EntityFilter.SingleEntityOrPlayer) { }
9+
10+
public override bool TryParseArgument(string input, CommandContext ctx, out IEntity result)
11+
{
12+
// TODO: Implement entity parsing logic based on entity selectors (@p, @a, @e, @r) or entity names
13+
result = null;
14+
return false;
15+
}
16+
17+
public override void Write(INetStreamWriter writer)
18+
{
19+
base.Write(writer);
20+
21+
writer.WriteByte((sbyte)this.Mask);
22+
}
23+
}
24+
25+
public enum EntityFilter : sbyte
26+
{
27+
SingleEntityOrPlayer = 0x01,
28+
OnlyPlayers = 0x02
29+
}
30+

Obsidian.API/Commands/ArgumentParsers/LocationArgumentParser.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
namespace Obsidian.API.Commands.ArgumentParsers;
22

3-
public sealed class LocationArgumentParser : BaseArgumentParser<VectorF>
3+
[ArgumentParser("minecraft:vec3")]
4+
public sealed partial class LocationArgumentParser : BaseArgumentParser<VectorF>
45
{
5-
public LocationArgumentParser() : base(10, "minecraft:vec3")
6-
{
7-
}
8-
96
public override bool TryParseArgument(string input, CommandContext context, out VectorF result)
107
{
118
var splitted = input.Split(' ');

Obsidian.API/Commands/ArgumentParsers/MinecraftTimeArgumentParser.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
namespace Obsidian.API.Commands.ArgumentParsers;
22

3-
public sealed class MinecraftTimeArgumentParser : BaseArgumentParser<MinecraftTime>
3+
[ArgumentParser("minecraft:time")]
4+
public sealed partial class MinecraftTimeArgumentParser : BaseArgumentParser<MinecraftTime>
45
{
5-
public MinecraftTimeArgumentParser() : base(42, "minecraft:time")
6-
{
7-
}
6+
public int Min { get; set; } = 0;
87

98
public override bool TryParseArgument(string input, CommandContext ctx, out MinecraftTime result)
109
{
@@ -38,6 +37,19 @@ public override bool TryParseArgument(string input, CommandContext ctx, out Mine
3837
isSuccess = true;
3938
}
4039

40+
if (result.Tick < Min)
41+
{
42+
result = default;
43+
return false;
44+
}
45+
4146
return isSuccess;
4247
}
48+
49+
public override void Write(INetStreamWriter writer)
50+
{
51+
base.Write(writer);
52+
53+
writer.WriteInt(Min);
54+
}
4355
}

Obsidian/Commands/Parsers/NumberCommandParsers.Helpers.cs renamed to Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.Helpers.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
namespace Obsidian.Commands.Parsers;
2-
public partial class NumberCommandParser<TNumber>
1+
namespace Obsidian.API.Commands.ArgumentParsers;
2+
public partial class NumericArgumentParser<TNumber>
33
{
44
protected void WriteAsInt(INetStreamWriter writer)
55
{
Lines changed: 112 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,166 @@
1-
namespace Obsidian.API.Commands.ArgumentParsers;
1+
using System.Numerics;
22

3-
public sealed class SignedIntArgumentParser : BaseArgumentParser<int>
3+
namespace Obsidian.API.Commands.ArgumentParsers;
4+
5+
public abstract partial class NumericArgumentParser<TNumber> : BaseArgumentParser<TNumber> where TNumber : struct,
6+
IConvertible,
7+
IMinMaxValue<TNumber>,
8+
INumber<TNumber>
49
{
5-
public SignedIntArgumentParser() : base(3, "brigadier:integer") { }
6-
public override bool TryParseArgument(string input, CommandContext ctx, out int result)
7-
=> int.TryParse(input, out result);
10+
private static Type NumberType => typeof(TNumber);
11+
public NumberFlags Flags { get; private set; }
12+
13+
public TNumber Min { get; }
14+
15+
public TNumber Max { get; }
16+
17+
protected NumericArgumentParser(TNumber min, TNumber max)
18+
{
19+
this.Min = min;
20+
this.Max = max;
21+
22+
if (min != TNumber.MinValue)
23+
this.Flags |= NumberFlags.HasMinValue;
24+
if (max != TNumber.MaxValue)
25+
this.Flags |= NumberFlags.HasMaxValue;
26+
}
27+
28+
public override void Write(INetStreamWriter writer)
29+
{
30+
base.Write(writer);
31+
32+
writer.WriteByte((sbyte)this.Flags);
33+
34+
this.WriteNumbers(writer);
35+
}
36+
37+
private void WriteNumbers(INetStreamWriter writer)
38+
{
39+
if (NumberType == typeof(int))
40+
this.WriteAsInt(writer);
41+
else if (NumberType == typeof(double))
42+
this.WriteAsDouble(writer);
43+
else if (NumberType == typeof(float))
44+
this.WriteAsSingle(writer);
45+
else if (NumberType == typeof(long))
46+
this.WriteAsLong(writer);
47+
}
848
}
949

10-
public sealed class BoolArgumentParser : BaseArgumentParser<bool>
50+
[ArgumentParser("brigadier:integer")]
51+
public sealed partial class SignedIntArgumentParser : NumericArgumentParser<int>
1152
{
12-
public BoolArgumentParser() : base(0, "brigadier:bool") { }
13-
public override bool TryParseArgument(string input, CommandContext ctx, out bool result)
14-
=> bool.TryParse(input, out result);
53+
public SignedIntArgumentParser() : base(int.MinValue, int.MaxValue) { }
54+
public SignedIntArgumentParser(int min, int max) : base(min, max) { }
55+
56+
public override bool TryParseArgument(string input, CommandContext ctx, out int result)
57+
=> int.TryParse(input, out result);
1558
}
1659

17-
public sealed class UnsignedByteArgumentParser : BaseArgumentParser<byte>
60+
[ArgumentParser("brigadier:integer")]
61+
public sealed partial class UnsignedByteArgumentParser : NumericArgumentParser<byte>
1862
{
19-
public UnsignedByteArgumentParser() : base(3, "brigadier:integer") { }
63+
public UnsignedByteArgumentParser() : base(byte.MinValue, byte.MaxValue) { }
64+
public UnsignedByteArgumentParser(byte min, byte max) : base(min, max) { }
65+
2066
public override bool TryParseArgument(string input, CommandContext ctx, out byte result)
2167
=> byte.TryParse(input, out result);
2268
}
2369

24-
public sealed class SignedByteArgumentParser : BaseArgumentParser<sbyte>
70+
[ArgumentParser("brigadier:integer")]
71+
public sealed partial class SignedByteArgumentParser : NumericArgumentParser<sbyte>
2572
{
26-
public SignedByteArgumentParser() : base(3, "brigadier:integer") { }
73+
public SignedByteArgumentParser() : base(sbyte.MinValue, sbyte.MaxValue) { }
74+
public SignedByteArgumentParser(sbyte min, sbyte max) : base(min, max) { }
75+
2776
public override bool TryParseArgument(string input, CommandContext ctx, out sbyte result)
2877
=> sbyte.TryParse(input, out result);
2978
}
3079

31-
public sealed class SignedShortArgumentParser : BaseArgumentParser<short>
80+
[ArgumentParser("brigadier:integer")]
81+
public sealed partial class SignedShortArgumentParser : NumericArgumentParser<short>
3282
{
33-
public SignedShortArgumentParser() : base(3, "brigadier:integer") { }
83+
public SignedShortArgumentParser() : base(short.MinValue, short.MaxValue) { }
84+
public SignedShortArgumentParser(short min, short max) : base(min, max) { }
85+
3486
public override bool TryParseArgument(string input, CommandContext ctx, out short result)
3587
=> short.TryParse(input, out result);
3688
}
3789

38-
public sealed class UnsignedShortArgumentParser : BaseArgumentParser<ushort>
90+
[ArgumentParser("brigadier:integer")]
91+
public sealed partial class UnsignedShortArgumentParser : NumericArgumentParser<ushort>
3992
{
40-
public UnsignedShortArgumentParser() : base(3, "brigadier:integer") { }
93+
public UnsignedShortArgumentParser() : base(ushort.MinValue, ushort.MaxValue) { }
94+
public UnsignedShortArgumentParser(ushort min, ushort max) : base(min, max) { }
95+
4196
public override bool TryParseArgument(string input, CommandContext ctx, out ushort result)
4297
=> ushort.TryParse(input, out result);
4398
}
4499

45-
public sealed class UnsignedIntArgumentParser : BaseArgumentParser<uint>
100+
[ArgumentParser("brigadier:integer")]
101+
public sealed partial class UnsignedIntArgumentParser : NumericArgumentParser<uint>
46102
{
47-
public UnsignedIntArgumentParser() : base(3, "brigadier:integer") { }
103+
public UnsignedIntArgumentParser() : base(uint.MinValue, uint.MaxValue) { }
104+
public UnsignedIntArgumentParser(uint min, uint max) : base(min, max) { }
105+
48106
public override bool TryParseArgument(string input, CommandContext ctx, out uint result)
49107
=> uint.TryParse(input, out result);
50108
}
51109

52-
public sealed class SignedLongArgumentParser : BaseArgumentParser<long>
110+
[ArgumentParser("brigadier:long")]
111+
public sealed partial class SignedLongArgumentParser : NumericArgumentParser<long>
53112
{
54-
public SignedLongArgumentParser() : base(3, "brigadier:long") { }
113+
public SignedLongArgumentParser() : base(long.MinValue, long.MaxValue) { }
114+
public SignedLongArgumentParser(long min, long max) : base(min, max) { }
115+
55116
public override bool TryParseArgument(string input, CommandContext ctx, out long result)
56117
=> long.TryParse(input, out result);
57118
}
58119

59-
public sealed class UnsignedLongArgumentParser : BaseArgumentParser<ulong>
120+
[ArgumentParser("brigadier:long")]
121+
public sealed partial class UnsignedLongArgumentParser : NumericArgumentParser<ulong>
60122
{
61-
public UnsignedLongArgumentParser() : base(4, "brigadier:long") { }
123+
public UnsignedLongArgumentParser() : base(ulong.MinValue, ulong.MaxValue) { }
124+
public UnsignedLongArgumentParser(ulong min, ulong max) : base(min, max) { }
125+
62126
public override bool TryParseArgument(string input, CommandContext ctx, out ulong result)
63127
=> ulong.TryParse(input, out result);
64128
}
65129

66-
public sealed class FloatArgumentParser : BaseArgumentParser<float>
130+
[ArgumentParser("brigadier:float")]
131+
public sealed partial class FloatArgumentParser : NumericArgumentParser<float>
67132
{
68-
public FloatArgumentParser() : base(1, "brigadier:float") { }
133+
public FloatArgumentParser() : base(float.MinValue, float.MaxValue) { }
134+
public FloatArgumentParser(float min, float max) : base(min, max) { }
135+
69136
public override bool TryParseArgument(string input, CommandContext ctx, out float result)
70137
=> float.TryParse(input, out result);
71138
}
72-
public sealed class DoubleArgumentParser : BaseArgumentParser<double>
139+
140+
[ArgumentParser("brigadier:double")]
141+
public sealed partial class DoubleArgumentParser : NumericArgumentParser<double>
73142
{
74-
public DoubleArgumentParser() : base(2, "brigadier:double") { }
143+
public DoubleArgumentParser() : base(double.MinValue, double.MaxValue) { }
144+
public DoubleArgumentParser(double min, double max) : base(min, max) { }
145+
75146
public override bool TryParseArgument(string input, CommandContext ctx, out double result)
76147
=> double.TryParse(input, out result);
77148
}
78-
public sealed class DecimalArgumentParser : BaseArgumentParser<decimal>
149+
150+
[ArgumentParser("brigadier:integer")]
151+
public sealed partial class DecimalArgumentParser : NumericArgumentParser<decimal>
79152
{
80-
public DecimalArgumentParser() : base(3, "brigadier:integer") { }
153+
public DecimalArgumentParser() : base(decimal.MinValue, decimal.MaxValue) { }
154+
public DecimalArgumentParser(decimal min, decimal max) : base(min, max) { }
155+
81156
public override bool TryParseArgument(string input, CommandContext ctx, out decimal result)
82157
=> decimal.TryParse(input, out result);
83158
}
159+
160+
[Flags]
161+
public enum NumberFlags : byte
162+
{
163+
None,
164+
HasMinValue = 1,
165+
HasMaxValue
166+
}

Obsidian.API/Commands/ArgumentParsers/PlayerArgumentParser.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
namespace Obsidian.API.Commands.ArgumentParsers;
22

3-
public class PlayerArgumentParser : BaseArgumentParser<IPlayer>
3+
[ArgumentParser("minecraft:game_profile")]
4+
public sealed partial class PlayerArgumentParser : BaseArgumentParser<IPlayer>
45
{
5-
public PlayerArgumentParser() : base(7, "minecraft:game_profile")
6-
{
7-
}
8-
96
//TODO support selectors
107
public override bool TryParseArgument(string input, CommandContext context, out IPlayer result)
118
{
Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,60 @@
11
namespace Obsidian.API.Commands.ArgumentParsers;
22

3-
public sealed class StringArgumentParser : BaseArgumentParser<string>
3+
[ArgumentParser("brigadier:string")]
4+
public sealed partial class StringArgumentParser(StringType type) : BaseArgumentParser<string>
45
{
5-
public StringArgumentParser() : base(5, "brigadier:string") { }
6+
public StringType Type { get; } = type;
7+
8+
public StringArgumentParser() : this(StringType.QuotablePhrase) { }
9+
610
public override bool TryParseArgument(string input, CommandContext ctx, out string result)
711
{
812
result = input;
913
return true;
1014
}
15+
16+
public override void Write(INetStreamWriter writer)
17+
{
18+
base.Write(writer);
19+
20+
writer.WriteVarInt((int)Type);
21+
}
1122
}
1223

13-
public sealed class GuidArgumentParser : BaseArgumentParser<Guid>
24+
[ArgumentParser("minecraft:uuid")]
25+
public sealed partial class GuidArgumentParser(Guid guid) : BaseArgumentParser<Guid>
1426
{
15-
public GuidArgumentParser() : base(49, "minecraft:uuid") { }
27+
public Guid Guid { get; } = guid;
28+
29+
public GuidArgumentParser() : this(Guid.Empty) { }
30+
1631
public override bool TryParseArgument(string input, CommandContext ctx, out Guid result)
1732
{
1833
return Guid.TryParse(input, out result);
1934
}
35+
36+
public override void Write(INetStreamWriter writer)
37+
{
38+
base.Write(writer);
39+
40+
writer.WriteUuid(this.Guid);
41+
}
42+
}
43+
44+
public enum StringType : int
45+
{
46+
/// <summary>
47+
/// Reads a single word.
48+
/// </summary>
49+
SingleWord = 0,
50+
51+
/// <summary>
52+
/// If it starts with a ", keeps reading until another " (allowing escaping with \). Otherwise behaves the same as <see cref="SingleWord"/>.
53+
/// </summary>
54+
QuotablePhrase = 1,
55+
56+
/// <summary>
57+
/// Reads the rest of the content after the cursor. Quotes will not be removed.
58+
/// </summary>
59+
GreedyPhrase = 2
2060
}

0 commit comments

Comments
 (0)