Skip to content

Commit 9c6acf6

Browse files
committed
Fix ugly A2S_INFO Edf solution
1 parent 9c459c7 commit 9c6acf6

5 files changed

Lines changed: 42 additions & 56 deletions

File tree

SteamQueryNet/SteamQueryNet.Tests/ServerQueryTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class ServerQueryTests
1616
public void ShouldInitializeWithProperHost(string host)
1717
{
1818
var squery = new ServerQuery(host, PORT);
19+
squery.GetServerInfo();
1920
}
2021

2122
[Theory]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace SteamQueryNet.Enums
2+
{
3+
public enum EDFFlags : byte
4+
{
5+
Port = 0x80,
6+
SteamID = 0x10,
7+
SourceTVPort = 0x40,
8+
SourceTVServerName = 0x40,
9+
Keywords = 0x20,
10+
GameID = 0x01
11+
}
12+
}

SteamQueryNet/SteamQueryNet/Models/ServerInfo.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public sealed class ServerInfo
7373

7474
/// <summary>
7575
/// This property only exist in a response if the server is running The Ship.
76+
/// Warning: this property information is not supported by SteamQueryNet yet.
7677
/// </summary>
7778
[ParseCustom]
7879
public ShipGameInfo ShipGameInfo { get; set; }
@@ -90,38 +91,38 @@ public sealed class ServerInfo
9091
/// <summary>
9192
/// The server's game port number.
9293
/// </summary>
93-
[EDF]
94+
[EDF((byte)EDFFlags.Port)]
9495
public short Port { get; set; }
9596

9697
/// <summary>
9798
/// Server's SteamID.
9899
/// </summary>
99-
[EDF]
100+
[EDF((byte)EDFFlags.SteamID)]
100101
public long SteamID { get; set; }
101102

102103
/// <summary>
103104
/// Spectator port number for SourceTV.
104105
/// </summary>
105-
[EDF]
106+
[EDF((byte)EDFFlags.SourceTVPort)]
106107
public short SourceTVPort { get; set; }
107108

108109
/// <summary>
109110
/// Name of the spectator server for SourceTV.
110111
/// </summary>
111-
[EDF]
112+
[EDF((byte)EDFFlags.SourceTVServerName)]
112113
public string SourceTVServerName { get; set; }
113114

114115
/// <summary>
115116
/// Tags that describe the game according to the server (for future use.)
116117
/// </summary>
117-
[EDF]
118+
[EDF((byte)EDFFlags.Keywords)]
118119
public string Keywords { get; set; }
119120

120121
/// <summary>
121122
/// The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits.
122123
/// The earlier AppID could have been truncated as it was forced into 16-bit storage.
123124
/// </summary>
124-
[EDF]
125+
[EDF((byte)EDFFlags.GameID)]
125126
public long GameID { get; set; }
126127

127128
/// <summary>

SteamQueryNet/SteamQueryNet/ServerQuery.cs

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -106,49 +106,10 @@ public ServerInfo GetServerInfo()
106106
try
107107
{
108108
sInfo.Ping = new Ping().Send(_ipEndpoint.Address).RoundtripTime;
109-
var request = BuildRequest(RequestHeaders.A2S_INFO, Encoding.UTF8.GetBytes(requestPayload));
110-
_client.Send(request, request.Length);
111-
byte[] response = _client.Receive(ref _ipEndpoint);
109+
byte[] response = SendRequest(RequestHeaders.A2S_INFO, Encoding.UTF8.GetBytes(requestPayload));
112110
if (response.Length > 0)
113111
{
114-
IEnumerable<byte> lastSource = ExtractData(sInfo, response, nameof(sInfo.EDF));
115-
116-
// Handle EDF's. This part looks hideous but i will get back to this after i get done with everything. Right now this works.
117-
if ((sInfo.EDF & 0x80) > 0)
118-
{
119-
(object result, int size) = ExtractMarshalType(lastSource, sInfo.Port.GetType());
120-
sInfo.Port = (short)result;
121-
lastSource = lastSource.Skip(size);
122-
}
123-
if ((sInfo.EDF & 0x10) > 0)
124-
{
125-
(object result, int size) = ExtractMarshalType(lastSource, sInfo.SteamID.GetType());
126-
sInfo.SteamID = (long)result;
127-
lastSource = lastSource.Skip(size);
128-
}
129-
if ((sInfo.EDF & 0x40) > 0)
130-
{
131-
(object result, int size) = ExtractMarshalType(lastSource, sInfo.SourceTVPort.GetType());
132-
sInfo.SourceTVPort = (short)result;
133-
lastSource = lastSource.Skip(size);
134-
135-
IEnumerable<byte> takenBytes = lastSource.TakeWhile(x => x != 0);
136-
sInfo.SourceTVServerName = Encoding.UTF8.GetString(takenBytes.ToArray());
137-
lastSource = lastSource.Skip(takenBytes.Count() + 1);
138-
139-
}
140-
if ((sInfo.EDF & 0x20) > 0)
141-
{
142-
IEnumerable<byte> takenBytes = lastSource.TakeWhile(x => x != 0);
143-
sInfo.Keywords = Encoding.UTF8.GetString(takenBytes.ToArray());
144-
lastSource = lastSource.Skip(takenBytes.Count() + 1);
145-
}
146-
if ((sInfo.EDF & 0x01) > 0)
147-
{
148-
(object result, int size) = ExtractMarshalType(lastSource, sInfo.GameID.GetType());
149-
sInfo.GameID = (long)result;
150-
lastSource = lastSource.Skip(size);
151-
}
112+
ExtractData(sInfo, response, nameof(sInfo.EDF));
152113
}
153114
}
154115
catch (Exception)
@@ -160,6 +121,13 @@ public ServerInfo GetServerInfo()
160121
return sInfo;
161122
}
162123

124+
private byte[] SendRequest(byte requestHeader, byte[] payload = null)
125+
{
126+
var request = BuildRequest(requestHeader, payload);
127+
_client.Send(request, request.Length);
128+
return _client.Receive(ref _ipEndpoint);
129+
}
130+
163131
public void RenewChallenge()
164132
{
165133
throw new NotImplementedException();
@@ -171,7 +139,7 @@ private byte[] BuildRequest(byte headerCode, byte[] extraParams = null)
171139
return extraParams != null ? request.Concat(extraParams).ToArray() : request;
172140
}
173141

174-
private IEnumerable<byte> ExtractData<TObject>(TObject objectRef, byte[] dataSource, string stopAt = "")
142+
private void ExtractData<TObject>(TObject objectRef, byte[] dataSource, string edfPropName = "")
175143
where TObject : class
176144
{
177145
IEnumerable<byte> takenBytes = new List<byte>();
@@ -182,6 +150,14 @@ private IEnumerable<byte> ExtractData<TObject>(TObject objectRef, byte[] dataSou
182150

183151
foreach (PropertyInfo property in propsOfObject)
184152
{
153+
CustomAttributeData edfInfo = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(EDFAttribute));
154+
if (edfInfo != null)
155+
{
156+
byte edfValue = (byte)typeof(TObject).GetProperty(edfPropName).GetValue(objectRef);
157+
byte edfPropertyConditionValue = (byte)edfInfo.ConstructorArguments[0].Value;
158+
if ((edfValue & edfPropertyConditionValue) <= 0) { continue; }
159+
}
160+
185161
if (property.PropertyType == typeof(string))
186162
{
187163
takenBytes = strippedSource.TakeWhile(x => x != 0);
@@ -195,14 +171,7 @@ private IEnumerable<byte> ExtractData<TObject>(TObject objectRef, byte[] dataSou
195171
property.SetValue(objectRef, property.PropertyType.IsEnum ? Enum.Parse(property.PropertyType, result.ToString()) : result);
196172
strippedSource = strippedSource.Skip(size);
197173
}
198-
199-
if (property.Name == stopAt)
200-
{
201-
break;
202-
}
203174
}
204-
205-
return strippedSource;
206175
}
207176

208177
private (object, int) ExtractMarshalType(IEnumerable<byte> source, Type type)

SteamQueryNet/SteamQueryNet/Utils/EDFAttribute.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
namespace SteamQueryNet.Utils
44
{
55
[AttributeUsage(AttributeTargets.Property)]
6-
public class EDFAttribute : Attribute { }
6+
public class EDFAttribute : Attribute
7+
{
8+
public EDFAttribute(byte condition) { }
9+
}
710
}

0 commit comments

Comments
 (0)