Fix inventory layout integration and qualify ordinary UI and radio guidance

This commit is contained in:
2026-09-19 18:17:51 +02:00
parent 5c7719c19c
commit 67de3752fb
125 changed files with 18310 additions and 42 deletions
@@ -0,0 +1,8 @@
ERRIC_InventoryMode : "{0F307326459A1395}Prefabs/MP/Modes/GameMode_Base.et" {
components {
SCR_RespawnSystemComponent "{56B2B4793051E7C9}" {
m_SpawnLogic SCR_SpawnLogic {}
}
}
m_bUseSpawnPreload 0
}
@@ -0,0 +1,7 @@
MetaFileClass {
Name "{86FBBCE45AF62682}Prefabs/ERRIC_InventoryMode.et"
Configurations {
EntityTemplateResourceClass PC {}
EntityTemplateResourceClass HEADLESS : PC {}
}
}
+19
View File
@@ -0,0 +1,19 @@
# Isolated stock inventory runtime control
This diagnostic addon depends only on installed vanilla Reforger (`58D0FB3206B6F859`). It must run without successor Core, AI, Intel, Map or Chat loaded. It has its own project, world and prefab identities. It is not a player mission or a multiplayer/admission test.
Copy this directory alone as the hidden runner's `addons/core`; select `Worlds/ERRIC_Inventory.ent` and command-line Workbench plugin `ERRIC_InventoryControlPlugin`, with `-erricInventoryControl 1 -errPlay 1`. Keep the separate private profile, muted hidden Gamescope containment, prefix lock and source-bound archive. The fixture emits `ERR SMOKE PASS/FAIL/COMPLETE` with explicit vanilla-control scope. No automatic reload; required completion count is one. Native compilation/runtime execution is pending.
The fixture waits at most 30 seconds in actual local `RplMode.None` for `SCR_PlayerController`. It creates one stock `{2F912ED6E399FF47}Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_Unarmed.et`, assigns that body once through native `SetControlledEntity`, waits for settling, then calls the controller's actual `ActionOpenInventory`. It verifies the exact body, native menu/top menu, root, native `GridLayoutWidget` named `StoragesListSlot` and its direct `Frame0` child. The open screenshot is requested after 500 ms. Public native `SCR_InventoryStorageManagerComponent.CloseInventory` closes it; another 500 ms later the fixture verifies closure and requests a closed screenshot. World teardown disposes the fixture actor; the diagnostic does not delete a possessed actor or modify its inventory, health, or controls.
`Action_OpenInventory` is not a toggle: the installed implementation always invokes `OpenInventory`. The menu's `Action_CloseInventory` is protected. Therefore this control deliberately uses the public native close method instead of incorrectly invoking the open method twice. No keyboard input or user-input usability is claimed.
Retain all raw GUI errors. The suspected vanilla source path is:
* `scripts/Game/Player/SCR_PlayerController.c:965`: `ActionOpenInventory` delegates to the body's native inventory manager.
* `scripts/Game/Inventory/SCR_InventoryStorageManagerComponent.c:1756,1824`: normal inventory-open path uses `ChimeraMenuPreset.Inventory20Menu`.
* `scripts/Game/UI/Inventory/SCR_InventoryMenuUI.c:1694`: `ShowStoragesList` creates `{FC579324F5E4B3A4}UI/layouts/Menus/Inventory/InventoryCharacterGrid.layout` beneath `StoragesListSlot`, then attaches `SCR_InventoryStoragesListUI`.
* The installed `InventoryMain.layout` defines `StoragesListSlot` as a `GridLayoutWidget`; `InventoryCharacterGrid.layout` defines its root as `OverlayWidget Frame0`.
* `scripts/Game/UI/Inventory/SCR_InventoryStoragesListUI.c:301–302` unconditionally calls two `LayoutSlot` operations on that root, which now has a native grid slot.
Successor ordinary runs 16:55:12 and 16:58:32 recorded exactly two `OverlayWidget Frame0 has invalid slot GridWidgetSlot ... expected LayoutSlot` errors when opening inventory. This source chain is a concrete hypothesis; this control must reproduce it without successor addons before attributing runtime errors to vanilla. A completed fixture alongside retained GUI errors is a failed clean-runtime report, not an error-free qualification. Workbench control evidence does not establish ordinary-game module parity.
@@ -0,0 +1,126 @@
// Diagnostic addon only. No successor scripts/resources or player audit policy.
#ifdef WORKBENCH
class ERRIC_InventoryModeClass : SCR_BaseGameModeClass {}
class ERRIC_InventoryMode : SCR_BaseGameMode
{
protected SCR_PlayerController m_Controller;
protected IEntity m_Character;
protected SCR_InventoryStorageManagerComponent m_Inventory;
protected SCR_InventoryMenuUI m_Menu;
protected int m_Deadline;
protected int m_Wait;
protected int m_Step;
protected bool m_Finished;
protected override void EOnInit(IEntity owner)
{
super.EOnInit(owner);
string enabled;
if (SCR_Global.IsEditMode() || !System.GetCLIParam("erricInventoryControl", enabled) || enabled != "1") return;
if (!Replication.IsServer() || RplSession.Mode() != RplMode.None)
{
Fail("requires isolated native singleplayer Workbench mode");
return;
}
m_Deadline = System.GetTickCount() + 30000;
GetGame().GetCallqueue().CallLater(Probe, 100, true);
}
protected void Fail(string reason)
{
if (m_Finished) return;
m_Finished = true;
if (GetGame()) GetGame().GetCallqueue().Remove(Probe);
Print("ERR SMOKE FAIL: vanilla inventory control: " + reason, LogLevel.ERROR);
}
protected bool Check(bool condition, string reason)
{
if (!condition) { Fail(reason); return false; }
Print("ERR SMOKE PASS: vanilla inventory control: " + reason);
return true;
}
protected bool SameBody()
{
if (!GetGame() || !m_Controller || !m_Character) return false;
return GetGame().GetPlayerController() == m_Controller && m_Controller.GetControlledEntity() == m_Character;
}
protected void Probe()
{
if (m_Finished || !GetGame() || !GetGame().GetWorld()) return;
int now = System.GetTickCount();
if (now > m_Deadline) { Fail("bounded native controller/menu deadline"); return; }
if (now < m_Wait) return;
if (m_Step == 0)
{
m_Controller = SCR_PlayerController.Cast(GetGame().GetPlayerController());
if (!m_Controller) return;
if (!Check(!m_Controller.GetControlledEntity(), "real local controller initially unassigned")) return;
Resource resource = Resource.Load("{2F912ED6E399FF47}Prefabs/Characters/Factions/BLUFOR/US_Army/Character_US_Unarmed.et");
if (!Check(resource && resource.IsValid(), "installed unmodified US_Unarmed resource")) return;
EntitySpawnParams params = new EntitySpawnParams();
params.TransformMode = ETransformMode.WORLD;
vector origin = "6090 0 7160";
origin[1] = GetGame().GetWorld().GetSurfaceY(origin[0], origin[2]) + 0.1;
params.Transform[3] = origin;
m_Character = GetGame().SpawnEntityPrefab(resource, GetGame().GetWorld(), params);
if (!Check(m_Character != null, "one stock body spawned")) return;
if (!Check(m_Controller.SetControlledEntity(m_Character), "native fixture-only body assignment succeeded")) return;
m_Inventory = SCR_InventoryStorageManagerComponent.Cast(m_Character.FindComponent(SCR_InventoryStorageManagerComponent));
if (!Check(m_Inventory != null, "stock inventory component present")) return;
m_Step = 1;
m_Wait = now + 1000;
return;
}
if (!SameBody()) { Fail("original local controller/body changed"); return; }
if (m_Step == 1)
{
if (!Check(SCR_InventoryMenuUI.GetInventoryMenu() == null, "inventory initially closed")) return;
m_Controller.ActionOpenInventory();
m_Step = 2;
m_Wait = now + 500;
return;
}
if (m_Step == 2)
{
m_Menu = SCR_InventoryMenuUI.GetInventoryMenu();
if (!Check(m_Menu != null, "actual native Inventory20Menu opened")) return;
ChimeraCharacter character = ChimeraCharacter.Cast(m_Character);
if (!Check(character && m_Menu.GetCharacterController() == character.GetCharacterController(), "menu bound to exact stock body")) return;
Widget root = m_Menu.GetRootWidget();
if (!Check(root != null && GetGame().GetMenuManager().GetTopMenu() == m_Menu, "native inventory root and top menu")) return;
Widget parent = root.FindAnyWidget("StoragesListSlot");
if (!Check(parent && GridLayoutWidget.Cast(parent), "stock storage-list parent is native GridLayoutWidget")) return;
Widget frame = parent.GetChildren();
if (!Check(frame && frame.GetName() == "Frame0" && frame.GetParent() == parent, "stock Frame0 is direct child of native storage grid")) return;
PrintFormat("ERRIC INVENTORY GEOMETRY: parent=%1 type=%2 child=%3 type=%4", parent.GetName(), parent.Type(), frame.GetName(), frame.Type());
System.MakeScreenshot("$logs:erric-inventory-open");
m_Step = 3;
m_Wait = now + 500;
return;
}
if (m_Step == 3)
{
if (!Check(SCR_InventoryMenuUI.GetInventoryMenu() == m_Menu, "same native menu retained for delayed capture")) return;
// Action_OpenInventory opens only; public native CloseInventory is its counterpart.
m_Inventory.CloseInventory();
m_Step = 4;
m_Wait = now + 500;
return;
}
if (!Check(SCR_InventoryMenuUI.GetInventoryMenu() == null, "native inventory closed with original body retained")) return;
System.MakeScreenshot("$logs:erric-inventory-closed");
m_Finished = true;
GetGame().GetCallqueue().Remove(Probe);
Print("ERR SMOKE COMPLETE: vanilla inventory control; direct native API experiment only, no successor or input qualification");
}
void ~ERRIC_InventoryMode()
{
if (GetGame()) GetGame().GetCallqueue().Remove(Probe);
// World teardown owns the fixture entity; do not delete a possessed actor.
}
}
#endif
@@ -0,0 +1,11 @@
[WorkbenchPluginAttribute(name: "Isolated vanilla inventory control", wbModules: {"WorldEditor"})]
class ERRIC_InventoryControlPlugin : WorldEditorPlugin
{
override void RunCommandline()
{
string enabled, play;
WorldEditor editor = Workbench.GetModule(WorldEditor);
if (editor && System.GetCLIParam("erricInventoryControl", enabled) && enabled == "1" && System.GetCLIParam("errPlay", play) && play == "1")
editor.SwitchToGameMode();
}
}
@@ -0,0 +1,3 @@
SubScene {
Parent "{853E92315D1D9EFE}worlds/Eden/Eden.ent"
}
@@ -0,0 +1,7 @@
MetaFileClass {
Name "{2AACCD1FDA9EB6E9}Worlds/ERRIC_Inventory.ent"
Configurations {
WorldResourceClass PC {}
WorldResourceClass HEADLESS : PC {}
}
}
@@ -0,0 +1,3 @@
ERRIC_InventoryMode InventoryControl : "{86FBBCE45AF62682}Prefabs/ERRIC_InventoryMode.et" {}
SCR_FactionManager Factions : "{589540B35EBA8CDC}Prefabs/MP/Managers/Factions/FactionManager_USxUSSR.et" {}
SCR_LoadoutManager Loadouts : "{97EF4C1A41F63DDB}Prefabs/MP/Managers/Loadouts/LoadoutManager_USxUSSR.et" {}
@@ -0,0 +1,6 @@
GameProject {
ID "ERRIC_InventoryControl"
GUID "0FFD909E91FC329B"
TITLE "Vanilla inventory diagnostic control (isolated)"
Dependencies { "58D0FB3206B6F859" }
}