diff --git a/Content.Client/_CP14/Fishing/CP14FishingSystem.cs b/Content.Client/_CP14/Fishing/CP14FishingSystem.cs index c951407e3b..729d43264c 100644 --- a/Content.Client/_CP14/Fishing/CP14FishingSystem.cs +++ b/Content.Client/_CP14/Fishing/CP14FishingSystem.cs @@ -25,7 +25,7 @@ public sealed class CP14FishingSystem : CP14SharedFishingSystem [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly InputSystem _input = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly HandsSystem _handsSystem = default!; + [Dependency] private readonly HandsSystem _hands = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -44,7 +44,7 @@ public sealed class CP14FishingSystem : CP14SharedFishingSystem if (!_gameTiming.IsFirstTimePredicted) return; - var heldUid = _handsSystem.GetActiveHandEntity(); + var heldUid = _hands.GetActiveHandEntity(); if (!TryComp(heldUid, out var fishingRodComponent)) return; @@ -63,18 +63,21 @@ public sealed class CP14FishingSystem : CP14SharedFishingSystem var reelKey = _input.CmdStates.GetState(CP14ContentKeyFunctions.CP14FishingAction) == BoundKeyState.Down; - if (!TryComp(player, out var combatMode) || - !combatMode.IsInCombatMode) - reelKey = false; - if (fishingRodComponent.Reeling == reelKey) return; + fishingRodComponent.Reeling = reelKey; RaiseNetworkEvent(new FishingReelKeyMessage(reelKey)); } private void UpdateUserInterface(CP14FishingRodComponent fishingRodComponent) { + if (_fishingPopup is null) + return; + + if (_fishingPopup.Visible == false) + return; + var fish = fishingRodComponent.CaughtFish; if (fish is null) diff --git a/Content.Server/_CP14/Fishing/CP14FishingSystem.cs b/Content.Server/_CP14/Fishing/CP14FishingSystem.cs index 65fb3fa72d..d89835426f 100644 --- a/Content.Server/_CP14/Fishing/CP14FishingSystem.cs +++ b/Content.Server/_CP14/Fishing/CP14FishingSystem.cs @@ -1,111 +1,5 @@ -using Content.Server.Hands.Systems; using Content.Shared._CP14.Fishing; -using Content.Shared._CP14.Fishing.Components; -using Content.Shared.CombatMode; -using Content.Shared.Interaction; -using Content.Shared.Throwing; -using Robust.Shared.Random; -using Robust.Shared.Timing; namespace Content.Server._CP14.Fishing; -public sealed class CP14FishingSystem : CP14SharedFishingSystem -{ - [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; - [Dependency] private readonly ThrowingSystem _throwingSystem = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly HandsSystem _handsSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IRobustRandom _random = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnInteract); - SubscribeNetworkEvent(OnReelingMessage); - } - - public override void Update(float delta) - { - base.Update(delta); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var component)) - { - if (component.FishingFloat is null) - continue; - - if (_transformSystem.InRange(uid, component.FishingFloat.Value, component.MaxFishingDistance * 1.5f)) - continue; - - PredictedDel(component.FishingFloat); - - component.FishingFloat = null; - component.Target = null; - DirtyFields(uid, component, null, nameof(CP14FishingRodComponent.FishingFloat), nameof(CP14FishingRodComponent.Target)); - } - } - - private void OnReelingMessage(FishingReelKeyMessage msg, EntitySessionEventArgs args) - { - if (args.SenderSession.AttachedEntity is not { } player) - return; - - if (!_handsSystem.TryGetActiveItem(player, out var activeItem) || - !TryComp(activeItem, out var fishingRodComponent)) - return; - - if (msg.Reeling && - (!TryComp(player, out var combatMode) || - !combatMode.IsInCombatMode)) - return; - - fishingRodComponent.Reeling = msg.Reeling; - DirtyField(activeItem.Value, fishingRodComponent, nameof(fishingRodComponent.Reeling)); - } - - private void OnInteract(EntityUid uid, CP14FishingRodComponent component, AfterInteractEvent args) - { - if (args.Handled) - return; - - if (args.Target is not { Valid: true }) - return; - - if (component.FishingFloat is not null) - return; - - if (!TryComp(args.Target, out _)) - return; - - if (!_interactionSystem.InRangeUnobstructed(uid, args.Target.Value, component.MaxFishingDistance)) - return; - - args.Handled = true; - - component.FishingTime = _gameTiming.CurTime; - component.FishingTime += TimeSpan.FromSeconds(_random.NextDouble(component.MinAwaitTime, component.MaxAwaitTime)); - CastFloat(args.Used, component, args.Target.Value); - } - - private void CastFloat(EntityUid uid, CP14FishingRodComponent component, EntityUid target) - { - var rodCoords = Transform(uid).Coordinates; - var targetCoords = Transform(target).Coordinates; - - var fishingFloat = PredictedSpawnAtPosition(component.FloatPrototype, rodCoords); - - component.FishingFloat = fishingFloat; - component.Target = target; - component.User = uid; - DirtyFields(uid, - component, - null, - nameof(CP14FishingRodComponent.FishingFloat), - nameof(CP14FishingRodComponent.Target), - nameof(CP14FishingRodComponent.User)); - - _throwingSystem.TryThrow(fishingFloat, targetCoords, component.ThrowPower, recoil: false, doSpin: false); - } -} +public sealed class CP14FishingSystem : CP14SharedFishingSystem; diff --git a/Content.Shared/_CP14/Fishing/CP14SharedFishingSystem.cs b/Content.Shared/_CP14/Fishing/CP14SharedFishingSystem.cs index 5e5498b7d4..780819b31d 100644 --- a/Content.Shared/_CP14/Fishing/CP14SharedFishingSystem.cs +++ b/Content.Shared/_CP14/Fishing/CP14SharedFishingSystem.cs @@ -2,9 +2,14 @@ using System.Linq; using System.Numerics; using Content.Shared._CP14.Fishing.Components; using Content.Shared.EntityTable; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; using Content.Shared.Interaction.Events; -using Content.Shared.Item; +using Content.Shared.Throwing; +using Robust.Shared.GameStates; using Robust.Shared.Map; +using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; @@ -14,12 +19,19 @@ namespace Content.Shared._CP14.Fishing; public abstract class CP14SharedFishingSystem : EntitySystem { + [Dependency] private readonly EntityTableSystem _entityTable = default!; + [Dependency] private readonly MetaDataSystem _meta = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly SharedPvsOverrideSystem _pvs= default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly EntityTableSystem _entityTable = default!; - [Dependency] private readonly MetaDataSystem _metaSystem = default!; - [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly INetManager _netManager = default!; private MapId? _mapId; @@ -27,8 +39,9 @@ public abstract class CP14SharedFishingSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnPickupEvent); + SubscribeLocalEvent(OnInteract); SubscribeLocalEvent(OnDropEvent); + SubscribeNetworkEvent(OnReelingMessage); } public override void Update(float frameTime) @@ -43,29 +56,23 @@ public abstract class CP14SharedFishingSystem : EntitySystem if (component.User is null) continue; - if (component.CaughtFish is null) - { - TryToCatchFish(uid, component, curTime); - continue; - } - - if (!component.FishHooked) - { - UpdateFishWaitingStatus(uid, component, curTime); - continue; - } - + RevalidateFishing(uid, component); + TryToCatchFish(uid, component, curTime); + UpdateFishWaitingStatus(uid, component, curTime); UpdatePositions(uid, component, curTime); } } private void UpdatePositions(EntityUid fishingRod, CP14FishingRodComponent fishingRodComponent, TimeSpan curTime) { - var fish = fishingRodComponent.CaughtFish; - - if (fish is null) + if (fishingRodComponent.CaughtFish is null) return; + if (!fishingRodComponent.FishHooked) + return; + + var fish = fishingRodComponent.CaughtFish; + TryComp(fish, out CP14FishComponent? fishComponent); if (fishComponent is null) @@ -121,8 +128,8 @@ public abstract class CP14SharedFishingSystem : EntitySystem } } - DirtyField(fishingRod, fishingRodComponent, nameof(fishingRodComponent.FloatPosition)); - DirtyField(fish.Value, fishComponent, nameof(fishComponent.FishPosAndDestination)); + DirtyField(fishingRod, fishingRodComponent, nameof(CP14FishingRodComponent.FloatPosition)); + DirtyField(fish.Value, fishComponent, nameof(CP14FishComponent.FishPosAndDestination)); } private void UpdateFishDestination(EntityUid fish, CP14FishComponent fishComponent, TimeSpan curTime, float maxCord) @@ -135,6 +142,12 @@ public abstract class CP14SharedFishingSystem : EntitySystem private void UpdateFishWaitingStatus(EntityUid fishingRod, CP14FishingRodComponent fishingRodComponent, TimeSpan curTime) { + if (fishingRodComponent.CaughtFish is null) + return; + + if (fishingRodComponent.FishHooked) + return; + var fish = fishingRodComponent.CaughtFish; TryComp(fish, out CP14FishComponent? fishComponent); @@ -157,14 +170,20 @@ public abstract class CP14SharedFishingSystem : EntitySystem fishingRodComponent.CaughtFish = null; DirtyField(fishingRod, fishingRodComponent, nameof(CP14FishingRodComponent.CaughtFish)); - Del(fish); + PredictedDel(fish); } private void TryToCatchFish(EntityUid fishingRod, CP14FishingRodComponent fishingRodComponent, TimeSpan curTime) { + if (!_netManager.IsServer) + return; + if (curTime < fishingRodComponent.FishingTime) return; + if (fishingRodComponent.User is null) + return; + if (fishingRodComponent.FishingFloat is null) return; @@ -186,7 +205,14 @@ public abstract class CP14SharedFishingSystem : EntitySystem var fishId = fishes.First(); EnsurePausedMap(); - var fish = Spawn(fishId, new MapCoordinates(Vector2.Zero, _mapId!.Value)); + var fish = PredictedSpawnAtPosition(fishId, new EntityCoordinates(_map.GetMap(_mapId!.Value), Vector2.Zero)); + + _playerManager.TryGetSessionByEntity(fishingRodComponent.User.Value, out var session); + + if (session is null) + return; + + _pvs.AddSessionOverride(fish, session); TryComp(fish, out CP14FishComponent? fishComponent); @@ -200,26 +226,105 @@ public abstract class CP14SharedFishingSystem : EntitySystem DirtyField(fish, fishComponent, nameof(CP14FishComponent.FishGetAwayTime)); } - private void OnPickupEvent(EntityUid entity, CP14FishingRodComponent component, GettingPickedUpAttemptEvent ev) + private void RevalidateFishing(EntityUid fishingRod, CP14FishingRodComponent component) { - if (ev.Cancelled) + if (component.FishingFloat is null) return; - component.User = ev.User; + if (_transform.InRange(fishingRod, component.FishingFloat.Value, component.MaxFishingDistance * 1.5f)) + return; + + PredictedDel(component.FishingFloat); + + component.FishingFloat = null; + component.Target = null; + component.User = null; + + DirtyFields(fishingRod, + component, + null, + nameof(CP14FishingRodComponent.FishingFloat), + nameof(CP14FishingRodComponent.Target), + nameof(CP14FishingRodComponent.User)); + } + + private void OnReelingMessage(FishingReelKeyMessage msg, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not { } player) + return; + + if (!_hands.TryGetActiveItem(player, out var activeItem) || + !TryComp(activeItem, out var fishingRodComponent)) + return; + + fishingRodComponent.Reeling = msg.Reeling; + DirtyField(activeItem.Value, fishingRodComponent, nameof(CP14FishingRodComponent.Reeling)); + } + + private void OnInteract(EntityUid uid, CP14FishingRodComponent component, AfterInteractEvent args) + { + if (args.Handled) + return; + + if (args.Target is not { Valid: true }) + return; + + if (component.FishingFloat is not null) + return; + + if (!TryComp(args.Target, out _)) + return; + + if (!_interaction.InRangeUnobstructed(uid, args.Target.Value, component.MaxFishingDistance)) + return; + + args.Handled = true; + + component.FishingTime = _gameTiming.CurTime; + component.FishingTime += TimeSpan.FromSeconds(_random.NextDouble(component.MinAwaitTime, component.MaxAwaitTime)); + component.User = args.User; + + DirtyFields(uid, component, null, nameof(CP14FishingRodComponent.FishingTime), nameof(CP14FishingRodComponent.User)); + + CastFloat(args.Used, component, args.Target.Value); } private void OnDropEvent(EntityUid entity, CP14FishingRodComponent component, DroppedEvent ev) { component.User = null; + DirtyField(entity, component, nameof(CP14FishingRodComponent.User)); + } + + private void CastFloat(EntityUid uid, CP14FishingRodComponent component, EntityUid target) + { + var rodCoords = Transform(uid).Coordinates; + var targetCoords = Transform(target).Coordinates; + + var fishingFloat = PredictedSpawnAtPosition(component.FloatPrototype, rodCoords); + + component.FishingFloat = fishingFloat; + component.Target = target; + component.User = uid; + DirtyFields(uid, + component, + null, + nameof(CP14FishingRodComponent.FishingFloat), + nameof(CP14FishingRodComponent.Target), + nameof(CP14FishingRodComponent.User)); + + _throwing.TryThrow(fishingFloat, targetCoords, component.ThrowPower, recoil: false, doSpin: false); } private void EnsurePausedMap() { + if (!_netManager.IsServer) + return; + if (_map.MapExists(_mapId)) return; var mapUid = _map.CreateMap(out var newMapId); - _metaSystem.SetEntityName(mapUid, Loc.GetString("fishing-paused-map-name")); + _meta.SetEntityName(mapUid, Loc.GetString("fishing-paused-map-name")); _mapId = newMapId; _map.SetPaused(mapUid, true); } diff --git a/Content.Shared/_CP14/Fishing/Components/CP14FishComponent.cs b/Content.Shared/_CP14/Fishing/Components/CP14FishComponent.cs index 3cfdc01386..7cdacfbcf9 100644 --- a/Content.Shared/_CP14/Fishing/Components/CP14FishComponent.cs +++ b/Content.Shared/_CP14/Fishing/Components/CP14FishComponent.cs @@ -7,16 +7,16 @@ namespace Content.Shared._CP14.Fishing.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause] public sealed partial class CP14FishComponent : Component { - [DataField(required: true)] + [DataField(required: true), ViewVariables] public CP14FishBaseBehavior FishBehavior = default!; - [AutoNetworkedField, AutoPausedField] + [AutoNetworkedField, AutoPausedField, ViewVariables] public TimeSpan FishSelectPosTime = TimeSpan.Zero; - [AutoNetworkedField, AutoPausedField] + [AutoNetworkedField, AutoPausedField, ViewVariables] public TimeSpan FishGetAwayTime = TimeSpan.Zero; - [AutoNetworkedField] + [AutoNetworkedField, ViewVariables] public Vector2 FishPosAndDestination; [DataField]