Skip to content

Commit bf2088d

Browse files
authored
Merge pull request #26 from Folleach/features/account-message
Create methods for create and read in game messages
2 parents 6357a5d + 3a54b32 commit bf2088d

File tree

10 files changed

+206
-3
lines changed

10 files changed

+206
-3
lines changed

GeometryDashAPI.Tests/MessageTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Linq;
2+
using FluentAssertions;
3+
using GeometryDashAPI.Server.Dtos;
4+
using NUnit.Framework;
5+
6+
namespace GeometryDashAPI.Tests;
7+
8+
[TestFixture]
9+
public class MessageTests
10+
{
11+
[Test]
12+
public void DecryptMessage()
13+
{
14+
var message = Message.FromRaw("SGVsbG8sIGl0J3MgbGlicmFyeSB0ZXN0IHRpbWU=", "eBNEUBFbQUFBEUddV0IRX1FGQl5DXxJFUFJfV0FCHRRWWl8WQBJeVFREEkxeRBRfXF9V");
15+
16+
message.Should().BeEquivalentTo(new Message()
17+
{
18+
Subject = "Hello, it's library test time",
19+
Body = "I've just view network packets, don't keep you mind"
20+
});
21+
}
22+
23+
[Test]
24+
public void EncryptMessage()
25+
{
26+
var message = new Message()
27+
{
28+
Subject = "Hello, it's library test time",
29+
Body = "I've just view network packets, don't keep you mind"
30+
};
31+
32+
var parameters = message.BuildQuery();
33+
34+
parameters.FirstOrDefault(x => x.Key == "subject").Value.Should().BeEquivalentTo("SGVsbG8sIGl0J3MgbGlicmFyeSB0ZXN0IHRpbWU=");
35+
parameters.FirstOrDefault(x => x.Key == "body").Value.Should().BeEquivalentTo("eBNEUBFbQUFBEUddV0IRX1FGQl5DXxJFUFJfV0FCHRRWWl8WQBJeVFREEkxeRBRfXF9V");
36+
}
37+
}

GeometryDashAPI/Server/Dtos/Account.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using GeometryDashAPI.Attributes;
2+
using GeometryDashAPI.Server.Enums;
23

34
namespace GeometryDashAPI.Server.Dtos
45
{
@@ -20,7 +21,7 @@ public class Account : GameObject
2021
[GameProperty("15")] public int Special { get; set; }
2122
[GameProperty("16")] public int AccountId { get; set; }
2223
[GameProperty("17")] public int UserCoins { get; set; }
23-
[GameProperty("18")] public int MessageState { get; set; }
24+
[GameProperty("18")] public AllowMessagesFrom MessageState { get; set; }
2425
[GameProperty("19")] public int FriendsState { get; set; }
2526
[GameProperty("20")] public string YouTubeId { get; set; }
2627
[GameProperty("21")] public int CubeId { get; set; }
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Text;
3+
4+
namespace GeometryDashAPI.Server.Dtos;
5+
6+
public class Message : IQuery
7+
{
8+
private static readonly string BodyXorKey = "14251";
9+
10+
public string Subject { get; set; }
11+
public string Body { get; set; }
12+
13+
public static Message FromRaw(string subject, string body)
14+
{
15+
return new Message()
16+
{
17+
Subject = DeserializeSubject(subject),
18+
Body = DeserializeBody(body)
19+
};
20+
}
21+
22+
public Parameters BuildQuery()
23+
{
24+
var parameters = new Parameters();
25+
BuildQuery(parameters);
26+
return parameters;
27+
}
28+
29+
public void BuildQuery(Parameters parameters)
30+
{
31+
parameters.Add(new Property("subject", SerializeSubject(Subject)));
32+
parameters.Add(new Property("body", SerializeBody(Body)));
33+
}
34+
35+
internal static string DeserializeSubject(string raw) => Encoding.UTF8.GetString(Convert.FromBase64String(raw));
36+
internal static string SerializeSubject(string subject) => Convert.ToBase64String(Encoding.ASCII.GetBytes(subject));
37+
38+
internal static string DeserializeBody(string raw) => Crypt.XOR(Encoding.UTF8.GetString(Convert.FromBase64String(raw)), BodyXorKey);
39+
internal static string SerializeBody(string body) => Convert.ToBase64String(Encoding.ASCII.GetBytes(Crypt.XOR(body, BodyXorKey)));
40+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using GeometryDashAPI.Attributes;
2+
3+
namespace GeometryDashAPI.Server.Dtos;
4+
5+
[Sense(":")]
6+
public class MessageContent : MessagePreview
7+
{
8+
[GameProperty("5")]
9+
private string body;
10+
11+
public string Body
12+
{
13+
get => Message.DeserializeBody(body);
14+
set => Message.SerializeBody(value);
15+
}
16+
17+
public Message Message => new()
18+
{
19+
Body = Message.DeserializeBody(body),
20+
Subject = Subject
21+
};
22+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using GeometryDashAPI.Attributes;
2+
3+
namespace GeometryDashAPI.Server.Dtos;
4+
5+
[Sense(":")]
6+
public class MessagePreview : GameObject
7+
{
8+
[GameProperty("1")]
9+
public int MessageId { get; set; }
10+
11+
[GameProperty("2")]
12+
public int SenderAccountId { get; set; }
13+
14+
[GameProperty("3")]
15+
public int SenderUserId { get; set; }
16+
17+
[GameProperty("4")]
18+
private string subject;
19+
20+
public string Subject
21+
{
22+
get => Message.DeserializeSubject(subject);
23+
set => Message.SerializeSubject(value);
24+
}
25+
26+
[GameProperty("6")]
27+
public string SenderUserName { get; set; }
28+
29+
[GameProperty("7")]
30+
public string Time { get; set; }
31+
32+
[GameProperty("8")]
33+
public bool HasBeenRead { get; set; }
34+
35+
public override string ToString()
36+
{
37+
return $"Letter '{Subject}' from {SenderUserName}({SenderAccountId})";
38+
}
39+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace GeometryDashAPI.Server.Enums;
2+
3+
public enum AllowMessagesFrom
4+
{
5+
All = 0,
6+
Friends = 1,
7+
None = 2
8+
}

GeometryDashAPI/Server/GameClient.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using GeometryDashAPI.Server.Enums;
22
using GeometryDashAPI.Server.Queries;
33
using System;
4+
using System.Net;
45
using System.Threading.Tasks;
56
using GeometryDashAPI.Attributes;
7+
using GeometryDashAPI.Server.Dtos;
68
using GeometryDashAPI.Server.Responses;
79

810
namespace GeometryDashAPI.Server
@@ -114,6 +116,38 @@ public async Task<ServerResponse<LevelPageResponse>> GetMyLevelsAsync(PasswordQu
114116
return await Get<LevelPageResponse>("/getGJLevels21.php", query);
115117
}
116118

119+
public async Task<ServerResponse<NoneResponse>> SendMessageAsync(PasswordQuery fromAccount, int toAccountId, Message message)
120+
{
121+
var query = new FlexibleQuery()
122+
.AddToChain(GetOnlineQuery())
123+
.AddToChain(fromAccount)
124+
.AddProperty(new Property("toAccountID", toAccountId))
125+
.AddToChain(message);
126+
127+
return await Get<NoneResponse>("/uploadGJMessage20.php", query);
128+
}
129+
130+
public Task<ServerResponse<MessagesPageResponse>> GetMessagesAsync(PasswordQuery account, int page)
131+
{
132+
var query = new FlexibleQuery()
133+
.AddToChain(GetOnlineQuery())
134+
.AddToChain(account)
135+
.AddProperty(new Property("page", page))
136+
.AddProperty(new Property("total", 0));
137+
138+
return Get<MessagesPageResponse>("/getGJMessages20.php", query);
139+
}
140+
141+
public Task<ServerResponse<MessageContent>> ReadMessageAsync(PasswordQuery account, int messageId)
142+
{
143+
var query = new FlexibleQuery()
144+
.AddToChain(GetOnlineQuery())
145+
.AddToChain(account)
146+
.AddProperty(new Property("messageID", messageId));
147+
148+
return Get<MessageContent>("/downloadGJMessage20.php", query);
149+
}
150+
117151
private async Task<ServerResponse<T>> Get<T>(string path, IQuery query) where T : IGameObject
118152
{
119153
var (statusCode, body) = await network.GetAsync(path, query);

GeometryDashAPI/Server/Pagination.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ public static Pagination Parse(string raw)
3434
var parser = new LLParserSpan(":".AsSpan(), raw.AsSpan());
3535
var result = new Pagination();
3636
#if NETSTANDARD2_1
37-
result.TotalCount = int.Parse(parser.Next());
37+
result.TotalCount = int.TryParse(parser.Next(), out var total) ? total : 0;
3838
result.RangeIn = int.Parse(parser.Next());
3939
result.RangeOut = int.Parse(parser.Next());
4040
#else
41-
result.TotalCount = int.Parse(parser.Next().ToString());
41+
result.TotalCount = int.TryParse(parser.Next().ToString(), out var total) ? total : 0;
4242
result.RangeIn = int.Parse(parser.Next().ToString());
4343
result.RangeOut = int.Parse(parser.Next().ToString());
4444
#endif
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Collections.Generic;
2+
using GeometryDashAPI.Attributes;
3+
using GeometryDashAPI.Server.Dtos;
4+
5+
namespace GeometryDashAPI.Server.Responses;
6+
7+
[AsStruct]
8+
[Sense("#")]
9+
public class MessagesPageResponse : GameObject
10+
{
11+
[GameProperty("0")]
12+
[ArraySeparator("|")]
13+
public List<MessagePreview> Messages { get; set; }
14+
15+
[GameProperty("1")]
16+
public Pagination Page { get; set; }
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace GeometryDashAPI.Server.Responses;
2+
3+
public class NoneResponse : GameObject
4+
{
5+
}

0 commit comments

Comments
 (0)