Review fixes: telemetry session id per login; Framework number text
F1: the telemetry session id is new at every login. The original made one per load of its assembly and its loader reloaded it at every login; the backend counts new kills per (session id, character), so reusing one id across a relog under-counted kills until the reset counter passed the old total. F5/F6: .NET Framework never wrote a negative zero, and its fixed-point formats (F7, F2, F0) rounded at fifteen significant digits, half away from zero. Spawn and portal coordinates, kills_per_hour and the !report line now format that way; the round-trip converter maps -0 to 0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b5371c2e4
commit
71f14473c6
10 changed files with 157 additions and 10 deletions
|
|
@ -59,6 +59,7 @@ static async Task<int> Record(int port, string outPath)
|
|||
{
|
||||
var buffer = new byte[65536];
|
||||
using var message = new MemoryStream();
|
||||
string? name = null;
|
||||
try
|
||||
{
|
||||
while (ws.WebSocket.State == WebSocketState.Open && !cts.IsCancellationRequested)
|
||||
|
|
@ -71,6 +72,7 @@ static async Task<int> Record(int port, string outPath)
|
|||
continue;
|
||||
string frame = Encoding.UTF8.GetString(message.ToArray());
|
||||
message.SetLength(0);
|
||||
name = await Relay.Handle(frame, ws.WebSocket, name);
|
||||
await writeLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
|
|
@ -86,6 +88,7 @@ static async Task<int> Record(int port, string outPath)
|
|||
catch (Exception ex) when (ex is OperationCanceledException or WebSocketException)
|
||||
{
|
||||
}
|
||||
Relay.Disconnected(name);
|
||||
Console.WriteLine("client disconnected");
|
||||
});
|
||||
}
|
||||
|
|
@ -170,3 +173,82 @@ static bool IsDataMap(string name) => name is "monsters" or "properties" or "ski
|
|||
or "vitals" or "IntValues" or "DoubleValues" or "BoolValues" or "StringValues" or "offense" or "defense";
|
||||
|
||||
static bool LooksLikeData(string key) => key.Length > 0 && (char.IsDigit(key[0]) || key.Contains(' '));
|
||||
|
||||
// The backend's vital-sharing relay: a client registers under its character
|
||||
// name; share_subscribe / share_unsubscribe opt it in and out; every other
|
||||
// share_* frame goes to every other opted-in client, unchanged.
|
||||
static class Relay
|
||||
{
|
||||
private static readonly object Gate = new();
|
||||
private static readonly Dictionary<string, WebSocket> Clients = new(StringComparer.Ordinal);
|
||||
private static readonly HashSet<string> Subscribers = new(StringComparer.Ordinal);
|
||||
|
||||
public static async Task<string?> Handle(string frame, WebSocket socket, string? name)
|
||||
{
|
||||
string? type;
|
||||
string? character;
|
||||
try
|
||||
{
|
||||
using JsonDocument doc = JsonDocument.Parse(frame);
|
||||
JsonElement root = doc.RootElement;
|
||||
type = root.TryGetProperty("type", out JsonElement t) ? t.GetString() : null;
|
||||
character = root.TryGetProperty("character_name", out JsonElement c) ? c.GetString()
|
||||
: root.TryGetProperty("player_name", out JsonElement p) ? p.GetString() : null;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
List<WebSocket> targets = [];
|
||||
lock (Gate)
|
||||
{
|
||||
if (type == "register" && character is not null)
|
||||
{
|
||||
Clients[character] = socket;
|
||||
return character;
|
||||
}
|
||||
if (type == "share_subscribe" && character is not null)
|
||||
{
|
||||
Subscribers.Add(character);
|
||||
return name;
|
||||
}
|
||||
if (type == "share_unsubscribe" && character is not null)
|
||||
{
|
||||
Subscribers.Remove(character);
|
||||
return name;
|
||||
}
|
||||
if (type is null || !type.StartsWith("share_", StringComparison.Ordinal))
|
||||
return name;
|
||||
foreach ((string client, WebSocket other) in Clients)
|
||||
{
|
||||
if (client != character && Subscribers.Contains(client) && other.State == WebSocketState.Open)
|
||||
targets.Add(other);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(frame);
|
||||
foreach (WebSocket target in targets)
|
||||
{
|
||||
try
|
||||
{
|
||||
await target.SendAsync(bytes, WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
catch (WebSocketException)
|
||||
{
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static void Disconnected(string? name)
|
||||
{
|
||||
if (name is null)
|
||||
return;
|
||||
lock (Gate)
|
||||
{
|
||||
Clients.Remove(name);
|
||||
Subscribers.Remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue