Admin: spawn items (saved on the server), unban (menu tab + console), tabbed admin menu; dashboard needles and steering wheel synced; server browser row opens the profile

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 10:15:35 +02:00
co-authored by Claude Opus 5.5
parent ba396146f2
commit 85fbb8a3ce
5 changed files with 77 additions and 3 deletions
+21
View File
@@ -135,6 +135,24 @@ try
Check(spawn != null && Math.Abs(spawn[0] - 250f) < 0.01f && Math.Abs(spawn[2] + 120f) < 0.01f,
"Rejoining returns the last real position, not the save's start point or a flung-away one: " + (spawn == null ? "none" : string.Join(", ", spawn)));
pos2.Close();
Console.WriteLine("== Admin: spawn items / unban");
var noAdmin = await TestClient.Join("NoAdmin", 0, null);
var watcher = await TestClient.Join("Watcher", 0, null);
noAdmin.Send(MsgType.SpawnItem, Wire.Build(w => { w.Write("beer case"); w.Write(1f); w.Write(2f); w.Write(3f); w.Write(0f); w.Write(0f); w.Write(0f); w.Write(1f); }));
Check(await watcher.WaitFor(MsgType.SpawnItem, 800) == null, "Non-admin cannot spawn items (not relayed)");
watcher.Send(MsgType.Ready, Array.Empty<byte>());
Check(Snapshot.Parse(await watcher.WaitFor(MsgType.WorldSnapshot)).Spawns == 0, "Non-admin spawn is not stored");
server.EnqueueCommand("ban " + noAdmin.Id + " test");
await Task.Delay(500);
var bannedTry = await TestClient.Join("NoAdmin", 0, null, expectReject: true);
Check(bannedTry.RejectReason != null && bannedTry.RejectReason.Contains("banned"), "Banned player cannot join: " + bannedTry.RejectReason);
server.EnqueueCommand("unban name:noadmin");
await Task.Delay(500);
var unbanned = await TestClient.Join("NoAdmin", 0, null);
Check(unbanned.Welcome != null, "After unban the player can join again");
unbanned.Close();
watcher.Close();
}
catch (Exception e)
{
@@ -169,6 +187,7 @@ sealed class Snapshot
public string Info;
public HashSet<int> ObjectIds = new();
public float[] Spawn;
public int Spawns = -1;
public int Vars = -1;
public static Snapshot Parse(byte[] data)
@@ -188,6 +207,8 @@ sealed class Snapshot
for (int i = 0; i < doors; i++) { r.ReadString(); r.ReadString(); }
s.Vars = r.ReadInt32();
for (int i = 0; i < s.Vars; i++) { r.ReadInt32(); byte t = r.ReadByte(); r.ReadBytes(t == 3 ? 1 : 4); }
s.Spawns = r.ReadInt32();
for (int i = 0; i < s.Spawns; i++) r.ReadBytes(r.ReadInt32());
s.Ok = r.BaseStream.Position == r.BaseStream.Length;
s.Info = $"{objects} objects, {events} events, money {money}, {doors} doors, {s.Vars} vars";
}