diff --git a/Content.Server/Salvage/SalvageGridComponent.cs b/Content.Server/Salvage/SalvageGridComponent.cs index ba9e89aaa4..be8a12f9d6 100644 --- a/Content.Server/Salvage/SalvageGridComponent.cs +++ b/Content.Server/Salvage/SalvageGridComponent.cs @@ -9,6 +9,6 @@ /// /// The magnet that spawned this grid. /// - public SalvageMagnetComponent? SpawnerMagnet; + public EntityUid? SpawnerMagnet; } } diff --git a/Content.Server/Salvage/SalvageMagnetComponent.cs b/Content.Server/Salvage/SalvageMagnetComponent.cs index 69b0cbdf5d..38c993d404 100644 --- a/Content.Server/Salvage/SalvageMagnetComponent.cs +++ b/Content.Server/Salvage/SalvageMagnetComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Radio; +using Content.Shared.Random; using Content.Shared.Salvage; using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -12,33 +13,19 @@ namespace Content.Server.Salvage [Access(typeof(SalvageSystem))] public sealed class SalvageMagnetComponent : SharedSalvageMagnetComponent { - /// - /// Offset relative to magnet used as centre of the placement circle. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("offset")] - public Vector2 Offset = Vector2.Zero; // TODO: Maybe specify a direction, and find the nearest edge of the magnets grid the salvage can fit at - - /// - /// Minimum distance from the offset position that will be used as a salvage's spawnpoint. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("offsetRadiusMin")] - public float OffsetRadiusMin = 24f; - /// /// Maximum distance from the offset position that will be used as a salvage's spawnpoint. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("offsetRadiusMax")] - public float OffsetRadiusMax = 48f; + public float OffsetRadiusMax = 32; /// /// The entity attached to the magnet /// [ViewVariables(VVAccess.ReadOnly)] [DataField("attachedEntity")] - public EntityUid? AttachedEntity = null; + public EntityUid? AttachedEntity; /// /// Current state of this magnet @@ -95,18 +82,34 @@ namespace Content.Server.Salvage /// /// Current how much charge the magnet currently has /// + [DataField("chargeRemaining")] public int ChargeRemaining = 5; /// /// How much capacity the magnet can hold /// + [DataField("chargeCapacity")] public int ChargeCapacity = 5; /// /// Used as a guard to prevent spamming the appearance system /// + [DataField("previousCharge")] public int PreviousCharge = 5; + /// + /// The chance that a random procgen asteroid will be + /// generated rather than a static salvage prototype. + /// + [DataField("asteroidChance"), ViewVariables(VVAccess.ReadWrite)] + public float AsteroidChance = 0.6f; + + /// + /// A weighted random prototype corresponding to + /// what asteroid entities will be generated. + /// + [DataField("asteroidPool", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string AsteroidPool = "RandomAsteroidPool"; } [CopyByRef, DataRecord] diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 7269c571e6..12a1032cac 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -178,14 +178,14 @@ public sealed partial class SalvageSystem // Handle payout after expedition has finished if (expedition.Completed) { - _sawmill.Debug($"Completed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); + Log.Debug($"Completed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown); Announce(uid, Loc.GetString("salvage-expedition-mission-completed")); GiveRewards(expedition); } else { - _sawmill.Debug($"Failed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); + Log.Debug($"Failed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_failedCooldown); Announce(uid, Loc.GetString("salvage-expedition-mission-failed")); } diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index c74933b02a..a3df1c5976 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -1,28 +1,30 @@ +using System.Linq; using Content.Server.Construction; using Content.Server.GameTicking; -using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; -using Content.Shared.CCVar; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Radio; using Content.Shared.Salvage; using Robust.Server.GameObjects; -using Robust.Server.Maps; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; -using System.Linq; using Content.Server.Chat.Managers; -using Content.Server.Chat.Systems; using Content.Server.Parallax; using Content.Server.Procedural; using Content.Server.Shuttles.Systems; using Content.Server.Station.Systems; +using Content.Server.Worldgen.Systems; +using Content.Shared.CCVar; +using Content.Shared.Random; +using Content.Shared.Random.Helpers; +using Robust.Server.Maps; +using Robust.Shared.Map.Components; using Robust.Shared.Timing; namespace Content.Server.Salvage @@ -49,18 +51,15 @@ namespace Content.Server.Salvage [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; - private static readonly int SalvageLocationPlaceAttempts = 16; + private const int SalvageLocationPlaceAttempts = 16; // TODO: This is probably not compatible with multi-station private readonly Dictionary _salvageGridStates = new(); - private ISawmill _sawmill = default!; - public override void Initialize() { base.Initialize(); - _sawmill = Logger.GetSawmill("salvage"); SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent(OnUpgradeExamine); @@ -105,24 +104,21 @@ namespace Content.Server.Salvage if (!Resolve(uid, ref component, false)) return; - int timeLeft = Convert.ToInt32(component.MagnetState.Until.TotalSeconds - currentTime.TotalSeconds); - if (component.MagnetState.StateType == MagnetStateType.Inactive) - component.ChargeRemaining = 5; - else if (component.MagnetState.StateType == MagnetStateType.Holding) + var timeLeft = Convert.ToInt32(component.MagnetState.Until.TotalSeconds - currentTime.TotalSeconds); + + component.ChargeRemaining = component.MagnetState.StateType switch { - component.ChargeRemaining = (timeLeft / (Convert.ToInt32(component.HoldTime.TotalSeconds) / component.ChargeCapacity)) + 1; - } - else if (component.MagnetState.StateType == MagnetStateType.Detaching) - component.ChargeRemaining = 0; - else if (component.MagnetState.StateType == MagnetStateType.CoolingDown) - { - component.ChargeRemaining = component.ChargeCapacity - (timeLeft / (Convert.ToInt32(component.CooldownTime.TotalSeconds) / component.ChargeCapacity)) - 1; - } - if (component.PreviousCharge != component.ChargeRemaining) - { - _appearanceSystem.SetData(uid, SalvageMagnetVisuals.ChargeState, component.ChargeRemaining); - component.PreviousCharge = component.ChargeRemaining; - } + MagnetStateType.Inactive => 5, + MagnetStateType.Holding => timeLeft / (Convert.ToInt32(component.HoldTime.TotalSeconds) / component.ChargeCapacity) + 1, + MagnetStateType.Detaching => 0, + MagnetStateType.CoolingDown => component.ChargeCapacity - timeLeft / (Convert.ToInt32(component.CooldownTime.TotalSeconds) / component.ChargeCapacity) - 1, + _ => component.ChargeRemaining + }; + + if (component.PreviousCharge == component.ChargeRemaining) + return; + _appearanceSystem.SetData(uid, SalvageMagnetVisuals.ChargeState, component.ChargeRemaining); + component.PreviousCharge = component.ChargeRemaining; } private void OnGridRemoval(GridRemovalEvent ev) @@ -130,34 +126,37 @@ namespace Content.Server.Salvage // If we ever want to give magnets names, and announce them individually, we would need to loop this, before removing it. if (_salvageGridStates.Remove(ev.EntityUid)) { - if (EntityManager.TryGetComponent(ev.EntityUid, out var salvComp) && salvComp.SpawnerMagnet != null) - Report(salvComp.SpawnerMagnet.Owner, salvComp.SpawnerMagnet.SalvageChannel, "salvage-system-announcement-spawn-magnet-lost"); + if (TryComp(ev.EntityUid, out var salvComp) && + TryComp(salvComp.SpawnerMagnet, out var magnet)) + Report(salvComp.SpawnerMagnet.Value, magnet.SalvageChannel, "salvage-system-announcement-spawn-magnet-lost"); // For the very unlikely possibility that the salvage magnet was on a salvage, we will not return here } foreach(var gridState in _salvageGridStates) { foreach(var magnet in gridState.Value.ActiveMagnets) { - if (magnet.AttachedEntity == ev.EntityUid) - { - magnet.AttachedEntity = null; - magnet.MagnetState = MagnetState.Inactive; - return; - } + if (!TryComp(magnet, out var magnetComponent)) + continue; + + if (magnetComponent.AttachedEntity != ev.EntityUid) + continue; + magnetComponent.AttachedEntity = null; + magnetComponent.MagnetState = MagnetState.Inactive; + return; } } } private void OnMagnetRemoval(EntityUid uid, SalvageMagnetComponent component, ComponentShutdown args) { - if (component.MagnetState.StateType == MagnetStateType.Inactive) return; - - var magnetTranform = EntityManager.GetComponent(component.Owner); - if (!(magnetTranform.GridUid is EntityUid gridId) || !_salvageGridStates.TryGetValue(gridId, out var salvageGridState)) - { + if (component.MagnetState.StateType == MagnetStateType.Inactive) return; - } - salvageGridState.ActiveMagnets.Remove(component); + + var magnetTranform = Transform(uid); + if (magnetTranform.GridUid is not { } gridId || !_salvageGridStates.TryGetValue(gridId, out var salvageGridState)) + return; + + salvageGridState.ActiveMagnets.Remove(uid); Report(uid, component.SalvageChannel, "salvage-system-announcement-spawn-magnet-lost"); if (component.AttachedEntity.HasValue) { @@ -169,6 +168,7 @@ namespace Content.Server.Salvage { Report(uid, component.SalvageChannel, "salvage-system-announcement-spawn-no-debris-available"); } + component.MagnetState = MagnetState.Inactive; } @@ -187,13 +187,13 @@ namespace Content.Server.Salvage private void OnExamined(EntityUid uid, SalvageMagnetComponent component, ExaminedEvent args) { - var gotGrid = false; - var remainingTime = TimeSpan.Zero; - if (!args.IsInDetailsRange) return; - if (Transform(uid).GridUid is EntityUid gridId && + var gotGrid = false; + var remainingTime = TimeSpan.Zero; + + if (Transform(uid).GridUid is { } gridId && _salvageGridStates.TryGetValue(gridId, out var salvageGridState)) { remainingTime = component.MagnetState.Until - salvageGridState.CurrentTime; @@ -201,8 +201,9 @@ namespace Content.Server.Salvage } else { - Logger.WarningS("salvage", "Failed to load salvage grid state, can't display remaining time"); + Log.Warning("Failed to load salvage grid state, can't display remaining time"); } + switch (component.MagnetState.StateType) { case MagnetStateType.Inactive: @@ -223,7 +224,7 @@ namespace Content.Server.Salvage args.PushMarkup(Loc.GetString("salvage-system-magnet-examined-active", ("timeLeft", Math.Ceiling(remainingTime.TotalSeconds)))); break; default: - throw new NotImplementedException("Unexpected magnet state type"); + throw new ArgumentOutOfRangeException(); } } @@ -232,57 +233,56 @@ namespace Content.Server.Salvage if (args.Handled) return; args.Handled = true; - StartMagnet(component, args.User); + StartMagnet(uid, component, args.User); UpdateAppearance(uid, component); } - private void StartMagnet(SalvageMagnetComponent component, EntityUid user) + private void StartMagnet(EntityUid uid, SalvageMagnetComponent component, EntityUid user) { switch (component.MagnetState.StateType) { case MagnetStateType.Inactive: - ShowPopup("salvage-system-report-activate-success", component, user); - SalvageGridState? gridState; - var magnetTransform = EntityManager.GetComponent(component.Owner); - EntityUid gridId = magnetTransform.GridUid ?? throw new InvalidOperationException("Magnet had no grid associated"); - if (!_salvageGridStates.TryGetValue(gridId, out gridState)) + ShowPopup(uid, "salvage-system-report-activate-success", user); + var magnetTransform = Transform(uid); + var gridId = magnetTransform.GridUid ?? throw new InvalidOperationException("Magnet had no grid associated"); + if (!_salvageGridStates.TryGetValue(gridId, out var gridState)) { gridState = new SalvageGridState(); _salvageGridStates[gridId] = gridState; } - gridState.ActiveMagnets.Add(component); + gridState.ActiveMagnets.Add(uid); component.MagnetState = new MagnetState(MagnetStateType.Attaching, gridState.CurrentTime + component.AttachingTime); - RaiseLocalEvent(new SalvageMagnetActivatedEvent(component.Owner)); - Report(component.Owner, component.SalvageChannel, "salvage-system-report-activate-success"); + RaiseLocalEvent(new SalvageMagnetActivatedEvent(uid)); + Report(uid, component.SalvageChannel, "salvage-system-report-activate-success"); break; case MagnetStateType.Attaching: case MagnetStateType.Holding: - ShowPopup("salvage-system-report-already-active", component, user); + ShowPopup(uid, "salvage-system-report-already-active", user); break; case MagnetStateType.Detaching: case MagnetStateType.CoolingDown: - ShowPopup("salvage-system-report-cooling-down", component, user); + ShowPopup(uid, "salvage-system-report-cooling-down", user); break; default: - throw new NotImplementedException("Unexpected magnet state type"); + throw new ArgumentOutOfRangeException(); } } - private void ShowPopup(string messageKey, SalvageMagnetComponent component, EntityUid user) + private void ShowPopup(EntityUid uid, string messageKey, EntityUid user) { - _popupSystem.PopupEntity(Loc.GetString(messageKey), component.Owner, user); + _popupSystem.PopupEntity(Loc.GetString(messageKey), uid, user); } private void SafeDeleteSalvage(EntityUid salvage) { if(!EntityManager.TryGetComponent(salvage, out var salvageTransform)) { - Logger.ErrorS("salvage", "Salvage entity was missing transform component"); + Log.Error("Salvage entity was missing transform component"); return; } if (salvageTransform.GridUid == null) { - Logger.ErrorS("salvage", "Salvage entity has no associated grid?"); + Log.Error( "Salvage entity has no associated grid?"); return; } @@ -296,125 +296,124 @@ namespace Content.Server.Salvage // Salvage mobs are NEVER immune (even if they're from a different salvage, they shouldn't be here) continue; } - Transform(playerEntityUid).AttachParent(salvageTransform.ParentUid); + _transform.SetParent(playerEntityUid, salvageTransform.ParentUid); } } // Deletion has to happen before grid traversal re-parents players. - EntityManager.DeleteEntity(salvage); + Del(salvage); } - private void TryGetSalvagePlacementLocation(SalvageMagnetComponent component, out MapCoordinates coords, out Angle angle) + private bool TryGetSalvagePlacementLocation(EntityUid uid, SalvageMagnetComponent component, Box2 bounds, out MapCoordinates coords, out Angle angle) { - coords = MapCoordinates.Nullspace; + var xform = Transform(uid); angle = Angle.Zero; - var tsc = Transform(component.Owner); - coords = new EntityCoordinates(component.Owner, component.Offset).ToMap(EntityManager); + coords = new EntityCoordinates(uid, new Vector2(0, -component.OffsetRadiusMax)).ToMap(EntityManager, _transform); - if (_mapManager.TryGetGrid(tsc.GridUid, out var magnetGrid) && TryComp(magnetGrid.Owner, out var gridXform)) + if (xform.GridUid is not null) + angle = _transform.GetWorldRotation(Transform(xform.GridUid.Value)); + + for (var i = 0; i < SalvageLocationPlaceAttempts; i++) { - angle = gridXform.WorldRotation; + var randomRadius = _random.NextFloat(component.OffsetRadiusMax); + var randomOffset = _random.NextAngle().ToWorldVec() * randomRadius; + var finalCoords = coords.Offset(randomOffset); + + var box2 = Box2.CenteredAround(finalCoords.Position, bounds.Size); + var box2Rot = new Box2Rotated(box2, angle, finalCoords.Position); + + // This doesn't stop it from spawning on top of random things in space + // Might be better like this, ghosts could stop it before + if (_mapManager.FindGridsIntersecting(finalCoords.MapId, box2Rot).Any()) + continue; + coords = finalCoords; + return true; } + return false; } - private IEnumerable GetAllSalvageMaps() => - _prototypeManager.EnumeratePrototypes(); - - private bool SpawnSalvage(SalvageMagnetComponent component) + private bool SpawnSalvage(EntityUid uid, SalvageMagnetComponent component) { - TryGetSalvagePlacementLocation(component, out var spl, out var spAngle); + var salvMap = _mapManager.CreateMap(); - var forcedSalvage = _configurationManager.GetCVar(CCVars.SalvageForced); - List allSalvageMaps; - if (string.IsNullOrWhiteSpace(forcedSalvage)) + Box2 bounds; + EntityUid? salvageEnt = null; + SalvageMapPrototype? salvageProto = null; + if (_random.Prob(component.AsteroidChance)) { - allSalvageMaps = GetAllSalvageMaps().ToList(); + var asteroidProto = _prototypeManager.Index(component.AsteroidPool).Pick(_random); + salvageEnt = Spawn(asteroidProto, new MapCoordinates(0, 0, salvMap)); + bounds = Comp(salvageEnt.Value).LocalAABB; } else { - allSalvageMaps = new(); - if (_prototypeManager.TryIndex(forcedSalvage, out var forcedMap)) - { - allSalvageMaps.Add(forcedMap); - } - else - { - Logger.ErrorS("c.s.salvage", $"Unable to get forced salvage map prototype {forcedSalvage}"); - } + var forcedSalvage = _configurationManager.GetCVar(CCVars.SalvageForced); + salvageProto = string.IsNullOrWhiteSpace(forcedSalvage) + ? _random.Pick(_prototypeManager.EnumeratePrototypes().ToList()) + : _prototypeManager.Index(forcedSalvage); + + bounds = salvageProto.Bounds; } - SalvageMapPrototype? map = null; - Vector2 spawnLocation = Vector2.Zero; - - for (var i = 0; i < allSalvageMaps.Count; i++) + if (!TryGetSalvagePlacementLocation(uid, component, bounds, out var spawnLocation, out var spawnAngle)) { - SalvageMapPrototype attemptedMap = _random.PickAndTake(allSalvageMaps); - for (var attempt = 0; attempt < SalvageLocationPlaceAttempts; attempt++) - { - var randomRadius = _random.NextFloat(component.OffsetRadiusMin, component.OffsetRadiusMax); - var randomOffset = _random.NextAngle().ToWorldVec() * randomRadius; - spawnLocation = spl.Position + randomOffset; - - var box2 = Box2.CenteredAround(spawnLocation + attemptedMap.Bounds.Center, attemptedMap.Bounds.Size); - var box2rot = new Box2Rotated(box2, spAngle, spawnLocation); - - // This doesn't stop it from spawning on top of random things in space - // Might be better like this, ghosts could stop it before - if (!_mapManager.FindGridsIntersecting(spl.MapId, box2rot).Any()) - { - map = attemptedMap; - break; - } - } - if (map != null) - { - break; - } - } - - if (map == null) - { - Report(component.Owner, component.SalvageChannel, "salvage-system-announcement-spawn-no-debris-available"); + Report(uid, component.SalvageChannel, "salvage-system-announcement-spawn-no-debris-available"); + _mapManager.DeleteMap(salvMap); return false; } - var opts = new MapLoadOptions + if (salvageEnt is { } ent) { - Offset = spawnLocation - }; - - var salvageEntityId = _map.LoadGrid(spl.MapId, map.MapPath.ToString(), opts); - if (salvageEntityId == null) - { - Report(component.Owner, component.SalvageChannel, "salvage-system-announcement-spawn-debris-disintegrated"); - return false; + var salvXForm = Transform(ent); + _transform.SetParent(ent, salvXForm, _mapManager.GetMapEntityId(spawnLocation.MapId)); + _transform.SetWorldPosition(salvXForm, spawnLocation.Position); } - component.AttachedEntity = salvageEntityId; - var gridcomp = EntityManager.EnsureComponent(salvageEntityId.Value); - gridcomp.SpawnerMagnet = component; + else if (salvageProto != null) + { + var opts = new MapLoadOptions + { + Offset = spawnLocation.Position, + Rotation = spawnAngle + }; - var pulledTransform = EntityManager.GetComponent(salvageEntityId.Value); - pulledTransform.WorldRotation = spAngle; + if (!_map.TryLoad(spawnLocation.MapId, salvageProto.MapPath.ToString(), out var roots, opts) || + roots.FirstOrNull() is not { } root) + { + Report(uid, component.SalvageChannel, "salvage-system-announcement-spawn-debris-disintegrated"); + _mapManager.DeleteMap(salvMap); + return false; + } - Report(component.Owner, component.SalvageChannel, "salvage-system-announcement-arrived", ("timeLeft", component.HoldTime.TotalSeconds)); + salvageEnt = root; + } + else + { + throw new InvalidOperationException("No asteroid generated and no salvage prototype present."); + } + + component.AttachedEntity = salvageEnt; + var gridcomp = EnsureComp(salvageEnt.Value); + gridcomp.SpawnerMagnet = uid; + _transform.SetWorldRotation(salvageEnt.Value, spawnAngle); + + Report(uid, component.SalvageChannel, "salvage-system-announcement-arrived", ("timeLeft", component.HoldTime.TotalSeconds)); + _mapManager.DeleteMap(salvMap); return true; } private void Report(EntityUid source, string channelName, string messageKey, params (string, object)[] args) { - if (!TryComp(source, out var radio)) return; - var message = args.Length == 0 ? Loc.GetString(messageKey) : Loc.GetString(messageKey, args); var channel = _prototypeManager.Index(channelName); _radioSystem.SendRadioMessage(source, message, channel, source); } - private void Transition(SalvageMagnetComponent magnet, TimeSpan currentTime) + private void Transition(EntityUid uid, SalvageMagnetComponent magnet, TimeSpan currentTime) { switch (magnet.MagnetState.StateType) { case MagnetStateType.Attaching: - if (SpawnSalvage(magnet)) + if (SpawnSalvage(uid, magnet)) { magnet.MagnetState = new MagnetState(MagnetStateType.Holding, currentTime + magnet.HoldTime); } @@ -424,7 +423,7 @@ namespace Content.Server.Salvage } break; case MagnetStateType.Holding: - Report(magnet.Owner, magnet.SalvageChannel, "salvage-system-announcement-losing", ("timeLeft", magnet.DetachingTime.TotalSeconds)); + Report(uid, magnet.SalvageChannel, "salvage-system-announcement-losing", ("timeLeft", magnet.DetachingTime.TotalSeconds)); magnet.MagnetState = new MagnetState(MagnetStateType.Detaching, currentTime + magnet.DetachingTime); break; case MagnetStateType.Detaching: @@ -434,41 +433,42 @@ namespace Content.Server.Salvage } else { - Logger.ErrorS("salvage", "Salvage detaching was expecting attached entity but it was null"); + Log.Error("Salvage detaching was expecting attached entity but it was null"); } - Report(magnet.Owner, magnet.SalvageChannel, "salvage-system-announcement-lost"); + Report(uid, magnet.SalvageChannel, "salvage-system-announcement-lost"); magnet.MagnetState = new MagnetState(MagnetStateType.CoolingDown, currentTime + magnet.CooldownTime); break; case MagnetStateType.CoolingDown: magnet.MagnetState = MagnetState.Inactive; break; } - UpdateAppearance(magnet.Owner, magnet); - UpdateChargeStateAppearance(magnet.Owner, currentTime, magnet); + UpdateAppearance(uid, magnet); + UpdateChargeStateAppearance(uid, currentTime, magnet); } public override void Update(float frameTime) { var secondsPassed = TimeSpan.FromSeconds(frameTime); // Keep track of time, and state per grid - foreach (var gridIdAndState in _salvageGridStates) + foreach (var (uid, state) in _salvageGridStates) { - var state = gridIdAndState.Value; if (state.ActiveMagnets.Count == 0) continue; - var gridId = gridIdAndState.Key; // Not handling the case where the salvage we spawned got paused // They both need to be paused, or it doesn't make sense - if (MetaData(gridId).EntityPaused) continue; + if (MetaData(uid).EntityPaused) continue; state.CurrentTime += secondsPassed; - var deleteQueue = new RemQueue(); + var deleteQueue = new RemQueue(); foreach(var magnet in state.ActiveMagnets) { - UpdateChargeStateAppearance(magnet.Owner, state.CurrentTime, magnet); - if (magnet.MagnetState.Until > state.CurrentTime) continue; - Transition(magnet, state.CurrentTime); - if (magnet.MagnetState.StateType == MagnetStateType.Inactive) + if (!TryComp(magnet, out var magnetComp)) + continue; + + UpdateChargeStateAppearance(magnet, state.CurrentTime, magnetComp); + if (magnetComp.MagnetState.Until > state.CurrentTime) continue; + Transition(magnet, magnetComp, state.CurrentTime); + if (magnetComp.MagnetState.StateType == MagnetStateType.Inactive) { deleteQueue.Add(magnet); } @@ -488,7 +488,7 @@ namespace Content.Server.Salvage public sealed class SalvageGridState { public TimeSpan CurrentTime { get; set; } - public List ActiveMagnets { get; } = new(); + public List ActiveMagnets { get; } = new(); } } diff --git a/Content.Server/Worldgen/Systems/LocalityLoaderSystem.cs b/Content.Server/Worldgen/Systems/LocalityLoaderSystem.cs index 97ed4c50be..2f3cffbe11 100644 --- a/Content.Server/Worldgen/Systems/LocalityLoaderSystem.cs +++ b/Content.Server/Worldgen/Systems/LocalityLoaderSystem.cs @@ -21,7 +21,11 @@ public sealed class LocalityLoaderSystem : BaseWorldSystem while (e.MoveNext(out var uid, out var loadable, out var xform)) { if (!controllerQuery.TryGetComponent(xform.MapUid, out var controller)) - return; + { + RaiseLocalEvent(uid, new LocalStructureLoadedEvent()); + RemCompDeferred(uid); + continue; + } var coords = GetChunkCoords(uid, xform); var done = false; diff --git a/Resources/Prototypes/Entities/Structures/Machines/salvage.yml b/Resources/Prototypes/Entities/Structures/Machines/salvage.yml index 56c6689b3e..e029a27051 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/salvage.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/salvage.yml @@ -71,8 +71,14 @@ description: Locates salvage. components: - type: SalvageMagnet - offsetRadiusMin: 12 - offsetRadiusMax: 48 + offsetRadiusMax: 32 - type: ApcPowerReceiver powerLoad: 1000 +- type: weightedRandom + id: RandomAsteroidPool + weights: + AsteroidSalvageSmall: 3 + AsteroidSalvageMedium: 7 + AsteroidSalvageLarge: 5 + AsteroidSalvageHuge: 3 diff --git a/Resources/Prototypes/Entities/World/Debris/asteroids.yml b/Resources/Prototypes/Entities/World/Debris/asteroids.yml index 0c55e9060f..99b46be9a6 100644 --- a/Resources/Prototypes/Entities/World/Debris/asteroids.yml +++ b/Resources/Prototypes/Entities/World/Debris/asteroids.yml @@ -16,18 +16,31 @@ FloorAsteroidCoarseSand0: - id: WallRock prob: 0.5 - - id: WallRockGold - prob: 0.01 - - id: WallRockSilver - prob: 0.04 - - id: WallRockPlasma - prob: 0.09 + orGroup: rock - id: WallRockTin - prob: 0.2 - - id: WallRockUranium - prob: 0.07 + prob: 0.15 + orGroup: rock - id: WallRockQuartz - prob: 0.2 + prob: 0.15 + orGroup: rock + - id: WallRockGold + prob: 0.05 + orGroup: rock + - id: WallRockSilver + prob: 0.05 + orGroup: rock + - id: WallRockPlasma + prob: 0.05 + orGroup: rock + - id: WallRockUranium + prob: 0.02 + orGroup: rock + - id: WallRockBananium + prob: 0.02 + orGroup: rock + - id: WallRockArtifactFragment + prob: 0.01 + orGroup: rock - type: GCAbleObject queue: SpaceDebris - type: IFF @@ -74,3 +87,51 @@ - type: BlobFloorPlanBuilder radius: 12 floorPlacements: 36 + +- type: entity + id: AsteroidSalvageSmall + parent: BaseAsteroidDebris + name: Salvage Asteroid Small + noSpawn: true + components: + - type: MapGrid + - type: BlobFloorPlanBuilder + blobDrawProb: 0.66 + radius: 15 + floorPlacements: 100 + +- type: entity + id: AsteroidSalvageMedium + parent: BaseAsteroidDebris + name: Salvage Asteroid Medium + noSpawn: true + components: + - type: MapGrid + - type: BlobFloorPlanBuilder + blobDrawProb: 0.66 + radius: 17 + floorPlacements: 150 + +- type: entity + id: AsteroidSalvageLarge + parent: BaseAsteroidDebris + name: Salvage Asteroid Large + noSpawn: true + components: + - type: MapGrid + - type: BlobFloorPlanBuilder + blobDrawProb: 0.66 + radius: 20 + floorPlacements: 200 + +- type: entity + id: AsteroidSalvageHuge + parent: BaseAsteroidDebris + name: Salvage Asteroid Huge + noSpawn: true + components: + - type: MapGrid + - type: BlobFloorPlanBuilder + blobDrawProb: 0.66 + radius: 23 + floorPlacements: 250