-
Автор темы
- #1
И снова TODO в Lyra… 93-я строка LyraInventoryManagerComponent.cpp. Очередное вырубленное в камне послание от Epic Games: TODO: Using the actor instead of component as the outer due to UE-127172.
Всё ясно. Тодошка из отряда костылеобразных. Как говорится, «нет ничего более постоянного, чем временное решение».
Но не сегодня.
Сегодня мы выкорчуем этот костыль и сделаем как надо.
Пора перестать плясать вокруг багов и управлять экземплярами предметов грамотно и централизованно.
В чём проблема?
Баг UE-127172 заставил разработчиков использовать актор вместо компонента в качестве Outer для экземпляров предметов.
А это:
Мы добавим централизованное управление жизненным циклом предметов через ULyraInventorySubsystem.
То, что должно было быть изначально.
Больше никаких «временных решений». Только чистый, логичный, мощный код.
Теперь подсистема — станет боссом. Она начнет управлять.
В своих потугах будем использовать UE5.5.0.
Добавляем методы в ULyraInventorySubsystem
Новые методы:
Что происходит?
Теперь всё под контролем.
Раньше мы колхозили. Создавали экземпляры кустарно, надеясь, что всё не рухнет. Теперь всё по уму — используем нашу подсистему.
Инвентарь больше не стихийное бедствие. Теперь он управляемый процесс.
Изменения:
Что мы сделали?
Мы разобрались с хаосом. Теперь экземпляры предметов — не беспризорники, а управляемые ресурсы.
Как говорится, «Хороший код — это когда даже временные решения выглядят намеренно»,
…но мы-то знаем, что лучше просто сделать всё правильно сразу.
Всё ясно. Тодошка из отряда костылеобразных. Как говорится, «нет ничего более постоянного, чем временное решение».
Но не сегодня.
Сегодня мы выкорчуем этот костыль и сделаем как надо.
Пора перестать плясать вокруг багов и управлять экземплярами предметов грамотно и централизованно.
В чём проблема?
Баг UE-127172 заставил разработчиков использовать актор вместо компонента в качестве Outer для экземпляров предметов.
А это:
- Ломает иерархию владения — предметы должны принадлежать компоненту, а не актору.
- Убивает модульность — чем больше привязок к акторам, тем сложнее гибко управлять инвентарём.
- Портит отладку — если что-то идёт не так, готовьтесь к головной боли.
- Выглядит как костыль — такой код лучше не показывать никому.
Мы добавим централизованное управление жизненным циклом предметов через ULyraInventorySubsystem.
То, что должно было быть изначально.
Больше никаких «временных решений». Только чистый, логичный, мощный код.
Теперь подсистема — станет боссом. Она начнет управлять.
- Создавать экземпляры предметов — централизованно, без хаоса.
- Инициализировать их правильно — без костылей, как и должно быть.
- Контролировать их жизненный цикл — удалит ненужное, очистит мусор.
В своих потугах будем использовать UE5.5.0.
Добавляем методы в ULyraInventorySubsystem
LyraInventorySubsystem.h:
public:
/** Create a new inventory item instance */
UFUNCTION(BlueprintCallable, Category="Lyra|Inventory")
ULyraInventoryItemInstance* CreateInventoryItemInstance(UObject* Outer, TSubclassOf<ULyraInventoryItemDefinition> ItemDef);
/** Initialize a newly created inventory item instance */
void InitializeItemInstance(ULyraInventoryItemInstance* Instance, TSubclassOf<ULyraInventoryItemDefinition> ItemDef);
private:
/** Cache of created inventory items for proper lifecycle management */
UPROPERTY()
TArray<TObjectPtr<ULyraInventoryItemInstance>> ManagedItems;
- CreateInventoryItemInstance — создаёт экземпляр предмета и настраивает его внешний объект (outer).
- InitializeItemInstance — выполняет дополнительную инициализацию экземпляра.
- ManagedItems — массив для отслеживания всех созданных экземпляров.
LyraInventorySubsystem.cpp:
// Надеюсь знаем куда вставлять?
#include "LyraInventoryItemInstance.h"
// Добавляем в функцию очистку управляемых предметов
void ULyraInventorySubsystem::Deinitialize()
{
// Cleanup managed items
ManagedItems.Empty(); // Вот эта строка
RegisteredInventoryComponents.Empty();
Super::Deinitialize();
}
// И добавляем реализации объявленных функций:
ULyraInventoryItemInstance* ULyraInventorySubsystem::CreateInventoryItemInstance(UObject* Outer, TSubclassOf<ULyraInventoryItemDefinition> ItemDef)
{
if (!ItemDef || !Outer)
{
return nullptr;
}
// Create the instance with the provided outer
ULyraInventoryItemInstance* NewInstance = NewObject<ULyraInventoryItemInstance>(Outer);
if (NewInstance)
{
InitializeItemInstance(NewInstance, ItemDef);
ManagedItems.Add(NewInstance);
}
return NewInstance;
}
void ULyraInventorySubsystem::InitializeItemInstance(ULyraInventoryItemInstance* Instance, TSubclassOf<ULyraInventoryItemDefinition> ItemDef)
{
if (!Instance || !ItemDef)
{
return;
}
Instance->SetItemDef(ItemDef);
// Initialize with fragments
if (const ULyraInventoryItemDefinition* Definition = ItemDef.GetDefaultObject())
{
for (const ULyraInventoryItemFragment* Fragment : Definition->Fragments)
{
if (Fragment)
{
Fragment->OnInstanceCreated(Instance);
}
}
}
}
Теперь всё под контролем.
- Экземпляр привязывается к компоненту, а не к актору. Больше никаких левых владельцев. Правильная иерархия.
- Все экземпляры хранятся в ManagedItems. Теперь мы управляем их жизненным циклом, а не надеемся на удачу.
- При деинициализации подсистемы ManagedItems очищается. Никаких утечек памяти. Всё чисто и логично.
Раньше мы колхозили. Создавали экземпляры кустарно, надеясь, что всё не рухнет. Теперь всё по уму — используем нашу подсистему.
Инвентарь больше не стихийное бедствие. Теперь он управляемый процесс.
LyraInventoryManagerComponent.cpp:
/* Заменяем вот этот код:
FLyraInventoryEntry& NewEntry = Entries.AddDefaulted_GetRef();
NewEntry.Instance = NewObject<ULyraInventoryItemInstance>(OwnerComponent->GetOwner()); //[USER=891005]@Todo[/USER]: Using the actor instead of component as the outer due to UE-127172
NewEntry.Instance->SetItemDef(ItemDef);
for (ULyraInventoryItemFragment* Fragment : GetDefault<ULyraInventoryItemDefinition>(ItemDef)->Fragments)
{
if (Fragment != nullptr)
{
Fragment->OnInstanceCreated(NewEntry.Instance);
}
}
NewEntry.StackCount = StackCount;
Result = NewEntry.Instance;
//const ULyraInventoryItemDefinition* ItemCDO = GetDefault<ULyraInventoryItemDefinition>(ItemDef);
MarkItemDirty(NewEntry);
return Result;
...на вот этот:*/
// Create the item instance through the subsystem
if (UGameInstance* GameInstance = OwnerComponent->GetWorld()->GetGameInstance())
{
if (ULyraInventorySubsystem* InventorySubsystem = GameInstance->GetSubsystem<ULyraInventorySubsystem>())
{
FLyraInventoryEntry& NewEntry = Entries.AddDefaulted_GetRef();
NewEntry.Instance = InventorySubsystem->CreateInventoryItemInstance(OwnerComponent, ItemDef);
if (NewEntry.Instance)
{
NewEntry.StackCount = StackCount;
NewEntry.LastObservedCount = StackCount;
Result = NewEntry.Instance;
//MarkItemDirty(NewEntry);
BroadcastChangeMessage(NewEntry, /[I]OldCount=[/I]/ 0, /[I]NewCount=[/I]/ StackCount);
}
}
}
return Result;
- AddEntry вызывает метод CreateInventoryItemInstance из подсистемы.
- Внешним объектом (outer) теперь корректно выступает компонент, а не актор.
- Инициализация экземпляра проводится через InitializeItemInstance.
LyraInventoryItemInstance.h:
// После строки "friend struct FLyraInventoryList;" добавим:
friend class ULyraInventorySubsystem;
Мы разобрались с хаосом. Теперь экземпляры предметов — не беспризорники, а управляемые ресурсы.
- Централизованное управление через подсистему.
- Компонент — главный, актор больше не вмешивается.
- UE-127172 — отправлен в могилу.
- Масштабируемость — кастомная логика создания предметов? Без проблем.
- Жизненный цикл под контролем — никаких утечек, никаких зомби-объектов.
- Оптимизация — массив экземпляров теперь под присмотром.
- Чистый код — логика создания и управления в одном месте.
- Правильная иерархия — предметы принадлежат кому надо.
- Гибкость — добавляем пуллинг, асинхронность, что угодно.
- Blueprint-дружественность — новые методы CreateInventoryItemInstance и InitializeItemInstance доступны из BP.
- TODO? Сожжены.
- Баги? Закопаны.
- Костыли? Переломаны через колено.
Как говорится, «Хороший код — это когда даже временные решения выглядят намеренно»,
…но мы-то знаем, что лучше просто сделать всё правильно сразу.
Пожалуйста, авторизуйтесь для просмотра ссылки.
Последнее редактирование: