Gulag v2 (#21)

* Components или чет типо того

* Gulag System

* Shared shit

* Cvars

* Ban manager update

* Ghost roles shit

* No ooc for gulaged

* Connection manager update

* Gulag proto shit

* Merge conflict issue

* Fixing shit

* Фикс говняхи плюс QOL

* Pendos loc

* better loc

* More qol

* ctrl+s issue

* No bwoink for banned

* Ore shit

* MAP!!!!!!

---------

Co-authored-by: Mona Hmiza <you@example.com>
This commit is contained in:
rhailrake
2024-02-03 11:39:40 +00:00
committed by GitHub
parent 8edae953d7
commit 1594dff648
18 changed files with 5828 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Content.Server._Miracle.GulagSystem;
using Content.Server.Chat.Managers;
using Content.Server.Database;
using Content.Server.GameTicking;
@@ -47,6 +48,7 @@ public sealed class BanManager : IBanManager, IPostInjectInit
public const string UnknownServer = "unknown";
private readonly Dictionary<NetUserId, HashSet<ServerRoleBanDef>> _cachedRoleBans = new();
private readonly Dictionary<NetUserId, HashSet<ServerBanDef>> _cachedServerBans = new(); // Miracle edit
public void Initialize()
{
@@ -63,6 +65,7 @@ public sealed class BanManager : IBanManager, IPostInjectInit
var netChannel = e.Session.Channel;
ImmutableArray<byte>? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId;
await CacheDbRoleBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, hwId);
await CacheDbServerBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, hwId); //Miracle edit
SendRoleBans(e.Session);
}
@@ -97,6 +100,17 @@ public sealed class BanManager : IBanManager, IPostInjectInit
_cachedRoleBans[userId] = userRoleBans;
}
//Miracle edit start
private async Task CacheDbServerBans(NetUserId userId, IPAddress? address = null, ImmutableArray<byte>? hwId = null)
{
var serverBans = await _db.GetServerBansAsync(address, userId, hwId, false);
var userServerBans = new HashSet<ServerBanDef>(serverBans);
_cachedServerBans[userId] = userServerBans;
}
//Miracle edit end
public void Restart()
{
// Clear out players that have disconnected.
@@ -110,6 +124,7 @@ public sealed class BanManager : IBanManager, IPostInjectInit
foreach (var player in toRemove)
{
_cachedRoleBans.Remove(player);
_cachedServerBans.Remove(player); //Miracle edit
}
// Check for expired bans
@@ -117,6 +132,13 @@ public sealed class BanManager : IBanManager, IPostInjectInit
{
roleBans.RemoveWhere(ban => DateTimeOffset.Now > ban.ExpirationTime);
}
//Miracle edit start
foreach (var serverBan in _cachedServerBans.Values)
{
serverBan.RemoveWhere(ban => DateTimeOffset.Now > ban.ExpirationTime);
}
//Miracle edit end
}
#region Server Bans
@@ -182,6 +204,12 @@ public sealed class BanManager : IBanManager, IPostInjectInit
_sawmill.Info(logMessage);
_chat.SendAdminAlert(logMessage);
if (banDef.UserId.HasValue)
{
_cachedServerBans.GetOrNew(banDef.UserId.Value).Add(banDef);
}
// If we're not banning a player we don't care about disconnecting people
if (target == null)
return;
@@ -189,12 +217,32 @@ public sealed class BanManager : IBanManager, IPostInjectInit
// Is the player connected?
if (!_playerManager.TryGetSessionById(target.Value, out var targetPlayer))
return;
// If they are, kick them
var message = banDef.FormatBanMessage(_cfg, _localizationManager);
targetPlayer.Channel.Disconnect(message);
// Kick when perma
if (banDef.ExpirationTime == null)
{
var message = banDef.FormatBanMessage(_cfg, _localizationManager);
targetPlayer.Channel.Disconnect(message);
}
else // Teleport to gulag
{
var gulag = _systems.GetEntitySystem<GulagSystem>();
gulag.SendToGulag(targetPlayer);
}
}
#endregion
//Miracle edit start
public HashSet<ServerBanDef> GetServerBans(NetUserId userId)
{
if (_cachedServerBans.TryGetValue(userId, out var bans))
{
return bans;
}
return new HashSet<ServerBanDef>();
}
//Miracle edit end
#region Job Bans
// If you are trying to remove timeOfBan, please don't. It's there because the note system groups role bans by time, reason and banning admin.
// Removing it will clutter the note list. Please also make sure that department bans are applied to roles with the same DateTimeOffset.

View File

@@ -2,6 +2,7 @@ using System.Collections.Immutable;
using System.Net;
using System.Threading.Tasks;
using Content.Server._White.PandaSocket.Interfaces;
using Content.Server.Database;
using Content.Shared.Database;
using Content.Shared.Roles;
using Robust.Shared.Network;
@@ -28,6 +29,8 @@ public interface IBanManager
public HashSet<string>? GetRoleBans(NetUserId playerUserId);
public HashSet<string>? GetJobBans(NetUserId playerUserId);
public HashSet<ServerBanDef> GetServerBans(NetUserId userId); // Miracle edit
/// <summary>
/// Creates a job ban for the specified target, username or GUID
/// </summary>

View File

@@ -6,6 +6,7 @@ using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Content.Server._Miracle.GulagSystem;
using Content.Server.Administration.Managers;
using Content.Server.GameTicking;
using Content.Server._White.PandaSocket.Main;
@@ -35,6 +36,8 @@ namespace Content.Server.Administration.Systems
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly SharedMindSystem _minds = default!;
[Dependency] private readonly PandaWebManager _pandaWeb = default!; // WD
[Dependency] private readonly GulagSystem _gulagSystem = default!; // Miracle
private ISawmill _sawmill = default!;
private readonly HttpClient _httpClient = new();
@@ -389,6 +392,12 @@ namespace Content.Server.Administration.Systems
base.OnBwoinkTextMessage(message, eventArgs);
var senderSession = eventArgs.SenderSession;
//No bwoink for banned
if (_gulagSystem.IsUserGulaged(senderSession.UserId, out _))
{
return;
}
// TODO: Sanitize text?
// Confirm that this person is actually allowed to send a message here.
var personalChannel = senderSession.UserId == message.UserId;

View File

@@ -1,3 +1,4 @@
using Content.Server._Miracle.GulagSystem;
using Content.Server.Chat.Managers;
using Content.Shared.Administration;
using Robust.Shared.Console;
@@ -19,6 +20,12 @@ namespace Content.Server.Chat.Commands
return;
}
var gulag = EntitySystem.Get<GulagSystem>();
if (gulag.IsUserGulaged(shell.Player.UserId, out var _))
{
return;
}
if (args.Length < 1)
return;

View File

@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Database;
using Content.Server.GameTicking;
@@ -170,7 +171,7 @@ namespace Content.Server.Connection
//WD-EDIT
var bans = await _db.GetServerBansAsync(addr, userId, hwId, includeUnbanned: false);
if (bans.Count > 0)
if (bans.Count > 0 && bans.Any(x=> x.ExpirationTime == null)) //Miracle edit
{
var firstBan = bans[0];
var message = firstBan.FormatBanMessage(_cfg, _loc);

View File

@@ -1,3 +1,4 @@
using Content.Server._Miracle.GulagSystem;
using Content.Server.Administration.Logs;
using Content.Server.EUI;
using Content.Server.Ghost.Roles.Components;
@@ -37,6 +38,8 @@ namespace Content.Server.Ghost.Roles
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly GulagSystem _gulagSystem = default!;
private uint _nextRoleIdentifier;
private bool _needsUpdateGhostRoleCount = true;
@@ -201,6 +204,11 @@ namespace Content.Server.Ghost.Roles
if (!_ghostRoles.TryGetValue(identifier, out var role))
return;
if (_gulagSystem.IsUserGulaged(player.UserId, out _))
{
return;
}
var ev = new TakeGhostRoleEvent(player);
RaiseLocalEvent(role, ref ev);

View File

@@ -0,0 +1,9 @@
using Content.Shared._Miracle.GulagSystem;
namespace Content.Server._Miracle.Components;
[RegisterComponent]
[Access(typeof(SharedGulagSystem))]
public sealed partial class GulagBoundComponent : Component
{
}

View File

@@ -0,0 +1,10 @@
using Content.Shared._Miracle.GulagSystem;
namespace Content.Server._Miracle.Components;
[RegisterComponent]
[Access(typeof(SharedGulagSystem))]
public sealed partial class GulagFillContainerComponent : Component
{
}

View File

@@ -0,0 +1,14 @@
using Content.Shared._Miracle.GulagSystem;
using Robust.Shared.Network;
namespace Content.Server._Miracle.Components;
[RegisterComponent]
[Access(typeof(SharedGulagSystem))]
public sealed partial class GulagOreProcessorComponent : Component
{
//I hate my life
public NetUserId? LastInteractedUser;
}

View File

@@ -0,0 +1,462 @@
using System.Linq;
using Content.Server._Miracle.Components;
using Content.Server.Administration.Managers;
using Content.Server.Administration.Systems;
using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Server.Chat.Managers;
using Content.Server.Database;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Server.KillTracking;
using Content.Server.Materials;
using Content.Server.Mind;
using Content.Server.Parallax;
using Content.Server.Preferences.Managers;
using Content.Server.Spawners.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.Storage.EntitySystems;
using Content.Shared._Miracle.Cvars;
using Content.Shared._Miracle.GulagSystem;
using Content.Shared.GameTicking;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Materials;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Popups;
using Content.Shared.Preferences;
using Content.Shared.Throwing;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._Miracle.GulagSystem;
public sealed partial class GulagSystem : SharedGulagSystem
{
//1 second = 10 points
[Dependency] private readonly AdminSystem _adminSystem = default!;
[Dependency] private readonly IBanManager _banManager = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly IServerDbManager _db = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StationSpawningSystem _spawningSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly CargoSystem _cargoSystem = default!;
[Dependency] private readonly MaterialStorageSystem _materialStorageSystem = default!;
[Dependency] private readonly EntityStorageSystem _entityStorageSystem = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IServerPreferencesManager _preferencesManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
private readonly List<ProtoId<BiomeTemplatePrototype>> _gulagBiomes = new()
{
"GulagBiome"
};
private readonly List<string> _gulagMaps = new()
{
"/Maps/Gulags/gulag.yml"
};
private double _timeToPointsRatio;
private MapId? _activeMap;
private EntityUid? _mapEntity;
private readonly TimeSpan _safeguardUpdateRate = TimeSpan.FromSeconds(10);
private DateTime _nextSafeguardUpdate = DateTime.MinValue;
private readonly TimeSpan _shuttleFillUpdateRate = TimeSpan.FromMinutes(10);
private DateTime _nextShuttleFillUpdate = DateTime.MinValue;
private List<EntityCoordinates> _spawnCoords = new();
private readonly Dictionary<NetUserId, double> _pointsPerPlayer = new();
private readonly Dictionary<ProtoId<MaterialPrototype>, int> _gulagMaterialStorage = new();
public override void Initialize()
{
base.Initialize();
_cfg.OnValueChanged(MiracleCvars.GulagPointsToTimeRatio, newValue => _timeToPointsRatio = newValue, true);
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStarting);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
SubscribeLocalEvent<PlayerBeforeSpawnEvent>(BeforeSpawn);
SubscribeLocalEvent<GulagOreProcessorComponent, MaterialEntityInsertedEvent>(OnOreInserted);
SubscribeLocalEvent<GulagOreProcessorComponent, InteractUsingEvent>(OnInteract, before: new[] {typeof(MaterialStorageSystem)});
SubscribeLocalEvent<GulagFillContainerComponent, MapInitEvent>(OnGulagContainerSpawned);
SubscribeLocalEvent<KillReportedEvent>(OnKillReported);
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnJoinedLobby);
//safeguard
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
}
private void OnJoinedLobby(PlayerJoinedLobbyEvent ev)
{
if(IsUserGulaged(ev.PlayerSession.UserId, out _))
{
_chatManager.DispatchServerMessage(ev.PlayerSession, Loc.GetString("gulag-chat-join-message"));
}
}
private void OnKillReported(ref KillReportedEvent ev)
{
if (!HasComp<GulagBoundComponent>(ev.Entity))
{
return;
}
if (ev.Primary is not KillPlayerSource source)
{
return;
}
var player = source.PlayerId;
if (!IsUserGulaged(player, out var ban))
{
return;
}
var banDef = ban.First();
var newExpirationTime = banDef.ExpirationTime!.Value.DateTime + TimeSpan.FromDays(1);
_db.EditServerBan(banDef.Id!.Value, banDef.Reason, banDef.Severity, newExpirationTime, banDef.UserId!.Value, DateTime.Now);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
Safeguard();
TryFillCargoShuttle();
}
private void OnGulagContainerSpawned(EntityUid uid, GulagFillContainerComponent component, MapInitEvent args)
{
var coords = Transform(uid).Coordinates;
foreach (var (materialId, value) in _gulagMaterialStorage)
{
var materialEntities = _materialStorageSystem.SpawnMultipleFromMaterial(value, materialId, coords);
foreach (var material in materialEntities)
{
_entityStorageSystem.Insert(material, uid);
}
}
_gulagMaterialStorage.Clear();
}
private void TryFillCargoShuttle()
{
if (_nextShuttleFillUpdate > DateTime.Now)
{
return;
}
if (_gulagMaterialStorage.Count == 0)
{
return;
}
var station = GetMainStation();
if (!station.HasValue)
{
return;
}
if (!TryComp<StationCargoOrderDatabaseComponent>(station.Value, out var comp))
{
return;
}
_cargoSystem.AddAndApproveOrder(station.Value, "CrateGulag", 0, 1, Loc.GetString("gulag-sender"),
Loc.GetString("gulag-order-description"), Loc.GetString("gulag-order-destination"), comp);
_nextShuttleFillUpdate = DateTime.Now + _shuttleFillUpdateRate;
}
// Just check if we need to bring back somehow escaped players
private void Safeguard()
{
if (_nextSafeguardUpdate > DateTime.Now)
{
return;
}
var querry = EntityQueryEnumerator<GulagBoundComponent, TransformComponent>();
while (querry.MoveNext(out var uid, out var gulagbound, out var xform))
{
if (xform.MapID != _activeMap)
{
SendToGulag(uid);
}
}
_nextSafeguardUpdate = DateTime.Now + _safeguardUpdateRate;
}
public void SendToGulag(ICommonSession session)
{
var playerEntity = session.AttachedEntity;
if (_mapEntity == null)
{
_adminSystem.Erase(session);
return;
}
if (playerEntity.HasValue)
{
SendToGulag(playerEntity.Value);
}
else
{
SpawnPlayer(session, (HumanoidCharacterProfile)_preferencesManager.GetPreferences(session.UserId).SelectedCharacter);
}
var banDef = _banManager.GetServerBans(session.UserId).First();
var message = Loc.GetString("gulag-greetings-message", ("BanTime", $"{(banDef.ExpirationTime! - DateTime.Now).Value.TotalHours}"));
_chatManager.DispatchServerMessage(session, message);
}
private void OnInteract(EntityUid uid, GulagOreProcessorComponent component, InteractUsingEvent args)
{
//It wasn't player who interacted with the entity
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
{
return;
}
component.LastInteractedUser = session.UserId;
Log.Info("OnInteract raised");
}
private void OnOreInserted(EntityUid uid, GulagOreProcessorComponent component, MaterialEntityInsertedEvent args)
{
var storageComponent = Comp<MaterialStorageComponent>(uid);
var userId = component.LastInteractedUser!.Value;
foreach (var (materialId, currentVolume ) in storageComponent.Storage)
{
var materialPrototype = _prototypeManager.Index<MaterialPrototype>(materialId.Id);
var stackVolume = _materialStorageSystem.GetSheetVolume(materialPrototype);
var actualOreCount = currentVolume / stackVolume;
var points = materialPrototype.Price * actualOreCount;
_pointsPerPlayer[userId] = points + _pointsPerPlayer.GetValueOrDefault(userId);
_gulagMaterialStorage[materialId] = currentVolume + _gulagMaterialStorage.GetValueOrDefault(materialId);
_materialStorageSystem.TrySetMaterialAmount(uid, materialId, 0);
}
var time = ConvertPointsToTime(_pointsPerPlayer[userId]);
_popupSystem.PopupEntity(Loc.GetString("gulag-ban-time-changed", ("Time", $"{time.TotalSeconds}")), uid, PopupType.Medium);
}
public bool IsUserGulaged(NetUserId playerId, out HashSet<ServerBanDef> bans)
{
bans = _banManager.GetServerBans(playerId);
return bans.Count != 0;
}
private void SendToGulag(EntityUid playerEntity)
{
if (_inventorySystem.TryGetContainerSlotEnumerator(playerEntity, out var enumerator))
{
while (enumerator.NextItem(out var item, out var slot))
{
if (_inventorySystem.TryUnequip(playerEntity, playerEntity, slot.Name, true, true))
_physicsSystem.ApplyAngularImpulse(item, ThrowingSystem.ThrowAngularImpulse);
}
}
if (TryComp(playerEntity, out HandsComponent? hands))
{
foreach (var hand in _handsSystem.EnumerateHands(playerEntity, hands))
{
_handsSystem.TryDrop(playerEntity, hand, checkActionBlocker: false, doDropInteraction: false,
handsComp: hands);
}
}
var newPosition = GetSpawnPosition();
_transformSystem.SetCoordinates(playerEntity, newPosition);
_transformSystem.AttachToGridOrMap(playerEntity);
EnsureComp<GulagBoundComponent>(playerEntity);
EnsureComp<KillTrackerComponent>(playerEntity);
}
private void SpawnPlayer(ICommonSession session, HumanoidCharacterProfile profile)
{
var newMind = _mind.CreateMind(session.UserId, profile.Name);
_mind.SetUserId(newMind, session.UserId);
var coords = GetSpawnPosition();
var mob = _spawningSystem.SpawnPlayerMob(coords, null, profile, null);
_mind.TransferTo(newMind, mob);
EnsureComp<GulagBoundComponent>(mob);
EnsureComp<KillTrackerComponent>(mob);
}
private void OnPlayerAttached(PlayerAttachedEvent ev)
{
var bans = _banManager.GetServerBans(ev.Player.UserId);
if (bans.Count == 0)
{
return;
}
var xform = Transform(ev.Entity);
if (xform.MapID != _activeMap)
{
SendToGulag(ev.Player);
}
}
private void BeforeSpawn(PlayerBeforeSpawnEvent ev)
{
var bans = _banManager.GetServerBans(ev.Player.UserId);
if (bans.Count == 0)
{
return;
}
ev.Handled = true;
SendToGulag(ev.Player);
}
private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
foreach (var (player, points) in _pointsPerPlayer)
{
var banDef = _banManager.GetServerBans(player).FirstOrDefault();
if (banDef == null)
{
continue;
}
var newExpirationTime = banDef.ExpirationTime!.Value.DateTime - ConvertPointsToTime(points);
_db.EditServerBan(banDef.Id!.Value, banDef.Reason, banDef.Severity, newExpirationTime, banDef.UserId!.Value, DateTime.Now);
}
_activeMap = null!;
_mapEntity = null!;
}
private void OnRoundStarting(RoundStartingEvent ev)
{
//Spawn Gulag
var mapId = _mapManager.CreateMap();
var mapUid = _mapManager.GetMapEntityId(mapId);
_metaData.SetEntityName(mapUid, "Gulag Map");
_mapManager.AddUninitializedMap(mapId);
var pickedMap = _random.Pick(_gulagMaps);
if (!_mapLoader.TryLoad(mapId, pickedMap, out var uids))
{
_mapManager.DeleteMap(mapId);
Log.Error("Can't spawn map with path {0}", pickedMap);
return;
}
foreach (var uid in uids)
{
_metaData.SetEntityName(uid, $"Gulag grid {uid}");
}
var pickerBiome = _random.Pick(_gulagBiomes);
_biome.EnsurePlanet(mapUid, _prototypeManager.Index<BiomeTemplatePrototype>(pickerBiome));
_mapManager.DoMapInitialize(mapId);
_activeMap = mapId;
_mapEntity = mapUid;
//Item2 = TransformComponent
_spawnCoords = EntityQuery<SpawnPointComponent, TransformComponent>()
.Where(x => x.Item2.MapID == mapId)
.Select(x => x.Item2.Coordinates)
.ToList();
}
private TimeSpan ConvertPointsToTime(double points)
{
return TimeSpan.FromSeconds(points / _timeToPointsRatio);
}
private EntityCoordinates GetSpawnPosition()
{
return _spawnCoords.Count != 0 ? _random.Pick(_spawnCoords) : Transform(_mapEntity!.Value).Coordinates;
}
private EntityUid? GetMainStation()
{
var stations = _stationSystem.GetStations();
foreach (var station in stations)
{
var stationData = Comp<StationDataComponent>(station);
if (!HasComp<StationCargoOrderDatabaseComponent>(station))
{
continue;
}
foreach (var grid in stationData.Grids)
{
if (Transform(grid).MapID == _gameTicker.DefaultMap)
{
return station;
}
}
}
return null!;
}
}

View File

@@ -0,0 +1,12 @@
using Robust.Shared.Configuration;
namespace Content.Shared._Miracle.Cvars;
[CVarDefs]
public sealed class MiracleCvars
{
// <points> / <ratio> = <time_in_seconds>
// 100 / 10 = 10
public static readonly CVarDef<double> GulagPointsToTimeRatio = CVarDef.Create("miracle.gulag.points_to_time",
10.0d, CVar.SERVERONLY, "<points> / <ratio> = <time_in_seconds>");
}

View File

@@ -0,0 +1,6 @@
namespace Content.Shared._Miracle.GulagSystem;
public abstract class SharedGulagSystem : EntitySystem
{
}

View File

@@ -0,0 +1,15 @@
ent-GulagOreProcessor = Ore Receiver.
.desc = Load ore, reduce your sentence.
ent-CrateGulag = Ore Container.
.desc = Ore straight from NanoTrasen's mining facility.
gulag-sender = NanoTrasen Mining Facility.
gulag-order-description = With love from our miners.
gulag-order-destination = Supply Department.
gulag-greetings-message = You have been sent to the correctional labor camp for violating local laws. You can shorten your sentence by mining ore and shipping it to the ore receiver. Remaining punishment time: { $BanTime } hours.
gulag-ban-time-changed = Your sentence has been reduced by { $Time } seconds.
gulag-chat-join-message = Welcome to the server. Due to violations committed by you, it has been decided to give you the opportunity to redeem your guilt through hard labor. After the start of the game round, you will be sent to the correctional labor camp, where you will be tasked with mining ore to reduce the duration of your punishment. It is important to note that killing your fellow unfortunate will increase your sentence by 1 day. We wish you luck in serving your sentence!

View File

@@ -0,0 +1,14 @@
ent-GulagOreProcessor = Приемник руды с трудового лагеря.
.desc = Загружаешь руду, сокращаешь срок.
ent-CrateGulag = Контейнер руды.
.desc = Руда прямиком с горнодобывающего предприятия НаноТразена.
gulag-sender = Горнодобывающее предприятие НаноТразен.
gulag-order-description = С любовью от наших горняков.
gulag-order-destination = Отдел снабжения.
gulag-greetings-message = Вы были отправлены в исправительный лагерь за нарушение местных законов. Вы можете сократить свой срок добывая руду и отгружая её в приёмник руды. Оставшийся срок наказания { $BanTime } часов.
gulag-ban-time-changed = Ваш срок был сокращен на { $Time } секунд.
gulag-chat-join-message = Добро пожаловать на сервер. В связи с нарушениями, совершенными вами, было принято решение предоставить вам возможность искупить свою вину через тяжелый труд. После начала игрового раунда вы будете отправлены в исправительный лагерь, где вам предстоит добывать руду, чтобы сократить срок своего наказания. Важно отметить, что за убийство своего собрата по несчастью ваш срок будет увеличен на 1 день. Желаем вам удачи в исполнении наказания!

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
# Caves
- type: biomeTemplate
id: GulagBiome
layers:
- !type:BiomeEntityLayer
threshold: 0.85
noise:
seed: 2
noiseType: OpenSimplex2
fractalType: PingPong
allowedTiles:
- FloorAsteroidSand
entities:
- CrystalGreen
- CrystalPink
- CrystalOrange
- CrystalBlue
- CrystalCyan
- !type:BiomeEntityLayer
threshold: 0.95
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 1
allowedTiles:
- FloorAsteroidSand
entities:
- FloraStalagmite1
- FloraStalagmite2
- FloraStalagmite3
- FloraStalagmite4
- FloraStalagmite5
- FloraStalagmite6
- !type:BiomeEntityLayer
threshold: -0.5
invert: true
noise:
seed: 0
noiseType: Perlin
fractalType: Ridged
octaves: 1
frequency: 0.1
gain: 0.5
allowedTiles:
- FloorAsteroidSand
entities:
- GulagWallRock
- !type:BiomeDummyLayer
id: Loot
- !type:BiomeTileLayer
threshold: -1.0
tile: FloorAsteroidSand
variants:
- 0
- !type:BiomeTileLayer
threshold: 0.5
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 2
tile: FloorAsteroidSand
- type: entity
id: GulagWallRock
parent: WallRock
name: rock
suffix: planetmap
components:
- type: OreVein
oreChance: 0.25
oreRarityPrototypeId: RandomGulagOreDistributionStandard
- type: weightedRandomOre
id: RandomGulagOreDistributionStandard
weights:
OreSteel: 10
OreCoal: 10
OreSpaceQuartz: 8
OreGold: 2
OrePlasma: 4
OreSilver: 1
OreUranium: 1
OreBananium: 0.5

View File

@@ -0,0 +1,6 @@
- type: entity
id: CrateGulag
parent: CrateGenericSteel
noSpawn: true
components:
- type: GulagFillContainer

View File

@@ -0,0 +1,38 @@
- type: entity
id: GulagOreProcessor
name: gulagMachine
description: Shit
parent: BaseMachinePowered
suffix: NoSpawn
components:
- type: Sprite
sprite: Structures/Machines/ore_processor.rsi
layers:
- state: icon
map: [ "enum.LatheVisualLayers.IsRunning" ]
- state: unlit
shader: unshaded
map: [ "enum.PowerDeviceVisualLayers.Powered" ]
- state: inserting
map: [ "enum.MaterialStorageVisualLayers.Inserting" ]
- state: panel
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
- type: MaterialStorage
ignoreColor: true
whitelist:
tags:
- Ore
- type: GulagOreProcessor
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeAabb
bounds: "-0.4,-0.4,0.4,0.4"
density: 190
mask:
- MachineMask
layer:
- MachineLayer
- type: Transform
anchored: true