diff --git a/Ananta.Server/Ananta.App/DebugApiServer.cs b/Ananta.Server/Ananta.App/DebugApiServer.cs index c28bc86..42feb05 100644 --- a/Ananta.Server/Ananta.App/DebugApiServer.cs +++ b/Ananta.Server/Ananta.App/DebugApiServer.cs @@ -118,6 +118,8 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub await WriteJsonAsync(ctx, TimeStatus(), token); else if (method == "POST" && path == "/api/time/set") await WriteJsonAsync(ctx, await TimeSetAsync(await ReadBodyAsync(ctx.Request, token), token), token); + else if (method == "POST" && path == "/api/weather/set") + await WriteJsonAsync(ctx, await WeatherSetAsync(await ReadBodyAsync(ctx.Request, token), token), token); else if (method == "POST" && path == "/api/world/switch-scene") await WriteJsonAsync(ctx, await SwitchSceneAsync(await ReadBodyAsync(ctx.Request, token), token), token); else if (method == "POST" && path == "/api/unstuck/blackscreen") @@ -865,6 +867,41 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub return new { ok = true, hour, minute, fix }; } + private async Task WeatherSetAsync(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?)" }; + + uint weatherId = 1, transition = 5; + try + { + using var doc = JsonDocument.Parse(string.IsNullOrWhiteSpace(json) ? "{}" : json); + var root = doc.RootElement; + if (root.TryGetProperty("weatherId", out var pw)) + weatherId = pw.GetUInt32(); + if (root.TryGetProperty("transition", out var pt)) + transition = pt.GetUInt32(); + } + catch (Exception ex) + { + return new { ok = false, error = $"bad request: {ex.Message}" }; + } + + var state = GameRouter.GetStateIfExists(session); + if (state is null) + return new { ok = false, error = "no live game session (is the client in the world?)" }; + lock (state.SyncRoot) + { + state.WeatherId = weatherId; + state.WeatherTransitionSeconds = transition; + state.HasExplicitWeather = true; + } + await GameRouter.PushSessionWeatherAsync(session); + session.Log.Info($"[DEBUG-API] weather set id={weatherId} transition={transition}s"); + return new { ok = true, weatherId, transition }; + } + private async Task UnstuckBlackScreenAsync(CancellationToken token) { var session = hub.Current; diff --git a/Ananta.Server/Ananta.App/DebugPanel/index.html b/Ananta.Server/Ananta.App/DebugPanel/index.html index a593a40..171c601 100644 --- a/Ananta.Server/Ananta.App/DebugPanel/index.html +++ b/Ananta.Server/Ananta.App/DebugPanel/index.html @@ -39,6 +39,25 @@
00:00 — night  ·  06:00 — morning  ·  12:00 — noon  ·  18:00 — evening  ·  23:59 — night
+
+

Weather / Atmosphere (สภาพอากาศ)

+
+ + + + + + + +
+
+ Custom Weather ID: + Transition (sec): + +
+
ซิงค์สภาพอากาศของโลกและบรรยากาศ client ทันที
+
+

Garage (server vehicles)

@@ -425,6 +444,18 @@ async function toggleClothes() { log('toggle clothes: ' + JSON.stringify(r)); } +async function setWeather(weatherId) { + const transition = parseInt(document.getElementById('weatherTransition')?.value || '5', 10); + const body = { weatherId: parseInt(weatherId, 10), transition }; + const r = await api('/api/weather/set', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); + log('set weather: ' + JSON.stringify(r)); +} + +async function setCustomWeather() { + const id = parseInt(document.getElementById('customWeatherId').value || '1', 10); + await setWeather(id); +} + function onEnemyPresetChange() { const sel = document.getElementById('enemypreset').value; if (sel !== 'custom') {