Files
wwdpublic/Content.Server/Clothing/Systems/LoadoutSystem.cs
Yarik 7b502a53fc Biggest books update (#772)
* Большое обновление книжек

* Remove dotnet tool cache artifacts

* Remove dotnet tool cache artifacts 2

* All comments on English

* Add all validation

* All localization, code reduction, named bookmarks system

* Add "try catch" because coderabbitai asked

* Add base check content length

* Fix "\\n"

* the "BookRandomStory" system has been fix and translate

* little fix "BookRandomStory" system

* 2 little fix "BookRandomStory" system

* 3 little fix "BookRandomStory" system

* 4 little fix "BookRandomStory" system

* 5 little fix "BookRandomStory" system

* Improved handling of UTF-8 character truncation

* 2 Improved validation and handling of UTF-8 character truncation

* Mini-up for author_books

* add new author book for botany

* Smaller long of text on one page

* translation of the new janitor's book

* Spelling lesson

* Make TODO notes

* Translate TODO notes...

* little fix "Check the status of the dialog before using it."

* DONE: Create new pages to transfer text, not replace old ones

* DONE: Make it visible when the text limit per page is exceeded

* DONE: Make it possible to delete unnecessary pages

* Fall protection on incorrect markings

* fix ".ftl"

* Text length limit for SplitContentIntoPages

* change limits

* Add sound

* Add placeholder to loadouts and new symbol for CreateNewPage

* Apply some suggestions from code review

All changes, except moving files into White folders

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* Apply some suggestions from code review 2

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* Transfering into "_White" folder

* Remove dublicate code

* Added the necessary code

* Add method

* BookSystem has been transfered into "Shared" folder

* Add attributions for ".ogg"

* changes for tools have been canceled

* Apply some suggestions from code review 3

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* content have been transfered into "_White" folder 2

* Little fix locales

* Apply some suggestions from code review 4

Add comments in "Resources/Prototypes/Entities/Objects/Misc/books_author.yml"

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* content have been transfered into "_White" folder and translate

* English spelling lesson

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* Add BookRandomeStorySystem

* Apply some suggestions from code review 5

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* rolling back some changes from "code review 5"

* Spelling lesson 2

* tweak BookSystem. (Apply suggestion from code review)

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* Little fix bookmark-default-title

* Apply some suggestions from code review 6

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* fix code review changes and transfer "BookRandomStorySystem.cs" into "Content.System"

* Half of good locales

* full good locales of RandomStorySystem

* Spelling lesson 3

* Removed unnecessary StoryGen file

* Fixed bookmarks pos after del any page

* Transd files into _White folder

* Fixed the constant activity of the add page button

* Correction at the request of coderabbitai

* Transfered at the request of code review

* Transfered at the request of code review 2

* Fix transfer

* Apply suggestions from code review 7

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>

* Apply suggestions from code review 8

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Apply and fix all suggestions from code review of file "BookWindow.xaml.cs"

* Fix formated

* Apply some suggestions from code review 9

maybe last...

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Add try catch on texture loading

* Add Dispose method

* Correct display of blank pages

* Little fix eng locale

* Unnecessary code removed

* A Little Defense Against NRE/KeyNotFound.

* Highlighting the current page in the bookmarks drop-down list.

* Added fallback for the save button when there is no hotkey.

* Correct unsubscribing from events.

* Little fix save button

* Little fix formated

* Locales transfered fix

---------

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-30 17:35:36 +03:00

185 lines
7.9 KiB
C#

using System.Linq;
using Content.Server.Paint;
using Content.Server.Players.PlayTimeTracking;
using Content.Shared._White.Book;
using Content.Shared._White.Book.Components;
using Content.Shared.CCVar;
using Content.Shared.Clothing.Loadouts.Prototypes;
using Content.Shared.Clothing.Loadouts.Systems;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Players;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.Storage;
using Content.Shared.Storage.EntitySystems;
using Content.Shared.Traits.Assorted.Components;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager;
namespace Content.Server.Clothing.Systems;
public sealed class LoadoutSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly SharedLoadoutSystem _loadout = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedStorageSystem _storage = default!;
[Dependency] private readonly PlayTimeTrackingManager _playTimeTracking = default!;
[Dependency] private readonly PaintSystem _paint = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly ILogManager _log = default!;
[Dependency] private readonly BookSystem _bookSystem = default!; // WD EDIT
private ISawmill _sawmill = default!;
public override void Initialize()
{
_sawmill = _log.GetSawmill("loadouts");
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
SubscribeLocalEvent<LoadProfileExtensionsEvent>(OnProfileLoad);
}
private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent ev)
{
if (ev.JobId == null || Deleted(ev.Mob) || !Exists(ev.Mob)
|| !HasComp<MetaDataComponent>(ev.Mob) // TODO: FIND THE STUPID RACE CONDITION THAT IS MAKING ME CHECK FOR THIS.
|| !_protoMan.TryIndex<JobPrototype>(ev.JobId, out var job)
|| !_configurationManager.GetCVar(CCVars.GameLoadoutsEnabled))
return;
ApplyCharacterLoadout(
ev.Mob,
ev.JobId,
ev.Profile,
_playTimeTracking.GetTrackerTimes(ev.Player),
ev.Player.ContentData()?.Whitelisted ?? false,
jobProto: job);
RaiseLocalEvent(ev.Mob, new PlayerLoadoutAppliedEvent(ev.Mob, ev.Player, ev.JobId, ev.LateJoin, ev.Silent, ev.JoinOrder, ev.Station, ev.Profile), broadcast: true);
}
private void OnProfileLoad(LoadProfileExtensionsEvent ev)
{
if (ev.JobId == null || Deleted(ev.Mob) || !Exists(ev.Mob)
|| !HasComp<MetaDataComponent>(ev.Mob) // TODO: FIND THE STUPID RACE CONDITION THAT IS MAKING ME CHECK FOR THIS.
|| !_protoMan.TryIndex<JobPrototype>(ev.JobId, out var job)
|| !_configurationManager.GetCVar(CCVars.GameLoadoutsEnabled))
return;
ApplyCharacterLoadout(
ev.Mob,
ev.JobId,
ev.Profile,
_playTimeTracking.GetTrackerTimes(ev.Player),
ev.Player.ContentData()?.Whitelisted ?? false,
jobProto: job);
}
/// Equips every loadout, then puts whatever extras it can in inventories
public void ApplyCharacterLoadout(
EntityUid uid,
ProtoId<JobPrototype> job,
HumanoidCharacterProfile profile,
Dictionary<string, TimeSpan> playTimes,
bool whitelisted,
bool deleteFailed = false,
JobPrototype? jobProto = null)
{
// Spawn the loadout, get a list of items that failed to equip
var (failedLoadouts, allLoadouts) =
_loadout.ApplyCharacterLoadout(uid, job, profile, playTimes, whitelisted, out var heirlooms);
// Try to find back-mounted storage apparatus
if (_inventory.TryGetSlotEntity(uid, "back", out var item) &&
EntityManager.TryGetComponent<StorageComponent>(item, out var inventory))
// Try inserting the entity into the storage, if it can't, it leaves the loadout item on the ground
foreach (var loadout in failedLoadouts)
if ((!EntityManager.TryGetComponent<ItemComponent>(loadout, out var itemComp)
|| !_storage.CanInsert(item.Value, loadout, out _, inventory, itemComp)
|| !_storage.Insert(item.Value, loadout, out _, playSound: false))
&& deleteFailed)
EntityManager.QueueDeleteEntity(loadout);
foreach (var loadout in allLoadouts)
{
if (loadout.Item1 == EntityUid.Invalid
|| !HasComp<MetaDataComponent>(loadout.Item1)
|| Deleted(loadout.Item1))
{
_sawmill.Warning($"Loadout {loadout.Item2.LoadoutName} failed to load properly, deleting.");
EntityManager.QueueDeleteEntity(loadout.Item1);
continue;
}
var loadoutProto = _protoMan.Index<LoadoutPrototype>(loadout.Item2.LoadoutName);
if (loadoutProto.CustomName && loadout.Item2.CustomName != null)
_meta.SetEntityName(loadout.Item1, loadout.Item2.CustomName);
if (loadoutProto.CustomDescription && loadout.Item2.CustomDescription != null)
_meta.SetEntityDescription(loadout.Item1, loadout.Item2.CustomDescription);
// WD EDIT START
if (!string.IsNullOrEmpty(loadout.Item2.CustomContent) && TryComp<BookComponent>(loadout.Item1, out var bookComponent))
{
try
{
_bookSystem.SplitContentIntoPages(bookComponent, loadout.Item2.CustomContent);
Dirty(loadout.Item1, bookComponent);
}
catch (Exception ex)
{
_sawmill.Error($"Failed to apply custom book content to loadout {loadout.Item2.LoadoutName}: {ex.Message}");
}
}
// WD EDIT END
if (loadoutProto.CustomColorTint && !string.IsNullOrEmpty(loadout.Item2.CustomColorTint))
_paint.Paint(null, null, loadout.Item1, Color.FromHex(loadout.Item2.CustomColorTint));
foreach (var component in loadoutProto.Components.Values)
{
if (HasComp(loadout.Item1, component.Component.GetType()))
continue;
var comp = (Component) _serialization.CreateCopy(component.Component, notNullableOverride: true);
comp.Owner = loadout.Item1;
EntityManager.AddComponent(loadout.Item1, comp);
}
foreach (var function in loadoutProto.Functions)
function.OnPlayerSpawn(uid, loadout.Item1, _componentFactory, EntityManager, _serialization);
}
// Pick the heirloom
if (heirlooms.Any())
{
var heirloom = _random.Pick(heirlooms);
if (Exists(heirloom.Item1)) // WD EDIT
{
EnsureComp<HeirloomHaverComponent>(uid, out var haver);
EnsureComp<HeirloomComponent>(heirloom.Item1, out var comp);
haver.Heirloom = heirloom.Item1;
comp.HOwner = uid;
Dirty(uid, haver);
Dirty(heirloom.Item1, comp);
}
}
if (jobProto != null ||
_protoMan.TryIndex(job, out jobProto))
foreach (var special in jobProto.AfterLoadoutSpecial)
special.AfterEquip(uid);
}
}