Skip to content

Commit e3a4cd1

Browse files
committed
Fix ss13 Playercounts
1 parent 9140bb1 commit e3a4cd1

File tree

1 file changed

+22
-114
lines changed

1 file changed

+22
-114
lines changed

SS14.Launcher/Models/ServerStatus/ClassicServerListCache.cs

Lines changed: 22 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.Net.Http;
66
using System.Threading;
77
using System.Threading.Tasks;
8+
using System.Net.Http.Json;
9+
using System.Text.Json.Serialization;
810
using Serilog;
911
using Splat;
1012
using SS14.Launcher.Utility;
@@ -28,8 +30,10 @@ public async Task Refresh()
2830
{
2931
try
3032
{
31-
var response = await _http.GetStringAsync("http://www.byond.com/games/exadv1/spacestation13?format=text");
32-
var servers = ParseByondResponse(response);
33+
var hubResponse = await _http.GetFromJsonAsync<GoonhubHubResponse>("https://node.goonhub.com/hub");
34+
if (hubResponse == null) return;
35+
36+
var servers = ParseGoonhubResponse(hubResponse);
3337

3438
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
3539
{
@@ -46,101 +50,17 @@ public async Task Refresh()
4650
}
4751
}
4852

49-
private List<ClassicServerStatusData> ParseByondResponse(string response)
53+
private List<ClassicServerStatusData> ParseGoonhubResponse(GoonhubHubResponse hubResponse)
5054
{
5155
var list = new List<ClassicServerStatusData>();
52-
using var reader = new StringReader(response);
53-
54-
string? line;
55-
string? currentName = null;
56-
string? currentUrl = null;
57-
string? currentStatus = null;
58-
int currentPlayers = 0;
59-
60-
// Simple state machine to parse the text format
61-
// The format uses 'world/ID' blocks for servers.
62-
63-
bool inServerBlock = false;
64-
65-
while ((line = reader.ReadLine()) != null)
66-
{
67-
var trimmed = line.Trim();
68-
if (string.IsNullOrWhiteSpace(trimmed)) continue;
69-
70-
if (trimmed.StartsWith("world/"))
71-
{
72-
// If we were parsing a server, save it
73-
if (inServerBlock && currentUrl != null)
74-
{
75-
// Name might be missing, try to extract from status or use URL
76-
var name = currentName ?? ExtractNameFromStatus(currentStatus) ?? "Unknown Server";
77-
var roundTime = ExtractRoundTimeFromStatus(currentStatus);
78-
list.Add(new ClassicServerStatusData(name, currentUrl, currentPlayers, CleanStatus(currentStatus, name) ?? "", roundTime ?? "In-Lobby"));
79-
}
80-
81-
// Reset for new server
82-
inServerBlock = true;
83-
currentName = null;
84-
currentUrl = null;
85-
currentStatus = null;
86-
currentPlayers = 0;
87-
}
88-
else if (inServerBlock)
89-
{
90-
if (trimmed.StartsWith("name ="))
91-
{
92-
currentName = ParseStringValue(trimmed);
93-
}
94-
else if (trimmed.StartsWith("url ="))
95-
{
96-
currentUrl = ParseStringValue(trimmed);
97-
}
98-
else if (trimmed.StartsWith("status ="))
99-
{
100-
currentStatus = ParseStringValue(trimmed);
101-
}
102-
else if (trimmed.StartsWith("players = list("))
103-
{
104-
// "players = list("Bob","Alice")"
105-
// Just count the commas + 1, correcting for empty list "list()"
106-
var content = trimmed.Substring("players = list(".Length);
107-
if (content.EndsWith(")"))
108-
{
109-
content = content.Substring(0, content.Length - 1);
110-
if (string.IsNullOrWhiteSpace(content))
111-
{
112-
currentPlayers = 0;
113-
}
114-
else
115-
{
116-
// A simple Count(',') + 1 is risky if names contain commas, but usually they are quoted.
117-
// However, parsing full CSV is safer but 'Splitting by ",' might be enough?
118-
// Let's iterate and count quoted segments.
119-
// Or simpler: Splitting by ',' is mostly fine for SS13 ckeys.
120-
currentPlayers = content.Split(',').Length;
121-
}
122-
}
123-
}
124-
else if (trimmed.StartsWith("players ="))
125-
{
126-
// Fallback for simple number if ever used
127-
var parts = trimmed.Split('=');
128-
if (parts.Length > 1 && int.TryParse(parts[1].Trim(), out var p))
129-
{
130-
currentPlayers = p;
131-
}
132-
}
133-
}
134-
}
135-
136-
// Add the last one if exists
137-
if (inServerBlock && currentUrl != null)
56+
foreach (var server in hubResponse.Response)
13857
{
139-
var name = currentName ?? ExtractNameFromStatus(currentStatus) ?? "Unknown Server";
140-
var roundTime = ExtractRoundTimeFromStatus(currentStatus);
141-
list.Add(new ClassicServerStatusData(name, currentUrl, currentPlayers, CleanStatus(currentStatus, name) ?? "", roundTime ?? "In-Lobby"));
58+
var name = ExtractNameFromStatus(server.Status) ?? "Unknown Server";
59+
var roundTime = ExtractRoundTimeFromStatus(server.Status) ?? "In-Lobby";
60+
var address = $"byond://BYOND.world.{server.UrlId}";
61+
62+
list.Add(new ClassicServerStatusData(name, address, server.Players, CleanStatus(server.Status, name) ?? "", roundTime));
14263
}
143-
14464
return list;
14565
}
14666

@@ -199,27 +119,15 @@ private List<ClassicServerStatusData> ParseByondResponse(string response)
199119
return s;
200120
}
201121

202-
private string ParseStringValue(string line)
122+
private sealed class GoonhubHubResponse
123+
{
124+
[JsonPropertyName("response")] public List<GoonhubServerEntry> Response { get; set; } = new();
125+
}
126+
127+
private sealed class GoonhubServerEntry
203128
{
204-
// format: key = "value"
205-
var idx = line.IndexOf('"');
206-
if (idx == -1) return string.Empty;
207-
var lastIdx = line.LastIndexOf('"');
208-
if (lastIdx <= idx) return string.Empty;
209-
210-
// Extract content inside quotes
211-
var inner = line.Substring(idx + 1, lastIdx - idx - 1);
212-
213-
// Unescape BYOND/C string escapes
214-
// \" -> "
215-
// \n -> newline
216-
// \\ -> \
217-
// The most critical one is \n showing up as literal \n in UI.
218-
219-
// Simple manual unescape for common sequences
220-
return inner.Replace("\\\"", "\"")
221-
.Replace("\\n", "\n")
222-
.Replace("\\\\", "\\")
223-
.Replace("\\t", "\t");
129+
[JsonPropertyName("urlId")] public string UrlId { get; set; } = "";
130+
[JsonPropertyName("players")] public int Players { get; set; }
131+
[JsonPropertyName("status")] public string Status { get; set; } = "";
224132
}
225133
}

0 commit comments

Comments
 (0)