Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement some field-level deltas #28242

Merged
Merged
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));
}
Comment on lines +563 to +574
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an easy way to make a helper for this.


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
Loading