using System; using System.Collections.Generic; using Content.Server.AI.Utility.AiLogic; using Content.Server.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement; using JetBrains.Annotations; using Robust.Server.AI; using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Timing; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Reflection; using Robust.Shared.IoC; using Robust.Shared.Utility; namespace Content.Server.GameObjects.EntitySystems.AI { [UsedImplicitly] internal class AiSystem : EntitySystem { #pragma warning disable 649 [Dependency] private readonly IPauseManager _pauseManager; [Dependency] private readonly IDynamicTypeFactory _typeFactory; [Dependency] private readonly IReflectionManager _reflectionManager; #pragma warning restore 649 private readonly Dictionary _processorTypes = new Dictionary(); /// public override void Initialize() { base.Initialize(); var processors = _reflectionManager.GetAllChildren(); foreach (var processor in processors) { var att = (AiLogicProcessorAttribute)Attribute.GetCustomAttribute(processor, typeof(AiLogicProcessorAttribute)); // Tests should pick this up DebugTools.AssertNotNull(att); _processorTypes.Add(att.SerializeName, processor); } } /// public override void Update(float frameTime) { foreach (var comp in ComponentManager.EntityQuery()) { if (_pauseManager.IsEntityPaused(comp.Owner)) { continue; } ProcessorInitialize(comp); var processor = comp.Processor; processor.Update(frameTime); } } /// /// Will start up the controller's processor if not already done so /// /// public void ProcessorInitialize(AiControllerComponent controller) { if (controller.Processor != null) return; controller.Processor = CreateProcessor(controller.LogicName); controller.Processor.SelfEntity = controller.Owner; controller.Processor.Setup(); } private AiLogicProcessor CreateProcessor(string name) { if (_processorTypes.TryGetValue(name, out var type)) { return (AiLogicProcessor)_typeFactory.CreateInstance(type); } // processor needs to inherit AiLogicProcessor, and needs an AiLogicProcessorAttribute to define the YAML name throw new ArgumentException($"Processor type {name} could not be found.", nameof(name)); } public bool ProcessorTypeExists(string name) => _processorTypes.ContainsKey(name); private class AddAiCommand : IClientCommand { public string Command => "addai"; public string Description => "Add an ai component with a given processor to an entity."; public string Help => "Usage: addai " + "\n processorId: Class that inherits AiLogicProcessor and has an AiLogicProcessor attribute." + "\n entityID: Uid of entity to add the AiControllerComponent to. Open its VV menu to find this."; public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) { if(args.Length != 2) { shell.SendText(player, "Wrong number of args."); return; } var processorId = args[0]; var entId = new EntityUid(int.Parse(args[1])); var ent = IoCManager.Resolve().GetEntity(entId); var aiSystem = EntitySystem.Get(); if (!aiSystem.ProcessorTypeExists(processorId)) { shell.SendText(player, "Invalid processor type. Processor must inherit AiLogicProcessor and have an AiLogicProcessor attribute."); return; } if (ent.HasComponent()) { shell.SendText(player, "Entity already has an AI component."); return; } if (ent.HasComponent()) { ent.RemoveComponent(); } var comp = ent.AddComponent(); comp.LogicName = processorId; shell.SendText(player, "AI component added."); } } } }