| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- using System.Diagnostics.CodeAnalysis;
- using Content.Server.NPC.Components;
- using Content.Server.NPC.HTN;
- using Content.Shared.CCVar;
- using Content.Shared.Mind;
- using Content.Shared.Mind.Components;
- using Content.Shared.Mobs;
- using Content.Shared.Mobs.Systems;
- using Content.Shared.NPC;
- using Content.Shared.NPC.Systems;
- using Robust.Server.GameObjects;
- using Robust.Shared.Configuration;
- using Robust.Shared.Player;
- namespace Content.Server.NPC.Systems
- {
- /// <summary>
- /// Handles NPCs running every tick.
- /// </summary>
- public sealed partial class NPCSystem : EntitySystem
- {
- [Dependency] private readonly IConfigurationManager _configurationManager = default!;
- [Dependency] private readonly HTNSystem _htn = default!;
- [Dependency] private readonly MobStateSystem _mobState = default!;
- /// <summary>
- /// Whether any NPCs are allowed to run at all.
- /// </summary>
- public bool Enabled { get; set; } = true;
- private int _maxUpdates;
- private int _count;
- /// <inheritdoc />
- public override void Initialize()
- {
- base.Initialize();
- Subs.CVar(_configurationManager, CCVars.NPCEnabled, value => Enabled = value, true);
- Subs.CVar(_configurationManager, CCVars.NPCMaxUpdates, obj => _maxUpdates = obj, true);
- }
- public void OnPlayerNPCAttach(EntityUid uid, HTNComponent component, PlayerAttachedEvent args)
- {
- SleepNPC(uid, component);
- }
- public void OnPlayerNPCDetach(EntityUid uid, HTNComponent component, PlayerDetachedEvent args)
- {
- if (_mobState.IsIncapacitated(uid) || TerminatingOrDeleted(uid))
- return;
- // This NPC has an attached mind, so it should not wake up.
- if (TryComp<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
- return;
- WakeNPC(uid, component);
- }
- public void OnNPCMapInit(EntityUid uid, HTNComponent component, MapInitEvent args)
- {
- component.Blackboard.SetValue(NPCBlackboard.Owner, uid);
- WakeNPC(uid, component);
- }
- public void OnNPCShutdown(EntityUid uid, HTNComponent component, ComponentShutdown args)
- {
- SleepNPC(uid, component);
- }
- /// <summary>
- /// Is the NPC awake and updating?
- /// </summary>
- public bool IsAwake(EntityUid uid, HTNComponent component, ActiveNPCComponent? active = null)
- {
- return Resolve(uid, ref active, false);
- }
- public bool TryGetNpc(EntityUid uid, [NotNullWhen(true)] out NPCComponent? component)
- {
- // If you add your own NPC components then add them here.
- if (TryComp<HTNComponent>(uid, out var htn))
- {
- component = htn;
- return true;
- }
- component = null;
- return false;
- }
- /// <summary>
- /// Allows the NPC to actively be updated.
- /// </summary>
- public void WakeNPC(EntityUid uid, HTNComponent? component = null)
- {
- if (!Resolve(uid, ref component, false))
- {
- return;
- }
- Log.Debug($"Waking {ToPrettyString(uid)}");
- EnsureComp<ActiveNPCComponent>(uid);
- }
- public void SleepNPC(EntityUid uid, HTNComponent? component = null)
- {
- if (!Resolve(uid, ref component, false))
- {
- return;
- }
- // Don't bother with an event
- if (TryComp<HTNComponent>(uid, out var htn))
- {
- if (htn.Plan != null)
- {
- var currentOperator = htn.Plan.CurrentOperator;
- _htn.ShutdownTask(currentOperator, htn.Blackboard, HTNOperatorStatus.Failed);
- _htn.ShutdownPlan(htn);
- htn.Plan = null;
- }
- }
- Log.Debug($"Sleeping {ToPrettyString(uid)}");
- RemComp<ActiveNPCComponent>(uid);
- }
- /// <inheritdoc />
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
- if (!Enabled)
- return;
- _count = 0;
- // Add your system here.
- _htn.UpdateNPC(ref _count, _maxUpdates, frameTime);
- }
- public void OnMobStateChange(EntityUid uid, HTNComponent component, MobStateChangedEvent args)
- {
- if (HasComp<ActorComponent>(uid))
- return;
- switch (args.NewMobState)
- {
- case MobState.Alive:
- WakeNPC(uid, component);
- break;
- case MobState.Critical:
- case MobState.Dead:
- SleepNPC(uid, component);
- break;
- }
- }
- }
- }
|