Files
wwdpublic/Content.Shared/_White/Book/BookSystem.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

227 lines
8.2 KiB
C#

using Content.Shared._White.Book.Components;
using Content.Shared.Interaction;
using Content.Shared.Tag;
using Content.Shared.UserInterface;
using Robust.Shared.Audio.Systems;
namespace Content.Shared._White.Book;
public sealed class BookSystem : EntitySystem
{
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BookComponent, BeforeActivatableUIOpenEvent>(BeforeUIOpen);
SubscribeLocalEvent<BookComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<BookComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<BookComponent, BookAddBookmarkMessage>(OnAddBookmark);
SubscribeLocalEvent<BookComponent, BookAddPageMessage>(OnAddPage);
SubscribeLocalEvent<BookComponent, BookAddTextMessage>(OnAddText);
SubscribeLocalEvent<BookComponent, BookDeletePageMessage>(OnDeletePage);
SubscribeLocalEvent<BookComponent, BookPageChangedMessage>(OnPageChanged);
SubscribeLocalEvent<BookComponent, BookRemoveBookmarkMessage>(OnRemoveBookmark);
}
private void BeforeUIOpen(EntityUid uid, BookComponent component, BeforeActivatableUIOpenEvent args)
{
UpdateUserInterface(uid, component);
}
private void OnInteractUsing(EntityUid uid, BookComponent component, InteractUsingEvent args)
{
if (!_tagSystem.HasTag(args.Used, "Write"))
return;
UpdateUserInterface(uid, component, true);
_uiSystem.OpenUi(uid, BookUiKey.Key, args.User);
args.Handled = true;
}
private void OnMapInit(EntityUid uid, BookComponent component, MapInitEvent args)
{
if (string.IsNullOrEmpty(component.Content))
return;
SplitContentIntoPages(component, Loc.GetString(component.Content));
UpdateUserInterface(uid, component);
}
private void OnAddBookmark(EntityUid uid, BookComponent component, BookAddBookmarkMessage args)
{
if (component.Bookmarks.Count >= component.MaxBookmarks || component.Bookmarks.ContainsKey(args.PageIndex))
return;
component.Bookmarks[args.PageIndex] = args.BookmarkName;
UpdateUserInterface(uid, component);
}
private void OnAddPage(EntityUid uid, BookComponent component, BookAddPageMessage args)
{
if (component.Pages.Count >= component.MaxPages)
return;
component.Pages.Add("");
component.CurrentPage = component.Pages.Count - 1;
_audioSystem.PlayPvs(component.PageFlipSound, uid);
UpdateUserInterface(uid, component);
}
private void OnAddText(EntityUid uid, BookComponent component, BookAddTextMessage args)
{
if (component.CurrentPage < 0 || component.CurrentPage >= component.Pages.Count)
{
component.CurrentPage = Math.Max(0, Math.Min(component.CurrentPage, component.Pages.Count - 1));
if (component.Pages.Count == 0)
{
component.Pages.Add("");
component.CurrentPage = 0;
}
}
var remainingText = args.Text;
var currentPageIndex = component.CurrentPage;
if (remainingText.Length <= component.MaxCharactersPerPage)
{
component.Pages[currentPageIndex] = remainingText;
}
else
{
while (!string.IsNullOrEmpty(remainingText) && component.Pages.Count < component.MaxPages)
{
if (remainingText.Length <= component.MaxCharactersPerPage)
{
component.Pages.Insert(currentPageIndex, remainingText);
break;
}
var pageText = remainingText[..component.MaxCharactersPerPage];
var lastSpaceIndex = pageText.LastIndexOf(' ');
if (lastSpaceIndex > component.MaxCharactersPerPage * 0.8)
{
pageText = pageText[..lastSpaceIndex];
remainingText = remainingText[(lastSpaceIndex + 1)..];
}
else
{
remainingText = remainingText[component.MaxCharactersPerPage..];
}
component.Pages.Insert(currentPageIndex, pageText);
currentPageIndex++;
}
}
component.CurrentPage = Math.Min(currentPageIndex, component.Pages.Count - 1);
_audioSystem.PlayPvs(component.SaveSound, uid);
UpdateUserInterface(uid, component);
}
private void OnDeletePage(EntityUid uid, BookComponent component, BookDeletePageMessage args)
{
if (component.Pages.Count <= 1 || args.PageIndex < 0 || args.PageIndex >= component.Pages.Count)
return;
component.Pages.RemoveAt(args.PageIndex);
component.Bookmarks.Remove(args.PageIndex);
if (component.Bookmarks.Count > 0)
{
var keys = new List<int>(component.Bookmarks.Keys);
foreach (var key in keys)
{
if (key > args.PageIndex)
{
var name = component.Bookmarks[key];
component.Bookmarks.Remove(key);
if (!component.Bookmarks.ContainsKey(key - 1))
component.Bookmarks[key - 1] = name;
}
}
}
component.CurrentPage = Math.Min(component.CurrentPage, component.Pages.Count - 1);
_audioSystem.PlayPvs(component.PageTearSound, uid);
UpdateUserInterface(uid, component);
}
private void OnPageChanged(EntityUid uid, BookComponent component, BookPageChangedMessage args)
{
component.CurrentPage = Math.Clamp(args.NewPage, 0, Math.Max(0, component.Pages.Count - 1));
_audioSystem.PlayPvs(component.PageFlipSound, uid);
}
private void OnRemoveBookmark(EntityUid uid, BookComponent component, BookRemoveBookmarkMessage args)
{
if (!component.Bookmarks.Remove(args.PageIndex))
return;
UpdateUserInterface(uid, component);
}
private void UpdateUserInterface(EntityUid uid, BookComponent component, bool isEditing = false)
{
_uiSystem.SetUiState(
uid,
BookUiKey.Key,
new BookBoundUserInterfaceState(
new List<string>(component.Pages),
component.CurrentPage,
component.MaxCharactersPerPage,
component.MaxPages,
new Dictionary<int, string>(component.Bookmarks),
component.MaxBookmarks,
isEditing));
}
public void SplitContentIntoPages(BookComponent component, string content)
{
component.Pages.Clear();
var manualPages = content.Split(new[] { "[/p]", }, StringSplitOptions.None);
foreach (var manualPage in manualPages)
{
if (component.Pages.Count >= component.MaxPages)
break;
var remainingText = manualPage.Trim();
if (string.IsNullOrEmpty(remainingText))
{
component.Pages.Add("");
continue;
}
while (!string.IsNullOrEmpty(remainingText) && component.Pages.Count < component.MaxPages)
{
if (remainingText.Length <= component.MaxCharactersPerPage)
{
component.Pages.Add(remainingText);
break;
}
var pageText = remainingText[..component.MaxCharactersPerPage];
var lastSpaceIndex = pageText.LastIndexOf(' ');
if (lastSpaceIndex > component.MaxCharactersPerPage * 0.8)
{
pageText = pageText.Substring(0, lastSpaceIndex);
remainingText = remainingText.Substring(lastSpaceIndex + 1);
}
else
{
remainingText = remainingText.Substring(component.MaxCharactersPerPage);
}
component.Pages.Add(pageText);
}
}
if (component.Pages.Count == 0)
component.Pages.Add("");
}
}