2024-04-20 11:51:04 +03:00
using System.Linq ;
2024-12-03 12:34:07 +03:00
using Content.Server.Labels ;
2024-04-20 11:51:04 +03:00
using Content.Shared._CP14.LockKey ;
2024-08-05 15:22:14 +03:00
using Content.Shared._CP14.LockKey.Components ;
using Content.Shared.GameTicking ;
2025-04-30 20:50:03 +03:00
using Content.Shared.Labels.EntitySystems ;
2024-04-02 20:59:40 +03:00
using Robust.Shared.Prototypes ;
using Robust.Shared.Random ;
2024-04-20 11:51:04 +03:00
namespace Content.Server._CP14.LockKey ;
2024-04-02 20:59:40 +03:00
2024-04-20 11:51:04 +03:00
public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
2024-04-02 20:59:40 +03:00
{
[Dependency] private readonly IPrototypeManager _proto = default ! ;
[Dependency] private readonly IRobustRandom _random = default ! ;
2024-12-03 12:34:07 +03:00
[Dependency] private readonly LabelSystem _label = default ! ;
2024-04-02 20:59:40 +03:00
2025-04-24 17:10:52 +03:00
private Dictionary < ProtoId < CP14LockTypePrototype > , List < int > > _roundKeyData = new ( ) ; //TODO: it won't survive saving and loading. This data must be stored in some component.
2024-04-02 20:59:40 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2024-08-05 15:22:14 +03:00
SubscribeLocalEvent < RoundRestartCleanupEvent > ( OnRoundEnd ) ;
2024-04-02 20:59:40 +03:00
2024-04-20 11:51:04 +03:00
SubscribeLocalEvent < CP14LockComponent , MapInitEvent > ( OnLockInit ) ;
SubscribeLocalEvent < CP14KeyComponent , MapInitEvent > ( OnKeyInit ) ;
2024-04-02 20:59:40 +03:00
}
#region Init
2024-08-05 15:22:14 +03:00
private void OnRoundEnd ( RoundRestartCleanupEvent ev )
2024-04-02 20:59:40 +03:00
{
_roundKeyData = new ( ) ;
}
2024-04-20 11:51:04 +03:00
private void OnKeyInit ( Entity < CP14KeyComponent > keyEnt , ref MapInitEvent args )
2024-04-02 20:59:40 +03:00
{
if ( keyEnt . Comp . AutoGenerateShape ! = null )
{
2024-12-03 12:34:07 +03:00
SetShape ( keyEnt , keyEnt . Comp . AutoGenerateShape . Value ) ;
2024-04-02 20:59:40 +03:00
}
}
2024-04-20 11:51:04 +03:00
private void OnLockInit ( Entity < CP14LockComponent > lockEnt , ref MapInitEvent args )
2024-04-02 20:59:40 +03:00
{
if ( lockEnt . Comp . AutoGenerateShape ! = null )
{
2024-12-03 12:34:07 +03:00
SetShape ( lockEnt , lockEnt . Comp . AutoGenerateShape . Value ) ;
2024-04-02 20:59:40 +03:00
}
2025-04-24 17:10:52 +03:00
else if ( lockEnt . Comp . AutoGenerateRandomShape ! = null )
2024-04-02 20:59:40 +03:00
{
2025-04-24 17:10:52 +03:00
SetRandomShape ( lockEnt , lockEnt . Comp . AutoGenerateRandomShape . Value ) ;
2024-04-02 20:59:40 +03:00
}
}
2025-04-24 17:10:52 +03:00
#endregion
2024-04-02 20:59:40 +03:00
2024-12-03 12:34:07 +03:00
private List < int > GetKeyLockData ( ProtoId < CP14LockTypePrototype > category )
2024-04-02 20:59:40 +03:00
{
if ( _roundKeyData . ContainsKey ( category ) )
2025-07-31 23:44:45 +03:00
return new List < int > ( _roundKeyData [ category ] ) ;
2024-10-21 14:20:05 +03:00
var newData = GenerateNewUniqueLockData ( category ) ;
_roundKeyData [ category ] = newData ;
return newData ;
2024-04-02 20:59:40 +03:00
}
2024-12-03 12:34:07 +03:00
public void SetShape ( Entity < CP14KeyComponent > keyEnt , ProtoId < CP14LockTypePrototype > type )
{
keyEnt . Comp . LockShape = GetKeyLockData ( type ) ;
2025-04-24 17:10:52 +03:00
DirtyField ( keyEnt , keyEnt . Comp , nameof ( CP14KeyComponent . LockShape ) ) ;
2024-12-03 12:34:07 +03:00
var indexedType = _proto . Index ( type ) ;
if ( indexedType . Name is not null )
_label . Label ( keyEnt , Loc . GetString ( indexedType . Name . Value ) ) ;
}
public void SetShape ( Entity < CP14LockComponent > lockEnt , ProtoId < CP14LockTypePrototype > 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 ) ) ;
2025-04-24 17:10:52 +03:00
DirtyField ( lockEnt , lockEnt . Comp , nameof ( CP14LockComponent . LockShape ) ) ;
}
public void SetRandomShape ( Entity < CP14LockComponent > lockEnt , int complexity )
{
lockEnt . Comp . LockShape = new List < int > ( ) ;
for ( var i = 0 ; i < complexity ; i + + )
{
lockEnt . Comp . LockShape . Add ( _random . Next ( - SharedCP14LockKeySystem . DepthComplexity , SharedCP14LockKeySystem . DepthComplexity ) ) ;
}
DirtyField ( lockEnt , lockEnt . Comp , nameof ( CP14LockComponent . LockShape ) ) ;
2024-12-03 12:34:07 +03:00
}
private List < int > GenerateNewUniqueLockData ( ProtoId < CP14LockTypePrototype > category )
2024-04-02 20:59:40 +03:00
{
2024-10-21 14:20:05 +03:00
List < int > newKeyData = new ( ) ;
2024-04-02 20:59:40 +03:00
var categoryData = _proto . Index ( category ) ;
var iteration = 0 ;
2024-10-21 14:20:05 +03:00
while ( true )
2024-04-02 20:59:40 +03:00
{
//Generate try
newKeyData = new List < int > ( ) ;
2024-10-21 14:20:05 +03:00
for ( var i = 0 ; i < categoryData . Complexity ; i + + )
2024-04-02 20:59:40 +03:00
{
2024-10-21 14:20:05 +03:00
newKeyData . Add ( _random . Next ( - SharedCP14LockKeySystem . DepthComplexity , SharedCP14LockKeySystem . DepthComplexity ) ) ;
2024-04-02 20:59:40 +03:00
}
2024-10-21 14:20:05 +03:00
// 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.
2024-04-02 20:59:40 +03:00
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
}
}