sodoff-mmo/src/Core/SWRacing.cs
2026-09-03 10:34:22 -07:00

261 lines
7.6 KiB
C#

using sodoffmmo.Data;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Text;
namespace sodoffmmo.Core
{
public class SWRacingRoom : Room
{
class SWPlayerState
{
public int Index;
public Vector3 PosTransform = new();
public string Token = "";
public bool IsHost;
public bool IsReady;
public bool SceneLoaded;
public bool CountdownFinished;
public int ColorIndex;
public string VehicleResName = "";
public int CurrentLap;
public float FinishedTime = -1f;
public bool IsTrackPrebuilt;
public int TrackIdx;
public string TrackStatus = "ZR";
}
public SWRacingRoom() : base(null, "ShipWreckMPRoom", true)
{
}
public bool CountdownStarted { get; set; } = false;
public bool RaceOngoing { get; set; } = false;
public bool BuddiesOnly { get; set; } = false;
Dictionary<Client, SWPlayerState> Players = new();
Client? host = null;
int nextIndex = 1;
public void AddPlayer(Client client)
{
lock (roomLock)
{
var state = new SWPlayerState { Index = nextIndex++ };
if(host is null)
{
host = client;
state.IsHost = true;
}
Players[client] = state;
}
}
public int GetIndex(Client client)
{
lock (roomLock)
{
var state = Players[client];
return state.Index;
}
}
public int GetReadyCount()
{
lock (roomLock)
{
int readyCount = 0;
foreach(var (client, s) in Players)
{
if (s.IsReady)
readyCount++;
}
return readyCount;
}
}
public IEnumerable<int> GetPlayersWithinRadius(Vector3 blast, float hitRadius, Client? excluding)
{
lock (roomLock)
{
float targetRadiusSquared = hitRadius * hitRadius;
List<int> targetedPlayers = [];
foreach(var player in Players)
{
if (player.Key.ClientID == excluding?.ClientID) continue;
if (Vector3.DistanceSquared(player.Value.PosTransform, blast) < targetRadiusSquared)
targetedPlayers.Add(player.Value.Index);
}
return targetedPlayers;
}
}
public void SetPlayerPosition(Client client, float X, float Y, float Z)
{
lock (roomLock)
{
var state = Players[client];
state.PosTransform.X = X;
state.PosTransform.Y = Y;
state.PosTransform.Z = Z;
}
}
public void SetReady(Client client, bool ready)
{
lock (roomLock)
{
var state = Players[client];
state.IsReady = ready;
}
}
public void SetTrack(Client client, int trackId)
{
lock (roomLock)
{
var state = Players[client];
state.TrackIdx = trackId;
}
}
public void SetTrackStatus(Client client, string statusCode)
{
lock (roomLock)
{
var state = Players[client];
state.TrackStatus = statusCode;
}
}
public void SetIsPrebuiltTrack(Client client, bool isPrebuiltTrack)
{
lock (roomLock)
{
var state = Players[client];
state.IsTrackPrebuilt = isPrebuiltTrack;
}
}
public void SetBoat(Client client, string boatRes, int colorIndex = 0)
{
lock (roomLock)
{
var state = Players[client];
state.VehicleResName = boatRes;
state.ColorIndex = colorIndex;
}
}
public void SetToken(Client client, string token)
{
lock (roomLock)
{
var state = Players[client];
state.Token = token;
}
}
public bool SetSceneLoaded(Client client)
{
lock (roomLock)
{
Players[client].SceneLoaded = true;
foreach (var (_, s) in Players)
if (!s.SceneLoaded) return false;
return true;
}
}
public bool SetCountdownFinished(Client client)
{
lock (roomLock)
{
Players[client].CountdownFinished = true;
foreach (var (_, s) in Players)
if (!s.CountdownFinished) return false;
return true;
}
}
public void SetPlayerLap(Client client, int lap)
{
lock (roomLock)
{
var state = Players[client];
state.CurrentLap = lap;
}
}
public void SetFinishedTime(Client client, float time)
{
lock (roomLock)
{
var state = Players[client];
state.FinishedTime = time;
}
}
public NetworkPacket GetAMPacket()
{
List<string> info = [ "AM" ];
foreach(var (client, s) in Players)
{
info.Add(s.IsHost ? "ZJ" : "");
info.Add(client.PlayerData.UNToken);
info.Add(s.Index.ToString());
info.Add(s.ColorIndex.ToString());
info.Add(s.VehicleResName);
info.Add(s.IsReady ? "AN" : "");
info.Add(s.IsTrackPrebuilt ? "ZP" : "ZQ");
info.Add(s.TrackIdx.ToString());
info.Add(s.TrackStatus);
}
string joined = string.Join("|", info);
return Utils.ArrNetworkPacket(["AM", joined], "", Id);
}
System.Timers.Timer? countdownTimer;
int lobbyCounter;
public void TryStartLobbyCountdown()
{
Console.WriteLine($"Attempted To Start SWL Lobby Countdown On SWL {Id}. Player Count - {Players.Count}");
lock (roomLock)
{
if (Players.Count <= 1) return; // this is multiplayers, don't just start a singleplayer time trial lmao
if (CountdownStarted || GetReadyCount() < Players.Count) return;
string joined = string.Join("|", "AB", Players.Count.ToString(), "3");
Send(Utils.ArrNetworkPacket([joined], "", Id));
CountdownStarted = true;
Console.WriteLine($"Countdown Started On SWL {Id}");
}
lobbyCounter = 3;
countdownTimer = new(1000) { AutoReset = true };
countdownTimer.Elapsed += TickLobbyCountdown;
countdownTimer.Enabled = true;
}
private void TickLobbyCountdown(object? sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine($"Lobby Countdown Tick TS - {DateTime.Now}");
if(--lobbyCounter <= 0)
{
countdownTimer!.Stop();
string joined = string.Join("|", "ZH", lobbyCounter.ToString());
Send(Utils.ArrNetworkPacket([joined], "", Id));
RaceOngoing = true;
}
}
}
}