ECS damageable (#4529)
* ECS and damage Data * Comments and newlines * Added Comments * Make TryChangeDamageEvent immutable * Remove SetAllDamage event Use public SetAllDamage function instead * Undo destructible mistakes That was some shit code. * Rename DamageData to DamageSpecifier And misc small edits misc * Cache trigger prototypes. * Renaming destructible classes & functions * Revert "Cache trigger prototypes." This reverts commit 86bae15ba6616884dba75f552dfdfbe2d1fb6586. * Replace prototypes with prototype IDs. * Split damage.yml into individual files * move get/handle component state to system * Update HealthChange doc * Make godmode call Dirty() on damageable component * Add Initialize() to fix damage test * Make non-static * uncache resistance set prototype and trim DamageableComponentState * Remove unnecessary Dirty() calls during initialization * RemoveTryChangeDamageEvent * revert Dirty() * Fix MobState relying on DamageableComponent.Dirty() * Fix DisposalUnit Tests. These were previously failing, but because the async was not await-ed, this never raised the exception. After I fixed MobState component, this exception stopped happening and instead the assertions started being tested & failing * Disposal test 2: electric boogaloo * Fix typos/mistakes also add comments and fix spacing. * Use Uids instead of IEntity * fix merge * Comments, a merge issue, and making some damage ignore resistances * Extend DamageSpecifier and use it for DamageableComponent * fix master merge * Fix Disposal unit test. Again. Snapgrids were removed in master * Execute Exectute
This commit is contained in:
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.MobState.State;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -17,18 +16,20 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Content.Shared.MobState.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// When attached to an <see cref="IDamageableComponent"/>,
|
||||
/// When attached to an <see cref="DamageableComponent"/>,
|
||||
/// this component will handle critical and death behaviors for mobs.
|
||||
/// Additionally, it handles sending effects to clients
|
||||
/// (such as blur effect for unconsciousness) and managing the health HUD.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IMobStateComponent))]
|
||||
[NetworkedComponent()]
|
||||
public abstract class SharedMobStateComponent : Component, IMobStateComponent, IActionBlocker
|
||||
public class MobStateComponent : Component, IMobStateComponent, IActionBlocker
|
||||
{
|
||||
public override string Name => "MobState";
|
||||
|
||||
/// <summary>
|
||||
/// States that this <see cref="SharedMobStateComponent"/> mapped to
|
||||
/// States that this <see cref="MobStateComponent"/> mapped to
|
||||
/// the amount of damage at which they are triggered.
|
||||
/// A threshold is reached when the total damage of an entity is equal
|
||||
/// to or higher than the int key, but lower than the next threshold.
|
||||
@@ -36,7 +37,7 @@ namespace Content.Shared.MobState.Components
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("thresholds")]
|
||||
private readonly SortedDictionary<int, IMobState> _lowestToHighestStates = default!;
|
||||
private readonly SortedDictionary<int, IMobState> _lowestToHighestStates = new();
|
||||
|
||||
// TODO Remove Nullability?
|
||||
[ViewVariables]
|
||||
@@ -53,7 +54,13 @@ namespace Content.Shared.MobState.Components
|
||||
|
||||
if (CurrentState != null && CurrentThreshold != null)
|
||||
{
|
||||
UpdateState(null, (CurrentState, CurrentThreshold.Value));
|
||||
// Initialize with given states
|
||||
SetMobState(null, (CurrentState, CurrentThreshold.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize with some amount of damage, defaulting to 0.
|
||||
UpdateState(Owner.GetComponentOrNull<DamageableComponent>()?.TotalDamage ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,29 +95,11 @@ namespace Content.Shared.MobState.Components
|
||||
|
||||
if (state.CurrentThreshold == null)
|
||||
{
|
||||
RemoveState(true);
|
||||
RemoveState();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateState(state.CurrentThreshold.Value, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case DamageChangedMessage msg:
|
||||
if (msg.Damageable.Owner != Owner)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateState(msg.Damageable.TotalDamage);
|
||||
|
||||
break;
|
||||
UpdateState(state.CurrentThreshold.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +125,7 @@ namespace Content.Shared.MobState.Components
|
||||
|
||||
public (IMobState state, int threshold)? GetState(int damage)
|
||||
{
|
||||
foreach (var (threshold, state) in _lowestToHighestStates.Reverse())
|
||||
foreach (var (threshold, state) in _highestToLowestStates)
|
||||
{
|
||||
if (damage >= threshold)
|
||||
{
|
||||
@@ -273,36 +262,32 @@ namespace Content.Shared.MobState.Components
|
||||
return TryGetState(earliestState, out state, out threshold);
|
||||
}
|
||||
|
||||
private void RemoveState(bool syncing = false)
|
||||
private void RemoveState()
|
||||
{
|
||||
var old = CurrentState;
|
||||
CurrentState = null;
|
||||
CurrentThreshold = null;
|
||||
|
||||
UpdateState(old, null);
|
||||
|
||||
if (!syncing)
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
SetMobState(old, null);
|
||||
}
|
||||
|
||||
public void UpdateState(int damage, bool syncing = false)
|
||||
/// <summary>
|
||||
/// Updates the mob state..
|
||||
/// </summary>
|
||||
public void UpdateState(int damage)
|
||||
{
|
||||
if (!TryGetState(damage, out var newState, out var threshold))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateState(CurrentState, (newState, threshold));
|
||||
|
||||
if (!syncing)
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
SetMobState(CurrentState, (newState, threshold));
|
||||
}
|
||||
|
||||
private void UpdateState(IMobState? old, (IMobState state, int threshold)? current)
|
||||
/// <summary>
|
||||
/// Sets the mob state and marks the component as dirty.
|
||||
/// </summary>
|
||||
private void SetMobState(IMobState? old, (IMobState state, int threshold)? current)
|
||||
{
|
||||
if (!current.HasValue)
|
||||
{
|
||||
@@ -328,9 +313,10 @@ namespace Content.Shared.MobState.Components
|
||||
state.UpdateState(Owner, threshold);
|
||||
|
||||
var message = new MobStateChangedMessage(this, old, state);
|
||||
|
||||
SendMessage(message);
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, message);
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanInteract()
|
||||
45
Content.Shared/MobState/EntitySystems/MobStateSystem.cs
Normal file
45
Content.Shared/MobState/EntitySystems/MobStateSystem.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.MobState.State;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Pulling.Events;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.MobState.EntitySystems
|
||||
{
|
||||
public class MobStateSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MobStateComponent, StartPullAttemptEvent>(OnStartPullAttempt);
|
||||
SubscribeLocalEvent<MobStateComponent, DamageChangedEvent>(UpdateState);
|
||||
SubscribeLocalEvent<MobStateComponent, MovementAttemptEvent>(OnMoveAttempt);
|
||||
}
|
||||
|
||||
private void OnStartPullAttempt(EntityUid uid, MobStateComponent component, StartPullAttemptEvent args)
|
||||
{
|
||||
if(component.IsIncapacitated())
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
public void UpdateState(EntityUid _, MobStateComponent component, DamageChangedEvent args)
|
||||
{
|
||||
component.UpdateState(args.Damageable.TotalDamage);
|
||||
}
|
||||
|
||||
private void OnMoveAttempt(EntityUid uid, MobStateComponent component, MovementAttemptEvent args)
|
||||
{
|
||||
switch (component.CurrentState)
|
||||
{
|
||||
case SharedCriticalMobState:
|
||||
case SharedDeadMobState:
|
||||
args.Cancel();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.MobState.State;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Pulling.Events;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.MobState.EntitySystems
|
||||
{
|
||||
public class SharedMobStateSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SharedMobStateComponent, StartPullAttemptEvent>(OnStartPullAttempt);
|
||||
SubscribeLocalEvent<SharedMobStateComponent, MovementAttemptEvent>(OnMoveAttempt);
|
||||
}
|
||||
|
||||
private void OnStartPullAttempt(EntityUid uid, SharedMobStateComponent component, StartPullAttemptEvent args)
|
||||
{
|
||||
if(component.IsIncapacitated())
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnMoveAttempt(EntityUid uid, SharedMobStateComponent component, MovementAttemptEvent args)
|
||||
{
|
||||
switch (component.CurrentState)
|
||||
{
|
||||
case SharedCriticalMobState:
|
||||
case SharedDeadMobState:
|
||||
args.Cancel();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,6 @@ namespace Content.Shared.MobState
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold);
|
||||
|
||||
void UpdateState(int damage, bool syncing = false);
|
||||
void UpdateState(int damage);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user