Skip to content

Commit

Permalink
Implement some field-level deltas (space-wizards#28242)
Browse files Browse the repository at this point in the history
* Update GasTileOverlayState

* Update DecalGridState

* Update NavMapState

* poke

* poke2

* poke3

* Implement field deltas for guns

* Content done

* Update

---------

Co-authored-by: ElectroJr <[email protected]>
  • Loading branch information
metalgearsloth and ElectroJr authored Dec 21, 2024
1 parent 1f85916 commit 9f4aa1e
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 47 deletions.
2 changes: 2 additions & 0 deletions Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent comp
{
var existing = component.Entities[^1];
component.Entities.RemoveAt(component.Entities.Count - 1);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));

Containers.Remove(existing, component.Container);
EnsureShootable(existing);
}
else if (component.UnspawnedCount > 0)
{
component.UnspawnedCount--;
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
ent = Spawn(component.Proto, coordinates);
EnsureShootable(ent.Value);
}
Expand Down
7 changes: 5 additions & 2 deletions Content.Server/Weapons/Ranged/Systems/GunSystem.Solution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,20 @@ protected override void UpdateSolutionShots(EntityUid uid, SolutionAmmoProviderC
if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out _, out solution))
{
component.Shots = shots;
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));
component.MaxShots = maxShots;
Dirty(uid, component);
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));
return;
}

shots = (int) (solution.Volume / component.FireCost);
maxShots = (int) (solution.MaxVolume / component.FireCost);

component.Shots = shots;
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));

component.MaxShots = maxShots;
Dirty(uid, component);
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));

UpdateSolutionAppearance(uid, component);
}
Expand Down
2 changes: 1 addition & 1 deletion Content.Shared/Nutrition/Components/HungerComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Content.Shared.Nutrition.Components;

[RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))]
[AutoGenerateComponentState, AutoGenerateComponentPause]
[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
public sealed partial class HungerComponent : Component
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Content.Shared/Nutrition/Components/ThirstComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Content.Shared.Nutrition.Components;

[RegisterComponent, NetworkedComponent, Access(typeof(ThirstSystem))]
[AutoGenerateComponentState, AutoGenerateComponentPause]
[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
public sealed partial class ThirstComponent : Component
{
// Base stuff
Expand Down
3 changes: 2 additions & 1 deletion Content.Shared/Nutrition/EntitySystems/HungerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ private void SetAuthoritativeHungerValue(Entity<HungerComponent> entity, float v
{
entity.Comp.LastAuthoritativeHungerChangeTime = _timing.CurTime;
entity.Comp.LastAuthoritativeHungerValue = ClampHungerWithinThresholds(entity.Comp, value);
Dirty(entity);
DirtyField(entity.Owner, entity.Comp, nameof(HungerComponent.LastAuthoritativeHungerChangeTime));
}

private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = null)
Expand All @@ -133,6 +133,7 @@ private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component =
var calculatedHungerThreshold = GetHungerThreshold(component);
if (calculatedHungerThreshold == component.CurrentThreshold)
return;

component.CurrentThreshold = calculatedHungerThreshold;
DoHungerThresholdEffects(uid, component);
}
Expand Down
3 changes: 2 additions & 1 deletion Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ public void SetThirst(EntityUid uid, ThirstComponent component, float amount)
component.ThirstThresholds[ThirstThreshold.Dead],
component.ThirstThresholds[ThirstThreshold.OverHydrated]
);
Dirty(uid, component);

EntityManager.DirtyField(uid, component, nameof(ThirstComponent.CurrentThirst));
}

private bool IsMovementThreshold(ThirstThreshold threshold)
Expand Down
16 changes: 8 additions & 8 deletions Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ public partial class AmmoComponent : Component, IShootable
{
// Muzzle flash stored on ammo because if we swap a gun to whatever we may want to override it.

[ViewVariables(VVAccess.ReadWrite), DataField("muzzleFlash", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? MuzzleFlash = "MuzzleFlashEffect";
[DataField]
public EntProtoId? MuzzleFlash = "MuzzleFlashEffect";
}

/// <summary>
/// Spawns another prototype to be shot instead of itself.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true)]
public sealed partial class CartridgeAmmoComponent : AmmoComponent
{
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype = default!;
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true)]
public EntProtoId Prototype;

[ViewVariables(VVAccess.ReadWrite), DataField("spent")]
[ViewVariables(VVAccess.ReadWrite), DataField]
[AutoNetworkedField]
public bool Spent = false;
public bool Spent;

/// <summary>
/// Caseless ammunition.
/// </summary>
[DataField("deleteOnSpawn")]
[DataField]
public bool DeleteOnSpawn;

[DataField("soundEject")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

namespace Content.Shared.Weapons.Ranged.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedGunSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), Access(typeof(SharedGunSystem))]
public sealed partial class BallisticAmmoProviderComponent : Component
{
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField]
public SoundSpecifier? SoundRack = new SoundPathSpecifier("/Audio/Weapons/Guns/Cock/smg_cock.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField]
public SoundSpecifier? SoundInsert = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/bullet_insert.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField]
Expand Down
2 changes: 1 addition & 1 deletion Content.Shared/Weapons/Ranged/Components/GunComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Content.Shared.Weapons.Ranged.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
[Access(typeof(SharedGunSystem))]
public sealed partial class GunComponent : Component
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,38 @@

namespace Content.Shared.Weapons.Ranged.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedGunSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), Access(typeof(SharedGunSystem))]
public sealed partial class SolutionAmmoProviderComponent : Component
{
/// <summary>
/// The solution where reagents are extracted from for the projectile.
/// </summary>
[DataField("solutionId", required: true), AutoNetworkedField]
[DataField(required: true), AutoNetworkedField]
public string SolutionId = default!;

/// <summary>
/// How much reagent it costs to fire once.
/// </summary>
[DataField("fireCost"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
[DataField, AutoNetworkedField]
public float FireCost = 5;

/// <summary>
/// The amount of shots currently available.
/// used for network predictions.
/// </summary>
[DataField("shots"), ViewVariables, AutoNetworkedField]
[DataField, AutoNetworkedField]
public int Shots;

/// <summary>
/// The max amount of shots the gun can fire.
/// used for network prediction
/// </summary>
[DataField("maxShots"), ViewVariables, AutoNetworkedField]
[DataField, AutoNetworkedField]
public int MaxShots;

/// <summary>
/// The prototype that's fired by the gun.
/// </summary>
[DataField("proto", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)), ViewVariables(VVAccess.ReadWrite)]
public string Prototype = default!;
[DataField("proto")]
public EntProtoId Prototype;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private void OnBallisticInteractUsing(EntityUid uid, BallisticAmmoProviderCompon
Audio.PlayPredicted(component.SoundInsert, uid, args.User);
args.Handled = true;
UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
}

private void OnBallisticAfterInteract(EntityUid uid, BallisticAmmoProviderComponent component, AfterInteractEvent args)
Expand Down Expand Up @@ -194,10 +194,9 @@ private void ManualCycle(EntityUid uid, BallisticAmmoProviderComponent component
!Paused(uid))
{
gunComp.NextFire = Timing.CurTime + TimeSpan.FromSeconds(1 / gunComp.FireRateModified);
Dirty(uid, gunComp);
DirtyField(uid, gunComp, nameof(GunComponent.NextFire));
}

Dirty(uid, component);
Audio.PlayPredicted(component.SoundRack, uid, user);

var shots = GetBallisticShots(component);
Expand Down Expand Up @@ -228,7 +227,7 @@ private void OnBallisticMapInit(EntityUid uid, BallisticAmmoProviderComponent co
{
component.UnspawnedCount = Math.Max(0, component.Capacity - component.Container.ContainedEntities.Count);
UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
}
}

Expand All @@ -249,18 +248,19 @@ private void OnBallisticTakeAmmo(EntityUid uid, BallisticAmmoProviderComponent c

args.Ammo.Add((entity, EnsureShootable(entity)));
component.Entities.RemoveAt(component.Entities.Count - 1);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
Containers.Remove(entity, component.Container);
}
else if (component.UnspawnedCount > 0)
{
component.UnspawnedCount--;
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
entity = Spawn(component.Proto, args.Coordinates);
args.Ammo.Add((entity, EnsureShootable(entity)));
}
}

UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
}

private void OnBallisticAmmoCount(EntityUid uid, BallisticAmmoProviderComponent component, ref GetAmmoCountEvent args)
Expand Down
78 changes: 61 additions & 17 deletions Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private void OnGunMelee(EntityUid uid, GunComponent component, MeleeHitEvent arg
if (melee.NextAttack > component.NextFire)
{
component.NextFire = melee.NextAttack;
Dirty(uid, component);
EntityManager.DirtyField(uid, component, nameof(MeleeWeaponComponent.NextAttack));
}
}

Expand Down Expand Up @@ -200,7 +200,7 @@ private void StopShooting(EntityUid uid, GunComponent gun)
gun.ShotCounter = 0;
gun.ShootCoordinates = null;
gun.Target = null;
Dirty(uid, gun);
EntityManager.DirtyField(uid, gun, nameof(GunComponent.ShotCounter));
}

/// <summary>
Expand All @@ -211,6 +211,7 @@ public void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun, Ent
gun.ShootCoordinates = toCoordinates;
AttemptShoot(user, gunUid, gun);
gun.ShotCounter = 0;
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));
}

/// <summary>
Expand All @@ -228,7 +229,9 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
{
if (gun.FireRateModified <= 0f ||
!_actionBlockerSystem.CanAttack(user))
{
return;
}

var toCoordinates = gun.ShootCoordinates;

Expand Down Expand Up @@ -277,7 +280,7 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
}

// NextFire has been touched regardless so need to dirty the gun.
Dirty(gunUid, gun);
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.NextFire));

// Get how many shots we're actually allowed to make, due to clip size or otherwise.
// Don't do this in the loop so we still reset NextFire.
Expand Down Expand Up @@ -331,6 +334,7 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
// Even if we don't actually shoot update the ShotCounter. This is to avoid spamming empty sounds
// where the gun may be SemiAuto or Burst.
gun.ShotCounter += shots;
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));

if (ev.Ammo.Count <= 0)
{
Expand Down Expand Up @@ -387,8 +391,6 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
if (_gravity.IsWeightless(user, userPhysics))
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
}

Dirty(gunUid, gun);
}

public void Shoot(
Expand Down Expand Up @@ -442,7 +444,7 @@ protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) {}
protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
{
if (cartridge.Spent != spent)
Dirty(uid, cartridge);
DirtyField(uid, cartridge, nameof(CartridgeAmmoComponent.Spent));

cartridge.Spent = spent;
Appearance.SetData(uid, AmmoVisuals.Spent, spent);
Expand Down Expand Up @@ -541,17 +543,59 @@ public void RefreshModifiers(Entity<GunComponent?> gun)

RaiseLocalEvent(gun, ref ev);

comp.SoundGunshotModified = ev.SoundGunshot;
comp.CameraRecoilScalarModified = ev.CameraRecoilScalar;
comp.AngleIncreaseModified = ev.AngleIncrease;
comp.AngleDecayModified = ev.AngleDecay;
comp.MaxAngleModified = ev.MaxAngle;
comp.MinAngleModified = ev.MinAngle;
comp.ShotsPerBurstModified = ev.ShotsPerBurst;
comp.FireRateModified = ev.FireRate;
comp.ProjectileSpeedModified = ev.ProjectileSpeed;

Dirty(gun);
if (comp.SoundGunshotModified != ev.SoundGunshot)
{
comp.SoundGunshotModified = ev.SoundGunshot;
DirtyField(gun, nameof(GunComponent.SoundGunshotModified));
}

if (!MathHelper.CloseTo(comp.CameraRecoilScalarModified, ev.CameraRecoilScalar))
{
comp.CameraRecoilScalarModified = ev.CameraRecoilScalar;
DirtyField(gun, nameof(GunComponent.CameraRecoilScalarModified));
}

if (!comp.AngleIncreaseModified.EqualsApprox(ev.AngleIncrease))
{
comp.AngleIncreaseModified = ev.AngleIncrease;
DirtyField(gun, nameof(GunComponent.AngleIncreaseModified));
}

if (!comp.AngleDecayModified.EqualsApprox(ev.AngleDecay))
{
comp.AngleDecayModified = ev.AngleDecay;
DirtyField(gun, nameof(GunComponent.AngleDecayModified));
}

if (!comp.MaxAngleModified.EqualsApprox(ev.MinAngle))
{
comp.MaxAngleModified = ev.MaxAngle;
DirtyField(gun, nameof(GunComponent.MaxAngleModified));
}

if (!comp.MinAngleModified.EqualsApprox(ev.MinAngle))
{
comp.MinAngleModified = ev.MinAngle;
DirtyField(gun, nameof(GunComponent.MinAngleModified));
}

if (comp.ShotsPerBurstModified != ev.ShotsPerBurst)
{
comp.ShotsPerBurstModified = ev.ShotsPerBurst;
DirtyField(gun, nameof(GunComponent.ShotsPerBurstModified));
}

if (!MathHelper.CloseTo(comp.FireRateModified, ev.FireRate))
{
comp.FireRateModified = ev.FireRate;
DirtyField(gun, nameof(GunComponent.FireRateModified));
}

if (!MathHelper.CloseTo(comp.ProjectileSpeedModified, ev.ProjectileSpeed))
{
comp.ProjectileSpeedModified = ev.ProjectileSpeed;
DirtyField(gun, nameof(GunComponent.ProjectileSpeedModified));
}
}

protected abstract void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null);
Expand Down

0 comments on commit 9f4aa1e

Please sign in to comment.