feat: Add metro transit, gadgets, shop, social apps, and traffic models checkpoint

This commit is contained in:
CAtlas0784 committed 2026-10-29 01:55:01 +07:00
1 parent caa42b84ed
commit 74e2963a12
79 files changed
+527962 -496

No files matched your search

+52 -18
View File
@@ -175,6 +175,8 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub
await WriteJsonAsync(ctx, ItemCatalogList(ctx.Request.QueryString), token);
else if (method == "POST" && (path == "/api/item/give" || path == "/api/player/give-item"))
await WriteJsonAsync(ctx, await GiveItemAsync(await ReadBodyAsync(ctx.Request, token), token), token);
else if (method == "POST" && path == "/api/gacha/grant-tickets")
await WriteJsonAsync(ctx, await GachaGrantTicketsAsync(token), token);
else if (method == "POST" && (path == "/api/armory/equip" || path == "/api/weapon/equip"))
await WriteJsonAsync(ctx, await WeaponEquipAsync(await ReadBodyAsync(ctx.Request, token), token), token);
else
@@ -706,26 +708,14 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub
new { id = "animal", label = "🐱 Animals & Pets (สัตว์/เป็ด/แมว)" },
new { id = "ally", label = "🤝 Allies & Story (พันธมิตร/ตัวละคร)" },
},
poiActions = new[]
{
new { id = 0, name = "🧍 Auto / None (ไม่ระบุท่า)" },
new { id = 2, name = "🧍 Idle (ยืนนิ่ง)" },
new { id = 1, name = "🚶 Walk (เดิน)" },
new { id = 4, name = "🏃 Run (วิ่ง)" },
new { id = 11, name = "📱 Phone / Camera (คุยโทรศัพท์/ถ่ายรูป)" },
new { id = 10, name = "🧱 Lean on Wall (พิงกำแพง)" },
new { id = 12, name = "🪑 Formal Sit (นั่งเก้าอี้เรียบร้อย)" },
new { id = 13, name = "🪑 Relaxed Sit (นั่งเก้าอี้ผ่อนคลาย)" },
new { id = 15, name = "💬 Sit & Talk (นั่งคุย)" },
new { id = 6, name = "👏 Clapping (ปรบมือ)" },
new { id = 5, name = "👀 Spectating (ยืนมุงดู)" },
new { id = 3, name = "😱 Scared / Panicking (ตกใจกลัว)" },
new { id = 8, name = "🥤 Vending Machine (กดตู้ขายน้ำ)" }
},
poiActions = PoiActionCatalog4229938.All()
.OrderBy(e => e.Id)
.Select(e => new { id = e.Id, name = string.IsNullOrWhiteSpace(e.Name) ? $"POI {e.Id}" : NameTranslator.PoiAction(e.Name) })
.ToList(),
items = entries.Select(e => new
{
id = e.Id,
name = string.IsNullOrWhiteSpace(e.Name) ? $"Agent_{e.Id}" : e.Name,
name = string.IsNullOrWhiteSpace(e.Name) ? $"Agent_{e.Id}" : NameTranslator.Agent(e.Name),
category = e.Category,
model = e.GeneralModelId,
camp = e.Camp,
@@ -1549,6 +1539,31 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub
CityTrafficEngine.Instance.TargetDensity = Math.Clamp(den.GetInt32(), 0, 100);
if (root.TryGetProperty("speedScale", out var spd))
CityTrafficEngine.Instance.SpeedScale = Math.Clamp((float)spd.GetDouble(), 0.1f, 5.0f);
if (root.TryGetProperty("moveReset", out var mr) && (mr.ValueKind == JsonValueKind.True || mr.ValueKind == JsonValueKind.False))
{
TrafficAndCrowdDriver.VehicleMoveReset = mr.GetBoolean();
Console.WriteLine($"[TRAFFIC] vehicle move channel: SyncTeleportVehicle reset={TrafficAndCrowdDriver.VehicleMoveReset}");
}
if (root.TryGetProperty("useAetherProtocol", out var ua) && (ua.ValueKind == JsonValueKind.True || ua.ValueKind == JsonValueKind.False))
{
CityTrafficEngine.Instance.UseAetherProtocol = ua.GetBoolean();
Console.WriteLine($"[TRAFFIC] protocol: {(ua.GetBoolean() ? "Aether client-driven (lane sync)" : "legacy scene-entity streaming")}");
}
if (root.TryGetProperty("serverVehicles", out var sv) && (sv.ValueKind == JsonValueKind.True || sv.ValueKind == JsonValueKind.False))
{
CityTrafficEngine.Instance.ServerSpawnedVehicles = sv.GetBoolean();
Console.WriteLine($"[TRAFFIC] server-spawned Aether vehicles: {sv.GetBoolean()}");
}
if (root.TryGetProperty("ambientIntersections", out var ai) && (ai.ValueKind == JsonValueKind.True || ai.ValueKind == JsonValueKind.False))
{
CityTrafficEngine.Instance.AmbientIntersectionInit = ai.GetBoolean();
Console.WriteLine($"[TRAFFIC] ambient intersection init: {ai.GetBoolean()} (takes effect on next world entry)");
}
if (root.TryGetProperty("timestampMode", out var tm) && tm.TryGetInt32(out var mode))
{
CityTrafficEngine.Instance.AetherTimestampMode = Math.Clamp(mode, 0, 2);
Console.WriteLine($"[TRAFFIC] aether timestamp mode: {CityTrafficEngine.Instance.AetherTimestampMode} (0=unix, 1=unix×15, 2=session seconds)");
}
return Task.FromResult<object>(new { ok = true, status = CityTrafficEngine.Instance.GetStatus() });
}
catch (Exception ex)
@@ -1639,9 +1654,28 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub
};
}
private async Task<object> GiveItemAsync(string json, CancellationToken token)
/// <summary>Debug panel: grants every gacha ticket item so any pool can be opened.</summary>
private async Task<object> GachaGrantTicketsAsync(CancellationToken token)
{
var session = hub.Current;
if (session is null)
return new { ok = false, error = "no active game session" };
var results = new List<object>();
var granted = 0;
foreach (var ticketId in EconomyConfigRepository.GachaTicketItemIds())
{
var result = await GameRouter.PanelGiveItemAsync(session, ticketId, 99, false);
if (result.Ok)
granted++;
results.Add(new { ticketId, ok = result.Ok, message = result.Message });
}
return new { ok = granted > 0, granted, results };
}
private async Task<object> GiveItemAsync(string json, CancellationToken token)
{ var session = hub.Current;
if (session is null)
return new { ok = false, error = "no live game session (is the client in the world?)" };