Lyra Inventory Fix 02: Подсистема для фрагментов инвентаря. Решаем TODO с умом.

Lyra Inventory Fix 02: Подсистема для фрагментов инвентаря. Решаем TODO с умом.

Ох уж эти TODO-комментарии от Epic Games... Они, как забытые под диваном носки: вроде лежат себе тихо, но каждый раз, проходя мимо, ты слышишь их шёпот: "Вернись! Не оставляй меня здесь!". И, заглянув под диван, на 49-й строке LyraInventoryItemDefinition.h мы как раз и нашли один такой: // Todo: Make into a subsystem instead?

Что ж, пора отправить его на заслуженную пенсию и навести порядок.

В своих потугах использую UE5.5.0.

Почему подсистема?

Подсистемы в Unreal Engine — это, грубо говоря, менеджеры, которые живут на глобальном уровне и позволяют управлять данными централизованно. В нашем случае — это идеальное решение для работы с инвентарем. Мы получим:

  • Глобальный доступ к инвентарям из любого места игры.
  • Чистый и структурированный код, а не дублирование логики по разным классам.

Создаём новую подсистему: ULyraInventorySubsystem

LyraInventorySubsystem.h

// Copyright Cainoli. You can use me to fulfill your fantasies. All Rights Reserved. #pragma once #include "LyraInventorySubsystem.generated.h" #include "Subsystems/GameInstanceSubsystem.h" class ULyraInventoryItemDefinition; class ULyraInventoryItemFragment; class ULyraInventoryItemInstance; /** * Subsystem responsible for managing inventory-related functionality across the game */ UCLASS() class LYRAGAME_API ULyraInventorySubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: // Begin USubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; // End USubsystem /** Find a fragment in an item definition by class */ UFUNCTION(BlueprintCallable, Category = "Lyra|Inventory", meta = (DeterminesOutputType = FragmentClass)) const ULyraInventoryItemFragment* FindItemDefinitionFragment(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, TSubclassOf<ULyraInventoryItemFragment> FragmentClass) const; /** Register an inventory component with the subsystem */ void RegisterInventoryComponent(class ULyraInventoryManagerComponent* Component); /** Unregister an inventory component from the subsystem */ void UnregisterInventoryComponent(class ULyraInventoryManagerComponent* Component); /** Get all registered inventory components */ UFUNCTION(BlueprintCallable, Category = "Lyra|Inventory") const TArray<class ULyraInventoryManagerComponent*>& GetAllInventoryComponents() const { return RegisteredInventoryComponents; } private: /** List of all active inventory components */ UPROPERTY() TArray<class ULyraInventoryManagerComponent*> RegisteredInventoryComponents; };

LyraInventoryFragmentSubsystem.cpp

// Copyright Cainoli. You can use me to fulfill your fantasies. All Rights Reserved. #include "LyraInventoryItemDefinition.h" #include "LyraInventoryManagerComponent.h" #include "LyraInventorySubsystem.h" void ULyraInventorySubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); } void ULyraInventorySubsystem::Deinitialize() { RegisteredInventoryComponents.Empty(); Super::Deinitialize(); } const ULyraInventoryItemFragment* ULyraInventorySubsystem::FindItemDefinitionFragment(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, TSubclassOf<ULyraInventoryItemFragment> FragmentClass) const { if (const ULyraInventoryItemDefinition* Definition = ItemDef.Get()) { return Definition->FindFragmentByClass(FragmentClass); } return nullptr; } void ULyraInventorySubsystem::RegisterInventoryComponent(ULyraInventoryManagerComponent* Component) { if (Component) { RegisteredInventoryComponents.AddUnique(Component); } } void ULyraInventorySubsystem::UnregisterInventoryComponent(ULyraInventoryManagerComponent* Component) { if (Component) { RegisteredInventoryComponents.Remove(Component); } }

Что тут происходит? Мы реализовали GameInstanceSubsystem, которая:

  • Централизует работу с инвентарями.
  • Включает метод поиска: FindItemDefinitionFragment — для поиска фрагментов в определении предмета.

Обновляем старый код

Теперь нужно интегрировать новую подсистему в существующие классы:

LyraInventoryItemDefinition.h

// Отправим на пенсию следующий класс: /** @deprecated Use ULyraInventorySubsystem instead */ UCLASS(meta = (DeprecatedNode, DeprecationMessage = "Use ULyraInventorySubsystem instead")) class ULyraInventoryFunctionLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() // На заслуженный отдых отправим и эту функцию: /** @deprecated Use ULyraInventorySubsystem::FindItemDefinitionFragment instead */ UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use ULyraInventorySubsystem::FindItemDefinitionFragment instead", DeterminesOutputType = FragmentClass)) static const ULyraInventoryItemFragment* FindItemDefinitionFragment(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, TSubclassOf<ULyraInventoryItemFragment> FragmentClass); };

Что мы сделали и зачем это нужно?

  • Создали подсистему ULyraInventorySubsystem: Работает как GameInstanceSubsystem.Предоставляет удобный и быстрый доступ к инвентарям.
  • Добавили два основных метода: FindItemDefinitionFragment — найти фрагмент в определении предмета.GetAllInventoryComponents() — получить все ULyraInventoryManagerComponent.
  • Обратная совместимость: Старые методы помечены как deprecated.Добавлены предупреждения, чтобы плавно перевести проект на новую систему.

Использование новой системы

В C++:

// Получение подсистемы auto* InventorySystem = GetWorld()->GetGameInstance()->GetSubsystem<ULyraInventorySubsystem>(); // Поиск фрагмента для определения предмета auto* Fragment = InventorySystem->FindItemDefinitionFragment(ItemDefClass, FragmentClass); // Получение всех инвентарей TArray<class ULyraInventoryManagerComponent*> InventoryComponents = InventorySystem->GetAllInventoryComponents();

В Blueprint:

  • Функции подсистемы доступны из Blueprint.
  • Поддержка выводного типа через метаданные.
Lyra Inventory Fix 02: Подсистема для фрагментов инвентаря. Решаем TODO с умом.

Соглашусь, пока что функционал катастрофически мал для оправдания затраченных сил, НО...

Что дальше? Возможности для расширения

Наша подсистема не просто решает TODO, она открывает путь для будущих улучшений. Система легко расширяема и может быть в дальнейшем я (или быть может вы) дополните ее новыми возможностями. Я планирую ее использовать для дальнейшего расширения универсальной модульной системы инвентаря на основе прототипа LyrЫ. Поэтому дальнейшие мои публикации будут не раз затрагивать эту подсистему.

Вывод

Теперь у нас есть централизованная система для управления инвентарями. TODO-комментарий на 49-й строке превратился в надёжный инструмент, который в перспективе упростит жизнь разработчикам и уже сейчас открывает простор для новых возможностей.

Как говорится, "Старый код не умирает, он просто становится частью подсистемы".

1
Начать дискуссию