Skip to content

Commit 68c0db9

Browse files
committed
Make use of dynamic objects to serialize/deserialize json
1 parent 8b23ee9 commit 68c0db9

6 files changed

Lines changed: 164 additions & 167 deletions

File tree

Apps/Extract/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,19 @@ static void ParseArgs(string[] args)
6363
case "--recording":
6464
case "--recordings":
6565
{
66-
_recording = splitArg[1];
66+
_recording = splitArg[1].Replace("\"", "");
6767
}
6868
break;
6969
case "-o":
7070
case "--outdirectory":
7171
{
72-
_outDirectory = splitArg[1];
72+
_outDirectory = splitArg[1].Replace("\"", "");
7373
}
7474
break;
7575
case "-t":
7676
case "--tibiadirectory":
7777
{
78-
_tibiaDirectory = splitArg[1];
78+
_tibiaDirectory = splitArg[1].Replace("\"", "");
7979
}
8080
break;
8181
default:

Apps/Record/Program.cs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,55 @@ class Program
1515

1616
static BinaryWriter _binaryWriter;
1717

18+
static string _tibiaDirectory = string.Empty;
19+
20+
static int _httpPort = 80;
21+
22+
static void ParseArgs(string[] args)
23+
{
24+
foreach (var arg in args)
25+
{
26+
if (!arg.Contains('=', StringComparison.CurrentCultureIgnoreCase))
27+
{
28+
continue;
29+
}
30+
31+
var splitArg = arg.Split('=');
32+
if (splitArg.Length != 2)
33+
{
34+
continue;
35+
}
36+
37+
switch (splitArg[0])
38+
{
39+
case "-t":
40+
case "--tibiadirectory":
41+
{
42+
_tibiaDirectory = splitArg[1].Replace("\"", "");
43+
}
44+
break;
45+
case "-p":
46+
case "--port":
47+
{
48+
if (int.TryParse(splitArg[1], out var port))
49+
{
50+
_httpPort = port;
51+
}
52+
}
53+
break;
54+
default:
55+
break;
56+
}
57+
}
58+
}
59+
1860
static void Main(string[] args)
1961
{
2062
try
2163
{
22-
var tibiaDirectory = args.Length > 0 ? args[1] : string.Empty;
64+
ParseArgs(args);
2365

24-
using (var client = new Client(tibiaDirectory))
66+
using (var client = new Client(_tibiaDirectory))
2567
{
2668
var utcNow = DateTime.UtcNow;
2769
var filename = $"{utcNow.Day}_{utcNow.Month}_{utcNow.Year}__{utcNow.Hour}_{utcNow.Minute}_{utcNow.Second}.oxr";
@@ -38,7 +80,7 @@ static void Main(string[] args)
3880
client.Proxy.OnReceivedServerMessage += Proxy_OnReceivedServerMessage;
3981

4082
// Disable packet parsing as we only care about the raw, decrypted packets and speed.
41-
client.StartProxy(enablePacketParsing: false);
83+
client.StartProxy(enablePacketParsing: false, httpPort: _httpPort);
4284

4385
while (Console.ReadLine() != "quit")
4486
{

Apps/Watch/Program.cs

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,48 @@ class Program
3030

3131
static string _recordingName;
3232

33+
static int _httpPort = 80;
34+
3335
static bool _userQuit;
3436

37+
static void ParseArgs(string[] args)
38+
{
39+
foreach (var arg in args)
40+
{
41+
if (!arg.Contains('=', StringComparison.CurrentCultureIgnoreCase))
42+
{
43+
continue;
44+
}
45+
46+
var splitArg = arg.Split('=');
47+
if (splitArg.Length != 2)
48+
{
49+
continue;
50+
}
51+
52+
switch (splitArg[0])
53+
{
54+
case "-r":
55+
case "--recording":
56+
{
57+
_recordingName = splitArg[1].Replace("\"", "");
58+
}
59+
break;
60+
case "-p":
61+
case "--port":
62+
{
63+
if (int.TryParse(splitArg[1], out var port))
64+
{
65+
_httpPort = port;
66+
}
67+
}
68+
break;
69+
default:
70+
break;
71+
}
72+
}
73+
}
74+
3575
static void Main(string[] args)
3676
{
3777
if (args.Length <= 0)
@@ -40,7 +80,8 @@ static void Main(string[] args)
4080
return;
4181
}
4282

43-
_recordingName = args[0];
83+
ParseArgs(args);
84+
4485
if (string.IsNullOrEmpty(_recordingName) || !_recordingName.EndsWith(".oxr", StringComparison.CurrentCultureIgnoreCase))
4586
{
4687
Console.WriteLine($"Invalid recording file: {_recordingName ?? "null"}");
@@ -68,11 +109,12 @@ static void Initialize()
68109
}
69110

70111
_httpListener = new HttpListener();
71-
if (!_httpListener.Prefixes.Contains("http://127.0.0.1:80/"))
112+
var uriPrefix = $"http://127.0.0.1:{_httpPort}/";
113+
if (!_httpListener.Prefixes.Contains(uriPrefix))
72114
{
73115
// The HTTP listener must be listening on port 80 as the
74116
// Tibia client sends HTTP requests over port 80.
75-
_httpListener.Prefixes.Add("http://127.0.0.1:80/");
117+
_httpListener.Prefixes.Add(uriPrefix);
76118
}
77119

78120
_httpListener.Start();
@@ -125,35 +167,45 @@ static void BeginGetContextCallback(IAsyncResult ar)
125167
var filename = Path.GetFileNameWithoutExtension(_recordingName);
126168
var address = ((IPEndPoint)_tcpListener.LocalEndpoint).Address.ToString();
127169
var port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
128-
129-
var loginData = new LoginData
130-
{
131-
Session = new Session(),
132-
PlayData = new PlayData
133-
{
134-
Worlds = new List<World>
135-
{
136-
new World
137-
{
138-
Name = OxWorldName,
139-
ExternalPortProtected = port,
140-
ExternalPortUnprotected = port,
141-
ExternalAddressProtected = address,
142-
ExternalAddressUnprotected = address
143-
}
144-
},
145-
Characters = new List<Character>
146-
{
147-
new Character
148-
{
149-
Name = filename,
150-
WorldId = 0
151-
}
152-
}
153-
}
154-
};
155-
156-
var response = Newtonsoft.Json.JsonConvert.SerializeObject(loginData);
170+
var response = "{\"session\":" +
171+
"{\"sessionkey\": null," +
172+
"\"lastlogintime\": 0," +
173+
"\"ispremium\": false," +
174+
"\"premiumuntil\": 0," +
175+
"\"status\": null," +
176+
"\"returnernotification\": false," +
177+
"\"showrewardnews\": false," +
178+
"\"isreturner\": false," +
179+
"\"fpstracking\": false," +
180+
"\"optiontracking\": false}" +
181+
",\"playdata\":" +
182+
"{\"worlds\":" +
183+
"[{\"id\": 0," +
184+
"\"name\": \"" + OxWorldName + "\"," +
185+
"\"externaladdressprotected\": \"" + address + "\"," +
186+
"\"externalportprotected\": " + port + "," +
187+
"\"externaladdressunprotected\": \"" + address + "\"," +
188+
"\"externalportunprotected\": " + port + "," +
189+
"\"previewstate\": 0," +
190+
"\"location\": null," +
191+
"\"anticheatprotection\": false," +
192+
"\"pvptype\": 0}]" +
193+
",\"characters\":" +
194+
"[{\"worldid\": 0," +
195+
"\"name\": \"" + filename + "\"," +
196+
"\"level\": 0," +
197+
"\"vocation\": null," +
198+
"\"ismale\": false," +
199+
"\"ishidden\": false," +
200+
"\"tutorial\": false," +
201+
"\"outfitid\": 0," +
202+
"\"headcolor\": 0," +
203+
"\"torsocolor\": 0," +
204+
"\"legscolor\": 0," +
205+
"\"detailcolor\": 0," +
206+
"\"addonsflags\": 0}]" +
207+
"}" +
208+
"}";
157209

158210
var data = Encoding.UTF8.GetBytes(response);
159211
context.Response.ContentLength64 = data.Length;
@@ -162,9 +214,6 @@ static void BeginGetContextCallback(IAsyncResult ar)
162214

163215
_httpListener.BeginGetContext(new AsyncCallback(BeginGetContextCallback), _httpListener);
164216
}
165-
catch (ObjectDisposedException)
166-
{
167-
}
168217
catch (Exception ex)
169218
{
170219
Console.WriteLine(ex);
@@ -335,13 +384,11 @@ static void PlayRecording()
335384

336385
Thread.Sleep((int)(timestamp - lastTimestamp));
337386
lastTimestamp = timestamp;
387+
Console.WriteLine($"Sending packet at {reader.BaseStream.Position}:{reader.BaseStream.Length}");
338388
SendToClient(message);
339389
}
340390
}
341391
}
342-
catch (SocketException)
343-
{
344-
}
345392
catch (Exception ex)
346393
{
347394
Console.WriteLine(ex);

TibiaAPI/Client.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public Client(string tibiaDirectory = "")
3838
Proxy = new Network.Connection(this);
3939
}
4040

41-
public bool StartProxy(bool enablePacketParsing = true)
41+
public bool StartProxy(bool enablePacketParsing = true, int httpPort = 80)
4242
{
43-
return Proxy.Start(enablePacketParsing);
43+
return Proxy.Start(enablePacketParsing, httpPort);
4444
}
4545

4646
public void StopProxy()
@@ -55,7 +55,8 @@ private bool Initialize(string tibiaDirectory = "")
5555
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
5656
{
5757
tibiaDirectory = Path.Combine(new string[] {
58-
"~", ".local", "share", "CipSoft GmbH", "Tibia", "packages", "Tibia" });
58+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
59+
"CipSoft GmbH", "Tibia", "packages", "Tibia" });
5960
}
6061
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
6162
{

TibiaAPI/Network/Connection.cs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ public class Connection : Communication, IDisposable
4646

4747
private ZStream _zStream = new ZStream();
4848

49-
private LoginData _loginData;
5049

5150
private Socket _clientSocket;
5251
private Socket _serverSocket;
@@ -56,6 +55,8 @@ public class Connection : Communication, IDisposable
5655

5756
private TcpListener _tcpListener;
5857

58+
private dynamic _loginData;
59+
5960
private uint _clientSequenceNumber = 1;
6061
private uint _serverSequenceNumber = 1;
6162

@@ -247,7 +248,7 @@ public void SendToServer(byte[] data)
247248
/// connection requests from the Tibia client.
248249
/// </summary>
249250
/// <returns></returns>
250-
internal bool Start(bool enablePacketParsing = true)
251+
internal bool Start(bool enablePacketParsing = true, int httpPort = 80)
251252
{
252253
if (_isStarted)
253254
{
@@ -261,11 +262,10 @@ internal bool Start(bool enablePacketParsing = true)
261262
_tcpListener = new TcpListener(IPAddress.Loopback, 0);
262263
}
263264

264-
if (!_httpListener.Prefixes.Contains("http://127.0.0.1:80/"))
265+
var uriPrefix = $"http://127.0.0.1:{httpPort}/";
266+
if (!_httpListener.Prefixes.Contains(uriPrefix))
265267
{
266-
// The HTTP listener must be listening on port 80 as the
267-
// Tibia client sends HTTP requests over port 80.
268-
_httpListener.Prefixes.Add("http://127.0.0.1:80/");
268+
_httpListener.Prefixes.Add(uriPrefix);
269269
}
270270

271271
//_zStream.deflateInit(zlibConst.Z_DEFAULT_COMPRESSION, -15);
@@ -544,24 +544,24 @@ private void BeginGetContextCallback(IAsyncResult ar)
544544
}
545545

546546
// Login data is the only thing we have to modify, everything else can be piped through.
547-
var loginData = JsonConvert.DeserializeObject<LoginData>(response);
548-
if (loginData != null && loginData.Session != null)
547+
dynamic loginData = JsonConvert.DeserializeObject(response);
548+
if (loginData != null && loginData.session != null)
549549
{
550550
// Change the address and port of each game world to that of the TCP listener so that
551551
// the Tibia client connects to the TCP listener instead of a game world.
552552
var address = ((IPEndPoint)_tcpListener.LocalEndpoint).Address.ToString();
553553
var port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
554-
foreach (var world in loginData.PlayData.Worlds)
554+
foreach (var world in loginData.playdata.worlds)
555555
{
556-
world.ExternalAddressProtected = address;
557-
world.ExternalAddressUnprotected = address;
558-
world.ExternalPortProtected = port;
559-
world.ExternalPortUnprotected = port;
556+
world.externaladdressprotected = address;
557+
world.externaladdressunprotected = address;
558+
world.externalportprotected = port;
559+
world.externalportunprotected = port;
560560
}
561561

562562
// Store the original login data so when the Tibia client tries to connect to a game world
563563
// the server socket can recall the address and port to connect to.
564-
_loginData = JsonConvert.DeserializeObject<LoginData>(response);
564+
_loginData = JsonConvert.DeserializeObject(response);
565565
response = JsonConvert.SerializeObject(loginData);
566566
}
567567

@@ -653,18 +653,22 @@ private void BeginReceiveWorldNameCallback(IAsyncResult ar)
653653
}
654654

655655
var worldName = Encoding.UTF8.GetString(_clientInMessage.GetBuffer(), 0, count - 1);
656-
var world = _loginData.PlayData.Worlds.Find(w => w.Name.Equals(worldName, StringComparison.CurrentCultureIgnoreCase));
657-
if (world == null)
656+
foreach (var world in _loginData.playdata.worlds)
658657
{
659-
throw new Exception($"[Connection.BeginReceiveWorldNameCallback] Login data not found for world: {worldName}.");
660-
}
658+
var name = (string)world.name;
659+
if (name.Equals(worldName, StringComparison.CurrentCultureIgnoreCase))
660+
{
661+
_clientSocket.BeginReceive(_clientInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveClientCallback), 0);
661662

662-
_clientSocket.BeginReceive(_clientInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveClientCallback), 0);
663+
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
664+
_serverSocket.Connect((string)world.externaladdressprotected, (int)world.externalportprotected);
665+
_serverSocket.Send(_clientInMessage.GetBuffer(), 0, count, SocketFlags.None);
666+
_serverSocket.BeginReceive(_serverInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveServerCallback), 0);
667+
return;
668+
}
669+
}
663670

664-
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
665-
_serverSocket.Connect(world.ExternalAddressProtected, world.ExternalPortProtected);
666-
_serverSocket.Send(_clientInMessage.GetBuffer(), 0, count, SocketFlags.None);
667-
_serverSocket.BeginReceive(_serverInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveServerCallback), 0);
671+
throw new Exception($"[Connection.BeginReceiveWorldNameCallback] Login data not found for world: {worldName}.");
668672
}
669673
catch (SocketException)
670674
{

0 commit comments

Comments
 (0)