using System.Linq; using Content.Server.Labels; using Content.Shared._CP14.LockKey; using Content.Shared._CP14.LockKey.Components; using Content.Shared.GameTicking; using Content.Shared.Labels.EntitySystems; using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server._CP14.LockKey; public sealed partial class CP14KeyholeGenerationSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly LabelSystem _label = default!; private Dictionary, List> _roundKeyData = new(); //TODO: it won't survive saving and loading. This data must be stored in some component. public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnRoundEnd); SubscribeLocalEvent(OnLockInit); SubscribeLocalEvent(OnKeyInit); } #region Init private void OnRoundEnd(RoundRestartCleanupEvent ev) { _roundKeyData = new(); } private void OnKeyInit(Entity keyEnt, ref MapInitEvent args) { if (keyEnt.Comp.AutoGenerateShape != null) { SetShape(keyEnt, keyEnt.Comp.AutoGenerateShape.Value); } } private void OnLockInit(Entity lockEnt, ref MapInitEvent args) { if (lockEnt.Comp.AutoGenerateShape != null) { SetShape(lockEnt, lockEnt.Comp.AutoGenerateShape.Value); } else if (lockEnt.Comp.AutoGenerateRandomShape != null) { SetRandomShape(lockEnt, lockEnt.Comp.AutoGenerateRandomShape.Value); } } #endregion private List GetKeyLockData(ProtoId category) { if (_roundKeyData.ContainsKey(category)) return new List(_roundKeyData[category]); var newData = GenerateNewUniqueLockData(category); _roundKeyData[category] = newData; return newData; } public void SetShape(Entity keyEnt, ProtoId type) { keyEnt.Comp.LockShape = GetKeyLockData(type); DirtyField(keyEnt, keyEnt.Comp, nameof(CP14KeyComponent.LockShape)); var indexedType = _proto.Index(type); if (indexedType.Name is not null) _label.Label(keyEnt, Loc.GetString(indexedType.Name.Value)); } public void SetShape(Entity lockEnt, ProtoId type) { lockEnt.Comp.LockShape = GetKeyLockData(type); var indexedType = _proto.Index(type); if (indexedType.Name is not null) _label.Label(lockEnt, Loc.GetString(indexedType.Name.Value)); DirtyField(lockEnt, lockEnt.Comp, nameof(CP14LockComponent.LockShape)); } public void SetRandomShape(Entity lockEnt, int complexity) { lockEnt.Comp.LockShape = new List(); for (var i = 0; i < complexity; i++) { lockEnt.Comp.LockShape.Add(_random.Next(-SharedCP14LockKeySystem.DepthComplexity, SharedCP14LockKeySystem.DepthComplexity)); } DirtyField(lockEnt, lockEnt.Comp, nameof(CP14LockComponent.LockShape)); } private List GenerateNewUniqueLockData(ProtoId category) { List newKeyData = new(); var categoryData = _proto.Index(category); var iteration = 0; while (true) { //Generate try newKeyData = new List(); for (var i = 0; i < categoryData.Complexity; i++) { newKeyData.Add(_random.Next(-SharedCP14LockKeySystem.DepthComplexity, SharedCP14LockKeySystem.DepthComplexity)); } // Identity Check shit code // It is currently trying to generate a unique code. If it fails to generate a unique code 100 times, it will output the last generated non-unique code. var unique = true; foreach (var pair in _roundKeyData) { if (newKeyData.SequenceEqual(pair.Value)) { unique = false; break; } } if (unique) return newKeyData; else iteration++; if (iteration > 100) { break; } } Log.Error("The unique key for CPLockSystem could not be generated!"); return newKeyData; //FUCK } }