Predict dumping (#32394)

* Predict dumping

- This got soaped really fucking hard.
- Dumping is predicted, this required disposals to be predicte.d
- Disposals required mailing (because it's tightly coupled), and a smidge of other content systems.
- I also had to fix a compnetworkgenerator issue at the same time so it wouldn't mispredict.

* Fix a bunch of stuff

* nasty merge

* Some reviews

* Some more reviews while I stash

* Fix merge

* Fix merge

* Half of review

* Review

* re(h)f

* lizards

* feexes

* feex
This commit is contained in:
metalgearsloth
2025-04-19 16:20:40 +10:00
committed by GitHub
parent f1f431e720
commit 63dfd21b14
140 changed files with 1655 additions and 1858 deletions

View File

@@ -1,126 +0,0 @@
using Content.Server.DeviceNetwork.Systems;
using Content.Shared.DeviceNetwork;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.DeviceNetwork.Components
{
[RegisterComponent]
[Access(typeof(DeviceNetworkSystem), typeof(DeviceNet))]
public sealed partial class DeviceNetworkComponent : Component
{
public enum DeviceNetIdDefaults
{
Private,
Wired,
Wireless,
Apc,
AtmosDevices,
Reserved = 100,
// Ids outside this enum may exist
// This exists to let yml use nice names instead of numbers
}
[DataField("deviceNetId")]
public DeviceNetIdDefaults NetIdEnum { get; set; }
public int DeviceNetId => (int) NetIdEnum;
/// <summary>
/// The frequency that this device is listening on.
/// </summary>
[DataField("receiveFrequency")]
public uint? ReceiveFrequency;
/// <summary>
/// frequency prototype. Used to select a default frequency to listen to on. Used when the map is
/// initialized.
/// </summary>
[DataField("receiveFrequencyId", customTypeSerializer: typeof(PrototypeIdSerializer<DeviceFrequencyPrototype>))]
public string? ReceiveFrequencyId;
/// <summary>
/// The frequency that this device going to try transmit on.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("transmitFrequency")]
public uint? TransmitFrequency;
/// <summary>
/// frequency prototype. Used to select a default frequency to transmit on. Used when the map is
/// initialized.
/// </summary>
[DataField("transmitFrequencyId", customTypeSerializer: typeof(PrototypeIdSerializer<DeviceFrequencyPrototype>))]
public string? TransmitFrequencyId;
/// <summary>
/// The address of the device, either on the network it is currently connected to or whatever address it
/// most recently used.
/// </summary>
[DataField("address")]
public string Address = string.Empty;
/// <summary>
/// If true, the address was customized and should be preserved across networks. If false, a randomly
/// generated address will be created whenever this device connects to a network.
/// </summary>
[DataField("customAddress")]
public bool CustomAddress = false;
/// <summary>
/// Prefix to prepend to any automatically generated addresses. Helps players to identify devices. This gets
/// localized.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("prefix")]
public string? Prefix;
/// <summary>
/// Whether the device should listen for all device messages, regardless of the intended recipient.
/// </summary>
[DataField("receiveAll")]
public bool ReceiveAll;
/// <summary>
/// If the device should show its address upon an examine. Useful for devices
/// that do not have a visible UI.
/// </summary>
[DataField("examinableAddress")]
public bool ExaminableAddress;
/// <summary>
/// Whether the device should attempt to join the network on map init.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("autoConnect")]
public bool AutoConnect = true;
/// <summary>
/// Whether to send the broadcast recipients list to the sender so it can be filtered.
/// <see cref="DeviceListSystem"/>
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("sendBroadcastAttemptEvent")]
public bool SendBroadcastAttemptEvent = false;
/// <summary>
/// Whether this device's address can be saved to device-lists
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("savableAddress")]
public bool SavableAddress = true;
/// <summary>
/// A list of device-lists that this device is on.
/// </summary>
[DataField]
[Access(typeof(DeviceListSystem))]
public HashSet<EntityUid> DeviceLists = new();
/// <summary>
/// A list of configurators that this device is on.
/// </summary>
[DataField]
[Access(typeof(NetworkConfiguratorSystem))]
public HashSet<EntityUid> Configurators = new();
}
}

View File

@@ -1,239 +0,0 @@
using Content.Server.DeviceNetwork.Components;
using Robust.Shared.Random;
using static Content.Server.DeviceNetwork.Components.DeviceNetworkComponent;
namespace Content.Server.DeviceNetwork;
/// <summary>
/// Data class for storing and retrieving information about devices connected to a device network.
/// </summary>
/// <remarks>
/// This basically just makes <see cref="DeviceNetworkComponent"/> accessible via their addresses and frequencies on
/// some network.
/// </remarks>
public sealed class DeviceNet
{
/// <summary>
/// Devices, mapped by their "Address", which is just an int that gets converted to Hex for displaying to users.
/// This dictionary contains all devices connected to this network, though they may not be listening to any
/// specific frequency.
/// </summary>
public readonly Dictionary<string, DeviceNetworkComponent> Devices = new();
/// <summary>
/// Devices listening on a given frequency.
/// </summary>
public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ListeningDevices = new();
/// <summary>
/// Devices listening to all packets on a given frequency, regardless of the intended recipient.
/// </summary>
public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ReceiveAllDevices = new();
private readonly IRobustRandom _random;
public readonly int NetId;
public DeviceNet(int netId, IRobustRandom random)
{
_random = random;
NetId = netId;
}
/// <summary>
/// Add a device to the network.
/// </summary>
public bool Add(DeviceNetworkComponent device)
{
if (device.CustomAddress)
{
// Only add if the device's existing address is available.
if (!Devices.TryAdd(device.Address, device))
return false;
}
else
{
// Randomly generate a new address if the existing random one is invalid. Otherwise, keep the existing address
if (string.IsNullOrWhiteSpace(device.Address) || Devices.ContainsKey(device.Address))
device.Address = GenerateValidAddress(device.Prefix);
Devices[device.Address] = device;
}
if (device.ReceiveFrequency is not uint freq)
return true;
if (!ListeningDevices.TryGetValue(freq, out var devices))
ListeningDevices[freq] = devices = new();
devices.Add(device);
if (!device.ReceiveAll)
return true;
if (!ReceiveAllDevices.TryGetValue(freq, out var receiveAlldevices))
ReceiveAllDevices[freq] = receiveAlldevices = new();
receiveAlldevices.Add(device);
return true;
}
/// <summary>
/// Remove a device from the network.
/// </summary>
public bool Remove(DeviceNetworkComponent device)
{
if (device.Address == null || !Devices.Remove(device.Address))
return false;
if (device.ReceiveFrequency is not uint freq)
return true;
if (ListeningDevices.TryGetValue(freq, out var listening))
{
listening.Remove(device);
if (listening.Count == 0)
ListeningDevices.Remove(freq);
}
if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll))
{
receiveAll.Remove(device);
if (receiveAll.Count == 0)
ListeningDevices.Remove(freq);
}
return true;
}
/// <summary>
/// Give an existing device a new randomly generated address. Useful if the device's address prefix was updated
/// and they want a new address to reflect that, or something like that.
/// </summary>
public bool RandomizeAddress(string oldAddress, string? prefix = null)
{
if (!Devices.Remove(oldAddress, out var device))
return false;
device.Address = GenerateValidAddress(prefix ?? device.Prefix);
device.CustomAddress = false;
Devices[device.Address] = device;
return true;
}
/// <summary>
/// Update the address of an existing device.
/// </summary>
public bool UpdateAddress(string oldAddress, string newAddress)
{
if (Devices.ContainsKey(newAddress))
return false;
if (!Devices.Remove(oldAddress, out var device))
return false;
device.Address = newAddress;
device.CustomAddress = true;
Devices[newAddress] = device;
return true;
}
/// <summary>
/// Make an existing network device listen to a new frequency.
/// </summary>
public bool UpdateReceiveFrequency(string address, uint? newFrequency)
{
if (!Devices.TryGetValue(address, out var device))
return false;
if (device.ReceiveFrequency == newFrequency)
return true;
if (device.ReceiveFrequency is uint freq)
{
if (ListeningDevices.TryGetValue(freq, out var listening))
{
listening.Remove(device);
if (listening.Count == 0)
ListeningDevices.Remove(freq);
}
if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll))
{
receiveAll.Remove(device);
if (receiveAll.Count == 0)
ListeningDevices.Remove(freq);
}
}
device.ReceiveFrequency = newFrequency;
if (newFrequency == null)
return true;
if (!ListeningDevices.TryGetValue(newFrequency.Value, out var devices))
ListeningDevices[newFrequency.Value] = devices = new();
devices.Add(device);
if (!device.ReceiveAll)
return true;
if (!ReceiveAllDevices.TryGetValue(newFrequency.Value, out var receiveAlldevices))
ReceiveAllDevices[newFrequency.Value] = receiveAlldevices = new();
receiveAlldevices.Add(device);
return true;
}
/// <summary>
/// Make an existing network device listen to a new frequency.
/// </summary>
public bool UpdateReceiveAll(string address, bool receiveAll)
{
if (!Devices.TryGetValue(address, out var device))
return false;
if (device.ReceiveAll == receiveAll)
return true;
device.ReceiveAll = receiveAll;
if (device.ReceiveFrequency is not uint freq)
return true;
// remove or add to set of listening devices
HashSet<DeviceNetworkComponent>? devices;
if (receiveAll)
{
if (!ReceiveAllDevices.TryGetValue(freq, out devices))
ReceiveAllDevices[freq] = devices = new();
devices.Add(device);
}
else if (ReceiveAllDevices.TryGetValue(freq, out devices))
{
devices.Remove(device);
if (devices.Count == 0)
ReceiveAllDevices.Remove(freq);
}
return true;
}
/// <summary>
/// Generates a valid address by randomly generating one and checking if it already exists on the network.
/// </summary>
private string GenerateValidAddress(string? prefix)
{
prefix = string.IsNullOrWhiteSpace(prefix) ? null : Loc.GetString(prefix);
string address;
do
{
var num = _random.Next();
address = $"{prefix}{num >> 16:X4}-{num & 0xFFFF:X4}";
}
while (Devices.ContainsKey(address));
return address;
}
}

View File

@@ -1,79 +0,0 @@
using Content.Server.DeviceNetwork.Components;
using Robust.Shared.Utility;
namespace Content.Server.DeviceNetwork
{
/// <summary>
/// A collection of constants to help with using device networks
/// </summary>
public static class DeviceNetworkConstants
{
/// <summary>
/// Used by logic gates to transmit the state of their ports
/// </summary>
public const string LogicState = "logic_state";
#region Commands
/// <summary>
/// The key for command names
/// E.g. [DeviceNetworkConstants.Command] = "ping"
/// </summary>
public const string Command = "command";
/// <summary>
/// The command for setting a devices state
/// E.g. to turn a light on or off
/// </summary>
public const string CmdSetState = "set_state";
/// <summary>
/// The command for a device that just updated its state
/// E.g. suit sensors broadcasting owners vitals state
/// </summary>
public const string CmdUpdatedState = "updated_state";
#endregion
#region SetState
/// <summary>
/// Used with the <see cref="CmdSetState"/> command to turn a device on or off
/// </summary>
public const string StateEnabled = "state_enabled";
#endregion
#region DisplayHelpers
/// <summary>
/// Converts the unsigned int to string and inserts a number before the last digit
/// </summary>
public static string FrequencyToString(this uint frequency)
{
var result = frequency.ToString();
if (result.Length <= 2)
return result + ".0";
return result.Insert(result.Length - 1, ".");
}
/// <summary>
/// Either returns the localized name representation of the corresponding <see cref="DeviceNetworkComponent.DeviceNetIdDefaults"/>
/// or converts the id to string
/// </summary>
public static string DeviceNetIdToLocalizedName(this int id)
{
if (!Enum.IsDefined(typeof(DeviceNetworkComponent.DeviceNetIdDefaults), id))
return id.ToString();
var result = ((DeviceNetworkComponent.DeviceNetIdDefaults) id).ToString();
var resultKebab = "device-net-id-" + CaseConversion.PascalToKebab(result);
return !Loc.TryGetString(resultKebab, out var name) ? result : name;
}
#endregion
}
}

View File

@@ -4,6 +4,7 @@ using Content.Server.NodeContainer.EntitySystems;
using JetBrains.Annotations;
using Content.Server.Power.EntitySystems;
using Content.Server.Power.Nodes;
using Content.Shared.DeviceNetwork.Events;
namespace Content.Server.DeviceNetwork.Systems
{

View File

@@ -1,9 +1,7 @@
using System.Linq;
using Content.Server.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.DeviceNetwork.Systems;
using Content.Shared.Interaction;
using JetBrains.Annotations;
using Robust.Shared.Map.Events;

View File

@@ -1,4 +1,5 @@
using Content.Shared.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.DeviceNetwork.Systems;
using Robust.Server.GameObjects;

View File

@@ -1,6 +1,7 @@
using Content.Server.DeviceNetwork.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.DeviceNetwork.Events;
namespace Content.Server.DeviceNetwork.Systems;

View File

@@ -1,12 +1,12 @@
using Content.Server.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Content.Shared.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.DeviceNetwork.Systems;
using Content.Shared.Examine;
namespace Content.Server.DeviceNetwork.Systems
@@ -16,7 +16,7 @@ namespace Content.Server.DeviceNetwork.Systems
/// Device networking allows machines and devices to communicate with each other while adhering to restrictions like range or being connected to the same powernet.
/// </summary>
[UsedImplicitly]
public sealed class DeviceNetworkSystem : EntitySystem
public sealed class DeviceNetworkSystem : SharedDeviceNetworkSystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
@@ -60,16 +60,7 @@ namespace Content.Server.DeviceNetwork.Systems
SwapQueues();
}
/// <summary>
/// Sends the given payload as a device network packet to the entity with the given address and frequency.
/// Addresses are given to the DeviceNetworkComponent of an entity when connecting.
/// </summary>
/// <param name="uid">The EntityUid of the sending entity</param>
/// <param name="address">The address of the entity that the packet gets sent to. If null, the message is broadcast to all devices on that frequency (except the sender)</param>
/// <param name="frequency">The frequency to send on</param>
/// <param name="data">The data to be sent</param>
/// <returns>Returns true when the packet was successfully enqueued.</returns>
public bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null)
public override bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null)
{
if (!Resolve(uid, ref device, false))
return false;
@@ -368,96 +359,4 @@ namespace Content.Server.DeviceNetwork.Systems
}
}
}
/// <summary>
/// Event raised before a device network packet is send.
/// Subscribed to by other systems to prevent the packet from being sent.
/// </summary>
public sealed class BeforePacketSentEvent : CancellableEntityEventArgs
{
/// <summary>
/// The EntityUid of the entity the packet was sent from.
/// </summary>
public readonly EntityUid Sender;
public readonly TransformComponent SenderTransform;
/// <summary>
/// The senders current position in world coordinates.
/// </summary>
public readonly Vector2 SenderPosition;
/// <summary>
/// The network the packet will be sent to.
/// </summary>
public readonly string NetworkId;
public BeforePacketSentEvent(EntityUid sender, TransformComponent xform, Vector2 senderPosition, string networkId)
{
Sender = sender;
SenderTransform = xform;
SenderPosition = senderPosition;
NetworkId = networkId;
}
}
/// <summary>
/// Sent to the sending entity before broadcasting network packets to recipients
/// </summary>
public sealed class BeforeBroadcastAttemptEvent : CancellableEntityEventArgs
{
public readonly IReadOnlySet<DeviceNetworkComponent> Recipients;
public HashSet<DeviceNetworkComponent>? ModifiedRecipients;
public BeforeBroadcastAttemptEvent(IReadOnlySet<DeviceNetworkComponent> recipients)
{
Recipients = recipients;
}
}
/// <summary>
/// Event raised when a device network packet gets sent.
/// </summary>
public sealed class DeviceNetworkPacketEvent : EntityEventArgs
{
/// <summary>
/// The id of the network that this packet is being sent on.
/// </summary>
public int NetId;
/// <summary>
/// The frequency the packet is sent on.
/// </summary>
public readonly uint Frequency;
/// <summary>
/// Address of the intended recipient. Null if the message was broadcast.
/// </summary>
public string? Address;
/// <summary>
/// The device network address of the sending entity.
/// </summary>
public readonly string SenderAddress;
/// <summary>
/// The entity that sent the packet.
/// </summary>
public EntityUid Sender;
/// <summary>
/// The data that is being sent.
/// </summary>
public readonly NetworkPayload Data;
public DeviceNetworkPacketEvent(int netId, string? address, uint frequency, string senderAddress, EntityUid sender, NetworkPayload data)
{
NetId = netId;
Address = address;
Frequency = frequency;
SenderAddress = senderAddress;
Sender = sender;
Data = data;
}
}
}

View File

@@ -1,7 +1,8 @@
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Components.Devices;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.Interaction;
using Content.Shared.DeviceNetwork.Components;
namespace Content.Server.DeviceNetwork.Systems.Devices
{

View File

@@ -1,7 +1,6 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.DeviceLinking.Systems;
using Content.Server.DeviceNetwork.Components;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Database;

View File

@@ -1,9 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.DeviceNetwork.Components;
using Content.Server.Medical.CrewMonitoring;
using Content.Server.Power.Components;
using Content.Server.Station.Systems;
using Content.Shared.Power;
using Content.Shared.DeviceNetwork.Components;
namespace Content.Server.DeviceNetwork.Systems;

View File

@@ -1,5 +1,6 @@
using Content.Server.DeviceNetwork.Components;
using Content.Server.Station.Systems;
using Content.Shared.DeviceNetwork.Events;
using JetBrains.Annotations;
using Robust.Shared.Map;

View File

@@ -1,4 +1,5 @@
using Content.Server.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Events;
using JetBrains.Annotations;
namespace Content.Server.DeviceNetwork.Systems

View File

@@ -1,4 +1,5 @@
using Content.Server.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Events;
using JetBrains.Annotations;
namespace Content.Server.DeviceNetwork.Systems