mirror of
https://github.com/Empostor/Empostor.git
synced 2026-10-19 15:51:39 +00:00
This commit is contained in:
1 parent
4e4f87a0a7
commit
3888bfa7ee
32 files changed
+1059
-126
No files matched your search
@@ -5,5 +5,7 @@
|
||||
"Reactor": "ReactorSystemType",
|
||||
"LifeSupp": "LifeSuppSystemType",
|
||||
"Ventilation": "VentilationSystem",
|
||||
"Decontamination": "DeconSystem",
|
||||
"Decontamination2": "DeconSystem",
|
||||
"Sabotage": "SabotageSystemType"
|
||||
}
|
||||
@@ -6,5 +6,7 @@
|
||||
"Security": "SecurityCameraSystemType",
|
||||
"Ventilation": "VentilationSystem",
|
||||
"Laboratory": "ReactorSystemType",
|
||||
"Decontamination": "DeconSystem",
|
||||
"Decontamination2": "DeconSystem",
|
||||
"Sabotage": "SabotageSystemType"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Threading.Tasks;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
using Empostor.Api.Net.Inner.Objects.ShipStatus;
|
||||
|
||||
namespace Empostor.Api.Net.Custom
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles custom <see cref="IInnerShipStatus" /> system state and update payloads.
|
||||
/// </summary>
|
||||
public interface ICustomSystemType : ICustomMessage
|
||||
{
|
||||
ValueTask DeserializeAsync(IInnerShipStatus shipStatus, IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState);
|
||||
|
||||
ValueTask<bool> HandleUpdateSystemAsync(IInnerShipStatus shipStatus, IInnerPlayerControl? playerControl, IClientPlayer sender, IClientPlayer? target, IMessageReader reader);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,11 @@ public static class MessageWriterExtensions
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this IMessageWriter writer, IMessageWriter message, bool includeHeader)
|
||||
{
|
||||
writer.Write(message.ToByteArray(includeHeader));
|
||||
}
|
||||
|
||||
public static void Write(this IMessageWriter writer, Vector2 vector)
|
||||
{
|
||||
writer.Write((ushort)(Mathf.ReverseLerp(vector.X) * (double)ushort.MaxValue));
|
||||
|
||||
@@ -6,22 +6,27 @@ namespace Empostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc35UpdateSystem
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, SystemTypes systemType, IInnerPlayerControl playerControl, ushort sequenceId, byte state, byte ventId)
|
||||
public static void Serialize(IMessageWriter writer, SystemTypes systemType, IInnerPlayerControl playerControl, IMessageWriter payload)
|
||||
{
|
||||
writer.Write((byte)systemType);
|
||||
writer.Write(playerControl);
|
||||
writer.Write(sequenceId);
|
||||
writer.Write(state);
|
||||
writer.Write(ventId);
|
||||
writer.Write(payload, false);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out SystemTypes systemType, out IInnerPlayerControl? playerControl, out ushort sequenceId, out byte state, out byte ventId)
|
||||
public static void Serialize(IMessageWriter writer, SystemTypes systemType, IInnerPlayerControl playerControl, byte amount)
|
||||
{
|
||||
writer.Write((byte)systemType);
|
||||
writer.Write(playerControl);
|
||||
writer.Write(amount);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out SystemTypes systemType, out IInnerPlayerControl? playerControl, out IMessageReader payload)
|
||||
{
|
||||
systemType = (SystemTypes)reader.ReadByte();
|
||||
playerControl = reader.ReadNetObject<IInnerPlayerControl>(game);
|
||||
sequenceId = reader.ReadUInt16();
|
||||
state = reader.ReadByte();
|
||||
ventId = reader.ReadByte();
|
||||
|
||||
// The system payload is appended directly with Write(payload, false); it is not a nested message.
|
||||
payload = reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,9 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerAirshipStatus : InnerShipStatus, IInnerAirshipStatus
|
||||
{
|
||||
public InnerAirshipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.Airship)
|
||||
public InnerAirshipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.Airship)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
public Vector2 PreSpawnLocation { get; } = new Vector2(-25f, 40f);
|
||||
@@ -35,13 +36,14 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.GapRoom, new MovingPlatformBehaviour());
|
||||
systems.Add(SystemTypes.Reactor, new HeliSabotageSystemType());
|
||||
systems.Add(SystemTypes.Decontamination, new ElectricalDoors(Doors));
|
||||
systems.Add(SystemTypes.Decontamination2, new AutoDoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.HeliSabotage, new HeliSabotageSystemType());
|
||||
systems.Add(SystemTypes.Decontamination, new ElectricalDoors());
|
||||
systems.Add(SystemTypes.Decontamination2, new AutoDoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.Security, new SecurityCameraSystemType());
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,21 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerDleksShipStatus : InnerShipStatus, IInnerDleksShipStatus
|
||||
{
|
||||
public InnerDleksShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.Dleks)
|
||||
public InnerDleksShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.Dleks)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
protected override void AddSystems(Dictionary<SystemTypes, ISystemType> systems)
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Doors, new AutoDoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.Doors, new AutoDoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.Security, new SecurityCameraSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType());
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType(30f, SystemTypes.Reactor));
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType(30f));
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,17 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerFungleShipStatus : InnerShipStatus
|
||||
{
|
||||
public InnerFungleShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.Fungle)
|
||||
public InnerFungleShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.Fungle)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
protected override void AddSystems(Dictionary<SystemTypes, ISystemType> systems)
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType());
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
systems.Add(SystemTypes.Comms, new HqHudSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType(60f, SystemTypes.Reactor));
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.MushroomMixupSabotage, new MushroomMixupSabotageSystemType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,21 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerMiraShipStatus : InnerShipStatus, IInnerMiraShipStatus
|
||||
{
|
||||
public InnerMiraShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.MiraHQ)
|
||||
public InnerMiraShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.MiraHQ)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
protected override void AddSystems(Dictionary<SystemTypes, ISystemType> systems)
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType());
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType());
|
||||
systems.Add(SystemTypes.Comms, new HqHudSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType(45f, SystemTypes.Reactor));
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType(45f));
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
systems.Add(SystemTypes.Decontamination, new DeconSystemType());
|
||||
systems.Add(SystemTypes.Decontamination2, new DeconSystemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,9 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerPolusShipStatus : InnerShipStatus, IInnerPolusShipStatus
|
||||
{
|
||||
public InnerPolusShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.Polus)
|
||||
public InnerPolusShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.Polus)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn)
|
||||
@@ -37,10 +38,13 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.Security, new SecurityCameraSystemType());
|
||||
systems.Add(SystemTypes.Laboratory, new ReactorSystemType());
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
systems.Add(SystemTypes.Laboratory, new ReactorSystemType(60f, SystemTypes.Laboratory));
|
||||
systems.Add(SystemTypes.Decontamination, new DeconSystemType());
|
||||
systems.Add(SystemTypes.Decontamination2, new DeconSystemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Empostor.Api.Innersloth.Maps;
|
||||
using Empostor.Api.Net;
|
||||
using Empostor.Api.Net.Custom;
|
||||
using Empostor.Api.Net.Inner;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
using Empostor.Api.Net.Inner.Objects.ShipStatus;
|
||||
using Empostor.Api.Net.Messages.Rpcs;
|
||||
using Empostor.Server.Net.Inner.Objects.Systems;
|
||||
@@ -18,10 +19,13 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal abstract class InnerShipStatus : InnerNetObject, IInnerShipStatus
|
||||
{
|
||||
private readonly ICustomMessageManager<ICustomSystemType> _customSystemManager;
|
||||
private readonly Dictionary<SystemTypes, ISystemType> _systems = new Dictionary<SystemTypes, ISystemType>();
|
||||
|
||||
protected InnerShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, MapTypes mapType) : base(customMessageManager, game)
|
||||
protected InnerShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game, MapTypes mapType) : base(customMessageManager, game)
|
||||
{
|
||||
_customSystemManager = customSystemManager;
|
||||
|
||||
Components.Add(this);
|
||||
|
||||
MapType = mapType;
|
||||
@@ -35,22 +39,21 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
|
||||
public Dictionary<int, bool> Doors { get; }
|
||||
|
||||
internal override ValueTask OnSpawnAsync()
|
||||
{
|
||||
for (var i = 0; i < Doors.Count; i++)
|
||||
{
|
||||
Doors.Add(i, false);
|
||||
}
|
||||
|
||||
AddSystems(_systems);
|
||||
_systems.Add(SystemTypes.Sabotage, new SabotageSystemType(_systems.Values.OfType<IActivatable>().ToArray()));
|
||||
|
||||
return base.OnSpawnAsync();
|
||||
}
|
||||
|
||||
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var result = false;
|
||||
foreach (var systemType in SystemTypeHelpers.AllTypes)
|
||||
{
|
||||
if (_systems.TryGetValue(systemType, out var value))
|
||||
{
|
||||
result = true;
|
||||
writer.StartMessage((byte)systemType);
|
||||
value.Serialize(writer, initialState);
|
||||
writer.EndMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return new ValueTask<bool>(result);
|
||||
}
|
||||
|
||||
public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
|
||||
@@ -62,12 +65,16 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var messageReader = reader.ReadMessage();
|
||||
using var messageReader = reader.ReadMessage();
|
||||
var type = (SystemTypes)messageReader.Tag;
|
||||
if (_systems.TryGetValue(type, out var value))
|
||||
{
|
||||
value.Deserialize(messageReader, initialState);
|
||||
}
|
||||
else if (_customSystemManager.TryGet(messageReader.Tag, out var customSystem))
|
||||
{
|
||||
await customSystem.DeserializeAsync(this, sender, target, messageReader, initialState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +91,7 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
}
|
||||
|
||||
Rpc27CloseDoorsOfType.Deserialize(reader, out var systemType);
|
||||
CloseDoorsOfType(systemType);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -94,8 +102,20 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: properly deserialize this RPC
|
||||
// Rpc35UpdateSystem.Deserialize(reader, Game, out var systemType, out var playerControl, out var sequenceId, out var state, out var ventId);
|
||||
Rpc35UpdateSystem.Deserialize(reader, Game, out var systemType, out var playerControl, out var payload);
|
||||
if (_systems.TryGetValue(systemType, out var system))
|
||||
{
|
||||
system.UpdateSystem(playerControl, payload);
|
||||
}
|
||||
else if (_customSystemManager.TryGet((byte)systemType, out var customSystem))
|
||||
{
|
||||
return await customSystem.HandleUpdateSystemAsync(this, playerControl, sender, target, payload);
|
||||
}
|
||||
else if (await sender.Client.ReportCheatAsync(call, CheatCategory.ProtocolExtension, $"Client sent unregistered system type {(byte)systemType}"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -143,6 +163,58 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
systems.Add(SystemTypes.MedBay, new MedScanSystem());
|
||||
}
|
||||
|
||||
protected void InitializeSystems()
|
||||
{
|
||||
for (var i = 0; i < Data.Doors.Count; i++)
|
||||
{
|
||||
Doors[i] = true;
|
||||
}
|
||||
|
||||
AddSystems(_systems);
|
||||
_systems.Add(SystemTypes.Sabotage, new SabotageSystemType(_systems.Values.OfType<IActivatable>().ToArray(), UpdateSystem));
|
||||
}
|
||||
|
||||
protected void UpdateSystem(IInnerPlayerControl? playerControl, SystemTypes systemType, byte amount)
|
||||
{
|
||||
if (!_systems.TryGetValue(systemType, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (system)
|
||||
{
|
||||
case SwitchSystem switchSystem:
|
||||
switchSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case ReactorSystemType reactorSystem:
|
||||
reactorSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case LifeSuppSystemType lifeSuppSystem:
|
||||
lifeSuppSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case HudOverrideSystemType hudOverrideSystem:
|
||||
hudOverrideSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case HqHudSystemType hqHudSystem:
|
||||
hqHudSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case HeliSabotageSystemType heliSabotageSystem:
|
||||
heliSabotageSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
case MushroomMixupSabotageSystemType mushroomMixupSabotageSystem:
|
||||
mushroomMixupSabotageSystem.UpdateSystem(playerControl, amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void CloseDoorsOfType(SystemTypes room)
|
||||
{
|
||||
if (_systems.TryGetValue(SystemTypes.Doors, out var system) && system is IDoorSystem doorSystem)
|
||||
{
|
||||
doorSystem.CloseDoorsOfType(room);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2 Rotate(Vector2 self, float degrees)
|
||||
{
|
||||
var f = 0.017453292f * degrees;
|
||||
|
||||
@@ -9,19 +9,21 @@ namespace Empostor.Server.Net.Inner.Objects.ShipStatus
|
||||
{
|
||||
internal class InnerSkeldShipStatus : InnerShipStatus, IInnerSkeldShipStatus
|
||||
{
|
||||
public InnerSkeldShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, Game game) : base(customMessageManager, game, MapTypes.Skeld)
|
||||
public InnerSkeldShipStatus(ICustomMessageManager<ICustomRpc> customMessageManager, ICustomMessageManager<ICustomSystemType> customSystemManager, Game game) : base(customMessageManager, customSystemManager, game, MapTypes.Skeld)
|
||||
{
|
||||
InitializeSystems();
|
||||
}
|
||||
|
||||
protected override void AddSystems(Dictionary<SystemTypes, ISystemType> systems)
|
||||
{
|
||||
base.AddSystems(systems);
|
||||
|
||||
systems.Add(SystemTypes.Doors, new AutoDoorsSystemType(Doors));
|
||||
systems.Add(SystemTypes.Doors, new AutoDoorsSystemType(Doors, Data.Doors));
|
||||
systems.Add(SystemTypes.Comms, new HudOverrideSystemType());
|
||||
systems.Add(SystemTypes.Security, new SecurityCameraSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType());
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType());
|
||||
systems.Add(SystemTypes.Reactor, new ReactorSystemType(30f, SystemTypes.Reactor));
|
||||
systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType(30f));
|
||||
systems.Add(SystemTypes.Ventilation, new VentilationSystemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems
|
||||
{
|
||||
public interface ISystemType
|
||||
{
|
||||
void Serialize(IMessageWriter writer, bool initialState);
|
||||
|
||||
void Deserialize(IMessageReader reader, bool initialState);
|
||||
|
||||
void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems
|
||||
{
|
||||
internal sealed class SequenceBuffer<T>
|
||||
{
|
||||
private readonly List<SequencedData> _buffer = new();
|
||||
|
||||
public SequenceBuffer(ushort sidStart = 0)
|
||||
{
|
||||
LastSid = sidStart;
|
||||
}
|
||||
|
||||
public ushort LastSid { get; set; }
|
||||
|
||||
public void Add(ushort sid, T info)
|
||||
{
|
||||
_buffer.Add(new SequencedData(sid, info));
|
||||
}
|
||||
|
||||
public void BumpSid()
|
||||
{
|
||||
LastSid++;
|
||||
}
|
||||
|
||||
public bool IsInvalidSid(ushort sid)
|
||||
{
|
||||
return !SidGreaterThan(sid, LastSid);
|
||||
}
|
||||
|
||||
public bool IsNextSid(ushort sid)
|
||||
{
|
||||
return sid == (ushort)(LastSid + 1);
|
||||
}
|
||||
|
||||
public IEnumerable<T> SubsequentObjs()
|
||||
{
|
||||
_buffer.Sort();
|
||||
while (_buffer.Count > 0 && IsNextSid(_buffer[0].Sid))
|
||||
{
|
||||
var result = _buffer[0].Data;
|
||||
_buffer.RemoveAt(0);
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool SidGreaterThan(ushort newSid, ushort prevSid)
|
||||
{
|
||||
var num = (ushort)(prevSid + (uint)short.MaxValue);
|
||||
|
||||
return (int)prevSid < (int)num
|
||||
? newSid > prevSid && newSid <= num
|
||||
: newSid > prevSid || newSid <= num;
|
||||
}
|
||||
|
||||
private readonly struct SequencedData : IComparable<SequencedData>
|
||||
{
|
||||
public SequencedData(ushort sid, T data)
|
||||
{
|
||||
Sid = sid;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public ushort Sid { get; }
|
||||
|
||||
public T Data { get; }
|
||||
|
||||
public int CompareTo(SequencedData other)
|
||||
{
|
||||
return Sid.CompareTo(other.Sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Empostor.Api.Innersloth.Maps;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class AutoDoorsSystemType : ISystemType
|
||||
public class AutoDoorsSystemType : ISystemType, IDoorSystem
|
||||
{
|
||||
private readonly Dictionary<int, bool> _doors;
|
||||
private readonly IReadOnlyDictionary<int, DoorData> _doorData;
|
||||
private uint _dirtyBits;
|
||||
|
||||
public AutoDoorsSystemType(Dictionary<int, bool> doors)
|
||||
public AutoDoorsSystemType(Dictionary<int, bool> doors, IReadOnlyDictionary<int, DoorData> doorData)
|
||||
{
|
||||
_doors = doors;
|
||||
_doorData = doorData;
|
||||
}
|
||||
|
||||
public bool IsActive => _doors.Values.Any(open => !open);
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (initialState)
|
||||
{
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
writer.Write(_doors[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePacked(_dirtyBits);
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
if ((_dirtyBits & (uint)(1 << i)) != 0)
|
||||
{
|
||||
writer.Write(_doors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -32,12 +56,28 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
if ((num & 1 << i) != 0)
|
||||
if ((num & (uint)(1 << i)) != 0)
|
||||
{
|
||||
_doors[i] = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
}
|
||||
|
||||
public void CloseDoorsOfType(SystemTypes room)
|
||||
{
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
if (_doorData.TryGetValue(i, out var door) && door.Room == room)
|
||||
{
|
||||
_doors[i] = false;
|
||||
_dirtyBits |= (uint)(1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class DeconSystemType : ISystemType
|
||||
{
|
||||
private const byte HeadUpCommand = 1;
|
||||
private const byte HeadDownCommand = 2;
|
||||
private const byte HeadUpInsideCommand = 3;
|
||||
private const byte HeadDownInsideCommand = 4;
|
||||
|
||||
public enum States : byte
|
||||
{
|
||||
Idle = 0,
|
||||
Enter = 1,
|
||||
Closed = 2,
|
||||
Exit = 4,
|
||||
HeadingUp = 8,
|
||||
}
|
||||
|
||||
public byte Timer { get; private set; }
|
||||
|
||||
public States CurState { get; private set; }
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
writer.Write(Timer);
|
||||
writer.Write((byte)CurState);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
Timer = reader.ReadByte();
|
||||
CurState = (States)reader.ReadByte();
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
if (CurState != States.Idle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reader.ReadByte())
|
||||
{
|
||||
case HeadUpCommand:
|
||||
CurState = States.Enter | States.HeadingUp;
|
||||
Timer = 3;
|
||||
break;
|
||||
case HeadDownCommand:
|
||||
CurState = States.Enter;
|
||||
Timer = 3;
|
||||
break;
|
||||
case HeadUpInsideCommand:
|
||||
CurState = States.Exit | States.HeadingUp;
|
||||
Timer = 3;
|
||||
break;
|
||||
case HeadDownInsideCommand:
|
||||
CurState = States.Exit;
|
||||
Timer = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Innersloth.Maps;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class DoorsSystemType : ISystemType
|
||||
public class DoorsSystemType : ISystemType, IDoorSystem
|
||||
{
|
||||
private readonly Dictionary<SystemTypes, float> _timers = new Dictionary<SystemTypes, float>();
|
||||
private readonly Dictionary<SystemTypes, float> _timers = new();
|
||||
private readonly Dictionary<int, bool> _doors;
|
||||
private readonly IReadOnlyDictionary<int, DoorData> _doorData;
|
||||
|
||||
public DoorsSystemType(Dictionary<int, bool> doors)
|
||||
public DoorsSystemType(Dictionary<int, bool> doors, IReadOnlyDictionary<int, DoorData> doorData)
|
||||
{
|
||||
_doors = doors;
|
||||
_doorData = doorData;
|
||||
}
|
||||
|
||||
public bool IsActive => false;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write((byte)_timers.Count);
|
||||
foreach (var timer in _timers)
|
||||
{
|
||||
writer.Write((byte)timer.Key);
|
||||
writer.Write(timer.Value);
|
||||
}
|
||||
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
writer.Write(_doors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -34,5 +49,28 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
_doors[j] = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
var value = reader.ReadByte();
|
||||
var doorId = value & 0x1f;
|
||||
if ((value & 0xc0) == 0x40 && _doors.ContainsKey(doorId))
|
||||
{
|
||||
_doors[doorId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseDoorsOfType(SystemTypes room)
|
||||
{
|
||||
_timers[room] = 30f;
|
||||
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
if (_doorData.TryGetValue(i, out var door) && door.Room == room)
|
||||
{
|
||||
_doors[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class ElectricalDoors : ISystemType
|
||||
{
|
||||
private readonly Dictionary<int, bool> _doors;
|
||||
|
||||
public ElectricalDoors(Dictionary<int, bool> doors)
|
||||
{
|
||||
_doors = doors;
|
||||
}
|
||||
private uint _state;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(_state);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
var num = reader.ReadUInt32();
|
||||
for (var i = 0; i < _doors.Count; i++)
|
||||
{
|
||||
_doors[i] = (num & (ulong)(1L << (i & 31))) > 0UL;
|
||||
}
|
||||
_state = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
-13
@@ -1,52 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class HeliSabotageSystemType : ISystemType, IActivatable
|
||||
{
|
||||
private readonly HashSet<ActiveConsoleData> _activeConsoles = new();
|
||||
private readonly HashSet<byte> _completedConsoles = new();
|
||||
|
||||
public HeliSabotageSystemType()
|
||||
{
|
||||
Countdown = 10000f;
|
||||
ActiveConsoles = new HashSet<Tuple<byte, byte>>();
|
||||
CompletedConsoles = new HashSet<byte>();
|
||||
_completedConsoles.Add(0);
|
||||
_completedConsoles.Add(1);
|
||||
}
|
||||
|
||||
public float Countdown { get; private set; }
|
||||
|
||||
public float Timer { get; private set; }
|
||||
|
||||
public HashSet<Tuple<byte, byte>> ActiveConsoles { get; }
|
||||
|
||||
public HashSet<byte> CompletedConsoles { get; }
|
||||
|
||||
public bool IsActive => Countdown < 10000.0;
|
||||
public bool IsActive => _completedConsoles.Count < 2;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(Countdown);
|
||||
writer.Write(Timer);
|
||||
|
||||
writer.WritePacked(_activeConsoles.Count);
|
||||
foreach (var activeConsole in _activeConsoles)
|
||||
{
|
||||
writer.Write(activeConsole.PlayerId);
|
||||
writer.Write(activeConsole.ConsoleId);
|
||||
}
|
||||
|
||||
writer.WritePacked(_completedConsoles.Count);
|
||||
foreach (var completedConsole in _completedConsoles)
|
||||
{
|
||||
writer.Write(completedConsole);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
Countdown = reader.ReadSingle();
|
||||
Timer = reader.ReadSingle();
|
||||
ActiveConsoles.Clear(); // TODO: Thread safety
|
||||
CompletedConsoles.Clear(); // TODO: Thread safety
|
||||
_activeConsoles.Clear();
|
||||
_completedConsoles.Clear();
|
||||
|
||||
var activeCount = reader.ReadPackedUInt32();
|
||||
|
||||
for (var i = 0; i < activeCount; i++)
|
||||
{
|
||||
ActiveConsoles.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
|
||||
_activeConsoles.Add(new ActiveConsoleData(reader.ReadByte(), reader.ReadByte()));
|
||||
}
|
||||
|
||||
var completedCount = reader.ReadPackedUInt32();
|
||||
|
||||
for (var i = 0; i < completedCount; i++)
|
||||
{
|
||||
CompletedConsoles.Add(reader.ReadByte());
|
||||
_completedConsoles.Add(reader.ReadByte());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var value = amount;
|
||||
var consoleId = (byte)(value & 0x0f);
|
||||
|
||||
switch (value & 0xf0)
|
||||
{
|
||||
case 0x80:
|
||||
Timer = -1f;
|
||||
Countdown = 90f;
|
||||
_completedConsoles.Clear();
|
||||
_activeConsoles.Clear();
|
||||
break;
|
||||
case 0x40 when playerControl != null:
|
||||
_activeConsoles.Add(new ActiveConsoleData(playerControl.PlayerId, consoleId));
|
||||
break;
|
||||
case 0x20 when playerControl != null:
|
||||
_activeConsoles.Remove(new ActiveConsoleData(playerControl.PlayerId, consoleId));
|
||||
break;
|
||||
case 0x10:
|
||||
Timer = 10f;
|
||||
_completedConsoles.Add(consoleId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly record struct ActiveConsoleData(byte PlayerId, byte ConsoleId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class HqHudSystemType : ISystemType, IActivatable
|
||||
{
|
||||
private readonly HashSet<Tuple<byte, byte>> _activeConsoles = new();
|
||||
private readonly HashSet<byte> _completedConsoles = new();
|
||||
|
||||
public HqHudSystemType()
|
||||
{
|
||||
_completedConsoles.Add(0);
|
||||
_completedConsoles.Add(1);
|
||||
}
|
||||
|
||||
public float Timer { get; private set; }
|
||||
|
||||
public bool IsActive => _completedConsoles.Count < 2;
|
||||
|
||||
public float NumComplete => _completedConsoles.Count;
|
||||
|
||||
public float PercentActive => Timer / 10f;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
writer.WritePacked(_activeConsoles.Count);
|
||||
foreach (var activeConsole in _activeConsoles)
|
||||
{
|
||||
writer.Write(activeConsole.Item1);
|
||||
writer.Write(activeConsole.Item2);
|
||||
}
|
||||
|
||||
writer.WritePacked(_completedConsoles.Count);
|
||||
foreach (var completedConsole in _completedConsoles)
|
||||
{
|
||||
writer.Write(completedConsole);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
_activeConsoles.Clear();
|
||||
var activeCount = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < activeCount; i++)
|
||||
{
|
||||
_activeConsoles.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
|
||||
}
|
||||
|
||||
_completedConsoles.Clear();
|
||||
var completedCount = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < completedCount; i++)
|
||||
{
|
||||
_completedConsoles.Add(reader.ReadByte());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var value = amount;
|
||||
var consoleId = (byte)(value & 0x0f);
|
||||
|
||||
switch (value & 0xf0)
|
||||
{
|
||||
case 0x80:
|
||||
Timer = -1f;
|
||||
_completedConsoles.Clear();
|
||||
_activeConsoles.Clear();
|
||||
break;
|
||||
case 0x40 when playerControl != null:
|
||||
_activeConsoles.Add(new Tuple<byte, byte>(playerControl.PlayerId, consoleId));
|
||||
break;
|
||||
case 0x20 when playerControl != null:
|
||||
_activeConsoles.Remove(new Tuple<byte, byte>(playerControl.PlayerId, consoleId));
|
||||
break;
|
||||
case 0x10:
|
||||
Timer = 10f;
|
||||
_completedConsoles.Add(consoleId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsConsoleActive(int consoleId)
|
||||
{
|
||||
return _activeConsoles.Any(x => x.Item2 == (byte)consoleId);
|
||||
}
|
||||
|
||||
internal bool IsConsoleOkay(int consoleId)
|
||||
{
|
||||
return _completedConsoles.Contains((byte)consoleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
@@ -8,12 +8,22 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(IsActive);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
IsActive = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
IsActive = (amount & 0x80) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public interface IDoorSystem : IActivatable
|
||||
{
|
||||
void CloseDoorsOfType(SystemTypes room);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class LifeSuppSystemType : ISystemType, IActivatable
|
||||
{
|
||||
public LifeSuppSystemType()
|
||||
private readonly float _lifeSuppDuration;
|
||||
|
||||
public LifeSuppSystemType(float lifeSuppDuration = 30f)
|
||||
{
|
||||
_lifeSuppDuration = lifeSuppDuration;
|
||||
Countdown = 10000f;
|
||||
CompletedConsoles = new HashSet<int>();
|
||||
}
|
||||
@@ -15,11 +18,16 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
|
||||
public HashSet<int> CompletedConsoles { get; }
|
||||
|
||||
public bool IsActive => Countdown < 10000.0;
|
||||
public bool IsActive => Countdown < 10000.0f;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(Countdown);
|
||||
writer.WritePacked(CompletedConsoles.Count);
|
||||
foreach (var consoleId in CompletedConsoles)
|
||||
{
|
||||
writer.WritePacked(consoleId);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -31,7 +39,7 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
return;
|
||||
}
|
||||
|
||||
CompletedConsoles.Clear(); // TODO: Thread safety
|
||||
CompletedConsoles.Clear();
|
||||
|
||||
var num = reader.ReadPackedInt32();
|
||||
|
||||
@@ -40,5 +48,34 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
CompletedConsoles.Add(reader.ReadPackedInt32());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var value = amount;
|
||||
var consoleId = value & 3;
|
||||
|
||||
if (value == 0x80 && !IsActive)
|
||||
{
|
||||
Countdown = _lifeSuppDuration;
|
||||
CompletedConsoles.Clear();
|
||||
}
|
||||
else if (value == 0x10)
|
||||
{
|
||||
Countdown = 10000f;
|
||||
}
|
||||
else if ((value & 0x40) != 0)
|
||||
{
|
||||
CompletedConsoles.Add(consoleId);
|
||||
if (CompletedConsoles.Count >= 2)
|
||||
{
|
||||
Countdown = 10000f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
@@ -12,9 +12,15 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
|
||||
public List<byte> UsersList { get; }
|
||||
|
||||
public byte CurrentUser { get; private set; } = byte.MaxValue;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.WritePacked(UsersList.Count);
|
||||
foreach (var user in UsersList)
|
||||
{
|
||||
writer.Write(user);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -28,5 +34,26 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
UsersList.Add(reader.ReadByte());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
var value = reader.ReadByte();
|
||||
var playerId = (byte)(value & 0x1f);
|
||||
if ((value & 0x80) != 0)
|
||||
{
|
||||
if (!UsersList.Contains(playerId))
|
||||
{
|
||||
UsersList.Add(playerId);
|
||||
}
|
||||
}
|
||||
else if ((value & 0x40) != 0)
|
||||
{
|
||||
UsersList.RemoveAll(x => x == playerId);
|
||||
if (CurrentUser == playerId)
|
||||
{
|
||||
CurrentUser = byte.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-7
@@ -1,21 +1,55 @@
|
||||
using System;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class MovingPlatformBehaviour : ISystemType, IActivatable
|
||||
public class MovingPlatformBehaviour : ISystemType
|
||||
{
|
||||
public bool IsActive { get; private set; }
|
||||
private byte _useId;
|
||||
|
||||
public uint TargetNetId { get; private set; } = uint.MaxValue;
|
||||
|
||||
public bool IsLeft { get; private set; } = true;
|
||||
|
||||
public bool InUse => TargetNetId != uint.MaxValue;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_useId++;
|
||||
writer.Write(_useId);
|
||||
writer.Write(TargetNetId);
|
||||
writer.Write(IsLeft);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
var sid = reader.ReadByte();
|
||||
var targetId = reader.ReadUInt32();
|
||||
var isLeft = reader.ReadBoolean();
|
||||
if (initialState)
|
||||
{
|
||||
_useId = reader.ReadByte();
|
||||
TargetNetId = reader.ReadUInt32();
|
||||
IsLeft = reader.ReadBoolean();
|
||||
return;
|
||||
}
|
||||
|
||||
var newSid = reader.ReadByte();
|
||||
if (SidGreaterThan(newSid, _useId))
|
||||
{
|
||||
_useId = newSid;
|
||||
TargetNetId = reader.ReadUInt32();
|
||||
IsLeft = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
}
|
||||
|
||||
private static bool SidGreaterThan(byte newSid, byte prevSid)
|
||||
{
|
||||
var num = (byte)(prevSid + sbyte.MaxValue);
|
||||
|
||||
return prevSid < num
|
||||
? newSid > prevSid && newSid <= num
|
||||
: newSid > prevSid || newSid <= num;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-2
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus;
|
||||
|
||||
public class MushroomMixupSabotageSystemType : ISystemType
|
||||
public class MushroomMixupSabotageSystemType : ISystemType, IActivatable
|
||||
{
|
||||
private readonly Dictionary<byte, CondensedOutfit> _currentMixups = new();
|
||||
private State _currentState;
|
||||
@@ -15,6 +16,8 @@ public class MushroomMixupSabotageSystemType : ISystemType
|
||||
IdleButMixedUp,
|
||||
}
|
||||
|
||||
public bool IsActive => _currentSecondsUntilHeal > 0f;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
writer.Write((byte)_currentState);
|
||||
@@ -26,6 +29,11 @@ public class MushroomMixupSabotageSystemType : ISystemType
|
||||
writer.Write(playerId);
|
||||
outfit.Serialize(writer);
|
||||
}
|
||||
|
||||
if (_currentState == State.JustTriggered)
|
||||
{
|
||||
_currentState = State.IdleButMixedUp;
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -40,7 +48,22 @@ public class MushroomMixupSabotageSystemType : ISystemType
|
||||
var playerId = reader.ReadByte();
|
||||
var outfit = CondensedOutfit.Deserialize(reader);
|
||||
|
||||
_currentMixups.Add(playerId, outfit);
|
||||
_currentMixups[playerId] = outfit;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var operation = amount;
|
||||
if (operation == 1)
|
||||
{
|
||||
_currentMixups.Clear();
|
||||
_currentState = State.JustTriggered;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class ReactorSystemType : ISystemType, IActivatable
|
||||
{
|
||||
public ReactorSystemType()
|
||||
private readonly float _reactorDuration;
|
||||
|
||||
public ReactorSystemType(float reactorDuration = 30f, SystemTypes system = SystemTypes.Reactor)
|
||||
{
|
||||
_reactorDuration = reactorDuration;
|
||||
System = system;
|
||||
Countdown = 10000f;
|
||||
UserConsolePairs = new HashSet<Tuple<byte, byte>>();
|
||||
}
|
||||
|
||||
public SystemTypes System { get; }
|
||||
|
||||
public float Countdown { get; private set; }
|
||||
|
||||
public HashSet<Tuple<byte, byte>> UserConsolePairs { get; }
|
||||
|
||||
public bool IsActive => Countdown < 10000.0;
|
||||
public bool IsActive => Countdown < 10000.0f;
|
||||
|
||||
public int UserCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = 0;
|
||||
var consoles = 0;
|
||||
foreach (var pair in UserConsolePairs)
|
||||
{
|
||||
var bit = 1 << pair.Item2;
|
||||
if ((bit & consoles) == 0)
|
||||
{
|
||||
result++;
|
||||
consoles |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(Countdown);
|
||||
writer.WritePacked(UserConsolePairs.Count);
|
||||
foreach (var pair in UserConsolePairs)
|
||||
{
|
||||
writer.Write(pair.Item1);
|
||||
writer.Write(pair.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
Countdown = reader.ReadSingle();
|
||||
UserConsolePairs.Clear(); // TODO: Thread safety
|
||||
UserConsolePairs.Clear();
|
||||
|
||||
var count = reader.ReadPackedInt32();
|
||||
|
||||
@@ -34,5 +68,43 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
UserConsolePairs.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var value = amount;
|
||||
var consoleId = (byte)(value & 3);
|
||||
|
||||
if (value == 0x80 && !IsActive)
|
||||
{
|
||||
Countdown = _reactorDuration;
|
||||
UserConsolePairs.Clear();
|
||||
}
|
||||
else if (value == 0x10)
|
||||
{
|
||||
Countdown = 10000f;
|
||||
}
|
||||
else if ((value & 0x40) != 0 && playerControl != null)
|
||||
{
|
||||
UserConsolePairs.Add(new Tuple<byte, byte>(playerControl.PlayerId, consoleId));
|
||||
if (UserCount >= 2)
|
||||
{
|
||||
Countdown = 10000f;
|
||||
}
|
||||
}
|
||||
else if ((value & 0x20) != 0 && playerControl != null)
|
||||
{
|
||||
UserConsolePairs.Remove(new Tuple<byte, byte>(playerControl.PlayerId, consoleId));
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetConsoleComplete(int consoleId)
|
||||
{
|
||||
return UserConsolePairs.Any(x => x.Item2 == consoleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,69 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class SabotageSystemType : ISystemType
|
||||
{
|
||||
private readonly IActivatable[] _specials;
|
||||
private readonly Action<IInnerPlayerControl?, SystemTypes, byte> _updateSystem;
|
||||
|
||||
public SabotageSystemType(IActivatable[] specials)
|
||||
public SabotageSystemType(IActivatable[] specials, Action<IInnerPlayerControl?, SystemTypes, byte> updateSystem)
|
||||
{
|
||||
_specials = specials;
|
||||
_specials = specials.Where(x => x is not IDoorSystem).ToArray();
|
||||
_updateSystem = updateSystem;
|
||||
}
|
||||
|
||||
public float Timer { get; set; }
|
||||
public float Timer { get; private set; }
|
||||
|
||||
public bool AnyActive => _specials.Any(x => x.IsActive);
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(Timer);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
Timer = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
if (Timer > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var systemType = (SystemTypes)reader.ReadByte();
|
||||
switch (systemType)
|
||||
{
|
||||
case SystemTypes.Laboratory:
|
||||
case SystemTypes.Reactor:
|
||||
case SystemTypes.HeliSabotage:
|
||||
case SystemTypes.LifeSupp:
|
||||
case SystemTypes.Comms:
|
||||
_updateSystem(playerControl, systemType, 0x80);
|
||||
break;
|
||||
case SystemTypes.Electrical:
|
||||
var value = (byte)4;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
if (Random.Shared.Next(2) == 0)
|
||||
{
|
||||
value |= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
_updateSystem(playerControl, systemType, (byte)(value | 0x80));
|
||||
break;
|
||||
case SystemTypes.MushroomMixupSabotage:
|
||||
_updateSystem(playerControl, systemType, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
Timer = 30f;
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
-4
@@ -1,19 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class SecurityCameraSystemType : ISystemType
|
||||
{
|
||||
public byte InUse { get; internal set; }
|
||||
private readonly HashSet<byte> _playersUsing = new();
|
||||
|
||||
public bool InUse => _playersUsing.Count > 0;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.WritePacked(_playersUsing.Count);
|
||||
foreach (var playerId in _playersUsing)
|
||||
{
|
||||
writer.Write(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
InUse = reader.ReadByte();
|
||||
_playersUsing.Clear();
|
||||
var num = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < num; i++)
|
||||
{
|
||||
_playersUsing.Add(reader.ReadByte());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
if (playerControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (reader.ReadByte() == 1)
|
||||
{
|
||||
_playersUsing.Add(playerControl.PlayerId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_playersUsing.Remove(playerControl.PlayerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
@@ -10,11 +10,13 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
|
||||
public byte Value { get; set; } = byte.MaxValue;
|
||||
|
||||
public bool IsActive { get; }
|
||||
public bool IsActive => ExpectedSwitches != ActualSwitches;
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(ExpectedSwitches);
|
||||
writer.Write(ActualSwitches);
|
||||
writer.Write(Value);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
@@ -23,5 +25,23 @@ namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
ActualSwitches = reader.ReadByte();
|
||||
Value = reader.ReadByte();
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
UpdateSystem(playerControl, reader.ReadByte());
|
||||
}
|
||||
|
||||
internal void UpdateSystem(IInnerPlayerControl? playerControl, byte amount)
|
||||
{
|
||||
var value = amount;
|
||||
if ((value & 0x80) != 0)
|
||||
{
|
||||
ActualSwitches ^= (byte)(value & 0x1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ActualSwitches ^= (byte)(1 << value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Empostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Empostor.Server.Net.Inner.Objects.Systems.ShipStatus
|
||||
{
|
||||
public class VentilationSystemType : ISystemType
|
||||
{
|
||||
private readonly Dictionary<byte, SequenceBuffer<VentMoveInfo>> _sequenceBuffers = new();
|
||||
private readonly Dictionary<byte, byte> _playersCleaningVents = new();
|
||||
private readonly Dictionary<byte, byte> _playersInsideVents = new();
|
||||
|
||||
public enum Operation : byte
|
||||
{
|
||||
StartCleaning,
|
||||
StopCleaning,
|
||||
Enter,
|
||||
Exit,
|
||||
Move,
|
||||
BootImpostors,
|
||||
}
|
||||
|
||||
public void Serialize(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
writer.WritePacked(_playersCleaningVents.Count);
|
||||
foreach (var pair in _playersCleaningVents)
|
||||
{
|
||||
writer.Write(pair.Key);
|
||||
writer.Write(pair.Value);
|
||||
}
|
||||
|
||||
writer.WritePacked(_playersInsideVents.Count);
|
||||
foreach (var pair in _playersInsideVents)
|
||||
{
|
||||
writer.Write(pair.Key);
|
||||
writer.Write(pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader, bool initialState)
|
||||
{
|
||||
_playersCleaningVents.Clear();
|
||||
var cleaningCount = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < cleaningCount; i++)
|
||||
{
|
||||
_playersCleaningVents[reader.ReadByte()] = reader.ReadByte();
|
||||
}
|
||||
|
||||
_playersInsideVents.Clear();
|
||||
var insideCount = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < insideCount; i++)
|
||||
{
|
||||
_playersInsideVents[reader.ReadByte()] = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSystem(IInnerPlayerControl? playerControl, IMessageReader reader)
|
||||
{
|
||||
if (playerControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var opId = reader.ReadUInt16();
|
||||
var operation = (Operation)reader.ReadByte();
|
||||
var ventId = reader.ReadByte();
|
||||
var playerId = playerControl.PlayerId;
|
||||
|
||||
if (!_sequenceBuffers.TryGetValue(playerId, out var sequenceBuffer))
|
||||
{
|
||||
sequenceBuffer = new SequenceBuffer<VentMoveInfo>((ushort)(opId - 1));
|
||||
_sequenceBuffers[playerId] = sequenceBuffer;
|
||||
}
|
||||
|
||||
if (sequenceBuffer.IsInvalidSid(opId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sequenceBuffer.IsNextSid(opId))
|
||||
{
|
||||
PerformVentOp(playerId, operation, ventId, sequenceBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
sequenceBuffer.Add(opId, new VentMoveInfo(operation, ventId, playerId));
|
||||
}
|
||||
|
||||
foreach (var info in sequenceBuffer.SubsequentObjs())
|
||||
{
|
||||
PerformVentOp(info.PlayerId, info.Op, info.VentId, sequenceBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVentCurrentlyBeingCleaned(int ventId)
|
||||
{
|
||||
return _playersCleaningVents.Any(x => x.Value == ventId);
|
||||
}
|
||||
|
||||
public bool IsImpostorInsideVent(int ventId)
|
||||
{
|
||||
return _playersInsideVents.Any(x => x.Value == ventId);
|
||||
}
|
||||
|
||||
private void PerformVentOp(byte playerId, Operation operation, byte ventId, SequenceBuffer<VentMoveInfo> sequenceBuffer)
|
||||
{
|
||||
sequenceBuffer.BumpSid();
|
||||
switch (operation)
|
||||
{
|
||||
case Operation.StartCleaning:
|
||||
BootImpostorsFromVent(ventId);
|
||||
_playersCleaningVents[playerId] = ventId;
|
||||
break;
|
||||
case Operation.StopCleaning:
|
||||
foreach (var pair in _playersCleaningVents.ToArray())
|
||||
{
|
||||
if (pair.Value == ventId)
|
||||
{
|
||||
_playersCleaningVents.Remove(pair.Key);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Operation.Enter:
|
||||
_playersInsideVents[playerId] = ventId;
|
||||
break;
|
||||
case Operation.Exit:
|
||||
_playersInsideVents.Remove(playerId);
|
||||
break;
|
||||
case Operation.Move:
|
||||
_playersInsideVents[playerId] = ventId;
|
||||
break;
|
||||
case Operation.BootImpostors:
|
||||
BootImpostorsFromVent(ventId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void BootImpostorsFromVent(byte ventId)
|
||||
{
|
||||
foreach (var pair in _playersInsideVents.ToArray())
|
||||
{
|
||||
if (pair.Value == ventId)
|
||||
{
|
||||
_playersInsideVents.Remove(pair.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly record struct VentMoveInfo(Operation Op, byte VentId, byte PlayerId);
|
||||
}
|
||||
}
|
||||
@@ -200,6 +200,7 @@ namespace Empostor.Server
|
||||
services.AddHazel();
|
||||
services.AddSingleton<ICustomMessageManager<ICustomRootMessage>, CustomMessageManager<ICustomRootMessage>>();
|
||||
services.AddSingleton<ICustomMessageManager<ICustomRpc>, CustomMessageManager<ICustomRpc>>();
|
||||
services.AddSingleton<ICustomMessageManager<ICustomSystemType>, CustomMessageManager<ICustomSystemType>>();
|
||||
services.AddSingleton<IMessageWriterProvider, MessageWriterProvider>();
|
||||
services.AddSingleton<IGameCodeFactory, GameCodeFactory>();
|
||||
services.AddSingleton<IEventManager, EventManager>();
|
||||
|
||||
Reference in new issue
Block a user