fix(ui): keep spell components in authored foreground
Install examination formula icons as the template root UIRegion image, matching retail ClearImage/SetImage behavior while retaining the authored missing-component overlay. Add the real DAT template fixture and conformance coverage. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
d4ce64f56b
commit
2c3da8e153
14 changed files with 231 additions and 34 deletions
|
|
@ -115,8 +115,8 @@ and the final two-client portal-out/materialization observer flow are
|
||||||
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
||||||
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
||||||
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
||||||
Release builds; the appraisal formula-media/geometry correction passes
|
Release builds; the appraisal formula-media/foreground correction passes
|
||||||
3,555 App tests / 3 skips and 7,986 complete-solution tests / 5 skips.
|
3,557 App tests / 3 skips and 7,988 complete-solution tests / 5 skips.
|
||||||
|
|
||||||
**Current work order:** the six-slice pre-M4 world-interaction completion
|
**Current work order:** the six-slice pre-M4 world-interaction completion
|
||||||
program in `docs/plans/2026-07-23-world-interaction-completion.md`: favorite
|
program in `docs/plans/2026-07-23-world-interaction-completion.md`: favorite
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,8 @@ and the final two-client portal-out/materialization observer flow are
|
||||||
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
||||||
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
||||||
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
||||||
Release builds; the appraisal formula-media/geometry correction passes
|
Release builds; the appraisal formula-media/foreground correction passes
|
||||||
3,555 App tests / 3 skips and 7,986 complete-solution tests / 5 skips.
|
3,557 App tests / 3 skips and 7,988 complete-solution tests / 5 skips.
|
||||||
|
|
||||||
**Current work order:** the six-slice pre-M4 world-interaction completion
|
**Current work order:** the six-slice pre-M4 world-interaction completion
|
||||||
program in `docs/plans/2026-07-23-world-interaction-completion.md`: favorite
|
program in `docs/plans/2026-07-23-world-interaction-completion.md`: favorite
|
||||||
|
|
|
||||||
|
|
@ -168,11 +168,14 @@ from a pending object appraisal to a spell releases exactly that appraisal
|
||||||
transaction before showing the SpellPanel.
|
transaction before showing the SpellPanel.
|
||||||
The formula-media correction now passes the component's DAT icon DID to
|
The formula-media correction now passes the component's DAT icon DID to
|
||||||
`GetSpellComponentIcon` instead of its WCID, so the authored cells render
|
`GetSpellComponentIcon` instead of its WCID, so the authored cells render
|
||||||
their actual scarab/taper images. ACE characters with component enforcement
|
their actual scarab/taper images. Each image is installed as the authored
|
||||||
disabled show the modern scarab/prismatic formula rather than an inactive
|
template root UIRegion's own image, matching retail's `ClearImage`/`SetImage`
|
||||||
legacy recipe (IA-21). A per-window authored-geometry revision resets the
|
path instead of sinking a synthetic child behind the window content. ACE
|
||||||
obsolete saved 545-pixel examination height once to LayoutDesc's 310 x 400
|
characters with component enforcement disabled show the modern
|
||||||
extent, preserving its position and all future retail-style user resizing.
|
scarab/prismatic formula rather than an inactive legacy recipe (IA-21). A
|
||||||
|
per-window authored-geometry revision resets the obsolete saved 545-pixel
|
||||||
|
examination height once to LayoutDesc's 310 x 400 extent, preserving its
|
||||||
|
position and all future retail-style user resizing.
|
||||||
|
|
||||||
**Files:** `src/AcDream.Core.Net/Messages/AppraiseInfoParser.cs`;
|
**Files:** `src/AcDream.Core.Net/Messages/AppraiseInfoParser.cs`;
|
||||||
`src/AcDream.App/UI/RetailUiRuntime.cs`;
|
`src/AcDream.App/UI/RetailUiRuntime.cs`;
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,10 @@ name/school/mana/duration/range/description and authored appropriate-formula
|
||||||
component cells, including live missing-component state. The follow-up resolves
|
component cells, including live missing-component state. The follow-up resolves
|
||||||
those cells through the component icon DID, shows the modern
|
those cells through the component icon DID, shows the modern
|
||||||
scarab/prismatic formula for ACE characters whose component enforcement is
|
scarab/prismatic formula for ACE characters whose component enforcement is
|
||||||
disabled (IA-21), and one-time migrates stale saved examination dimensions to
|
disabled (IA-21), installs each icon through the shared retained
|
||||||
the authored 310 x 400 extent while preserving retail-style later resizing.
|
`UIRegion::SetImage` seam so it keeps the authored foreground stack, and
|
||||||
|
one-time migrates stale saved examination dimensions to the authored
|
||||||
|
310 x 400 extent while preserving retail-style later resizing.
|
||||||
Its connected visual gate is pending. Slice 3's first connected gate exposed
|
Its connected visual gate is pending. Slice 3's first connected gate exposed
|
||||||
three deeper defects, now corrected: the response enum mislabeled ACE's
|
three deeper defects, now corrected: the response enum mislabeled ACE's
|
||||||
creature bit `0x0100` and dropped monster packets while retaining the busy
|
creature bit `0x0100` and dropped monster packets while retaining the busy
|
||||||
|
|
|
||||||
|
|
@ -114,9 +114,10 @@ SpellPanel locally, and no spell ID enters global object selection or the
|
||||||
status-bar magnifier command. Exact spell fields and the current appropriate
|
status-bar magnifier command. Exact spell fields and the current appropriate
|
||||||
formula's authored component cells are automated. The correction resolves
|
formula's authored component cells are automated. The correction resolves
|
||||||
component icons by DAT DID, projects scarabs/prismatic tapers when ACE
|
component icons by DAT DID, projects scarabs/prismatic tapers when ACE
|
||||||
disables component enforcement (IA-21), and resets obsolete saved dimensions
|
disables component enforcement (IA-21), installs each icon as its authored
|
||||||
|
template root's own foreground image, and resets obsolete saved dimensions
|
||||||
once to the authored 310 x 400 extent. The Release build with #228's 17
|
once to the authored 310 x 400 extent. The Release build with #228's 17
|
||||||
tracked test warnings, 3,555 App tests / 3 skips, and 7,986 complete-solution
|
tracked test warnings, 3,557 App tests / 3 skips, and 7,988 complete-solution
|
||||||
tests / 5 skips pass; the connected visual gate is pending.
|
tests / 5 skips pass; the connected visual gate is pending.
|
||||||
Slice 3's first connected gate found and corrected the real remaining defects:
|
Slice 3's first connected gate found and corrected the real remaining defects:
|
||||||
ACE creature flag `0x0100` was mislabeled as a weapon profile and left the
|
ACE creature flag `0x0100` was mislabeled as a weapon profile and left the
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ authored 310 x 400 layout correction are implemented; their connected visual
|
||||||
gate is pending. Favorite-spell press-time selection and right-click local
|
gate is pending. Favorite-spell press-time selection and right-click local
|
||||||
SpellPanel examination are implemented. The follow-up now maps
|
SpellPanel examination are implemented. The follow-up now maps
|
||||||
component-disabled ACE characters to the modern scarab/prismatic formula,
|
component-disabled ACE characters to the modern scarab/prismatic formula,
|
||||||
resolves formula icons by their DAT icon DIDs, and migrates stale examination
|
resolves formula icons by their DAT icon DIDs, installs those icons as each
|
||||||
|
authored template root's own foreground image, and migrates stale examination
|
||||||
dimensions once to the authored 310 x 400 extent. Their connected visual gate
|
dimensions once to the authored 310 x 400 extent. Their connected visual gate
|
||||||
is pending.
|
is pending.
|
||||||
**Milestone:** M4 prerequisite/preamble.
|
**Milestone:** M4 prerequisite/preamble.
|
||||||
|
|
|
||||||
|
|
@ -105,14 +105,21 @@ for each SCID in GetAppropriateSpellFormula(spell):
|
||||||
component = SpellComponentTable[SCID]
|
component = SpellComponentTable[SCID]
|
||||||
texture = GetSpellComponentIcon(component.iconDID)
|
texture = GetSpellComponentIcon(component.iconDID)
|
||||||
cell = AddItemFromTemplateList(0x1000032E)
|
cell = AddItemFromTemplateList(0x1000032E)
|
||||||
cell.icon = texture
|
cell.ClearImage()
|
||||||
|
cell.SetBlitMode(Blit_3Alpha)
|
||||||
|
cell.SetImage(texture)
|
||||||
cell.missingOverlay = !ComponentTracker.ComponentIsOwned(component.WCID)
|
cell.missingOverlay = !ComponentTracker.ComponentIsOwned(component.WCID)
|
||||||
|
|
||||||
initial floaty extent = LayoutDesc root extent = 310 x 400 pixels
|
initial floaty extent = LayoutDesc root extent = 310 x 400 pixels
|
||||||
restore user position/size from player UI state
|
restore user position/size from player UI state
|
||||||
```
|
```
|
||||||
|
|
||||||
The component icon lookup consumes the component's icon DID, not its WCID.
|
`SetImage` replaces the template root UIRegion's own image; retail does not add
|
||||||
|
a separate, negatively layered icon child. Template child `0x10000330` remains
|
||||||
|
the missing-component overlay. `UIRegion::DrawHere @ 0x0069FA30` draws the
|
||||||
|
root's image before its children for this template, preserving the authored
|
||||||
|
icon/overlay foreground stack. The component icon lookup consumes the
|
||||||
|
component's icon DID, not its WCID.
|
||||||
acdream's retained-layout persistence carries an authored-geometry revision:
|
acdream's retained-layout persistence carries an authored-geometry revision:
|
||||||
when a shipped LayoutDesc extent correction invalidates an older saved size,
|
when a shipped LayoutDesc extent correction invalidates an older saved size,
|
||||||
only width/height reset once; position, visibility, and later user resizing
|
only width/height reset once; position, visibility, and later user resizing
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ namespace AcDream.App.UI.Layout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiates the authored formula-icon template used by retail
|
/// Instantiates the authored formula-icon template used by retail
|
||||||
/// <c>SpellExamineUI::ExamineSpell @ 0x004B6210</c>. The controller replaces
|
/// <c>SpellExamineUI::ExamineSpell @ 0x004B6210</c>. The controller installs
|
||||||
/// the template root's placeholder image with the resolved component icon while
|
/// the component icon as the template root's own <c>UIRegion</c> image while
|
||||||
/// retaining child <c>0x10000330</c> as the missing-component overlay.
|
/// retaining child <c>0x10000330</c> as the missing-component overlay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SpellExamineComponentTemplateFactory
|
public sealed class SpellExamineComponentTemplateFactory
|
||||||
|
|
@ -62,20 +62,13 @@ public sealed class SpellExamineComponentTemplateFactory
|
||||||
did => _fonts.TryGetValue(did, out UiDatFont? font)
|
did => _fonts.TryGetValue(did, out UiDatFont? font)
|
||||||
? font
|
? font
|
||||||
: _defaultFont);
|
: _defaultFont);
|
||||||
UiElement root = content.Root;
|
if (content.Root is not UiDatElement root)
|
||||||
if (root is UiDatElement datRoot)
|
|
||||||
datRoot.MediaVisible = false;
|
|
||||||
|
|
||||||
var icon = new UiTextureElement
|
|
||||||
{
|
{
|
||||||
Width = root.Width,
|
throw new InvalidOperationException(
|
||||||
Height = root.Height,
|
$"Retail spell-component template 0x{TemplateId:X8} "
|
||||||
Anchors = AnchorEdges.Left | AnchorEdges.Top
|
+ "must resolve to a UIRegion-compatible element.");
|
||||||
| AnchorEdges.Right | AnchorEdges.Bottom,
|
}
|
||||||
Texture = iconTexture,
|
root.RuntimeImageTexture = iconTexture;
|
||||||
ZOrder = int.MinValue / 2,
|
|
||||||
};
|
|
||||||
root.AddChild(icon);
|
|
||||||
|
|
||||||
if (content.FindElement(MissingOverlayId) is { } missing)
|
if (content.FindElement(MissingOverlayId) is { } missing)
|
||||||
missing.Visible = !owned;
|
missing.Visible = !owned;
|
||||||
|
|
|
||||||
|
|
@ -165,8 +165,37 @@ public sealed class UiDatElement : UiElement, IUiDatStateful
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool MediaVisible { get; set; } = true;
|
public bool MediaVisible { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runtime image installed on this region in place of its authored state media.
|
||||||
|
/// A non-null value mirrors retail <c>UIRegion::ClearImage</c> followed by
|
||||||
|
/// <c>UIRegion::SetImage</c>; zero deliberately leaves the region image-less.
|
||||||
|
/// The image remains this element's own media, so authored descendants retain
|
||||||
|
/// their normal foreground relationship.
|
||||||
|
/// </summary>
|
||||||
|
public uint? RuntimeImageTexture { get; set; }
|
||||||
|
|
||||||
protected override void OnDraw(UiRenderContext ctx)
|
protected override void OnDraw(UiRenderContext ctx)
|
||||||
{
|
{
|
||||||
|
if (MediaVisible && RuntimeImageTexture is uint runtimeTexture)
|
||||||
|
{
|
||||||
|
if (runtimeTexture != 0u)
|
||||||
|
{
|
||||||
|
ctx.DrawSprite(
|
||||||
|
runtimeTexture,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
Width,
|
||||||
|
Height,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
1f,
|
||||||
|
1f,
|
||||||
|
Vector4.One);
|
||||||
|
}
|
||||||
|
DrawLabel(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var (file, _) = ActiveMedia();
|
var (file, _) = ActiveMedia();
|
||||||
if (MediaVisible && file != 0)
|
if (MediaVisible && file != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -180,6 +209,11 @@ public sealed class UiDatElement : UiElement, IUiDatStateful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawLabel(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLabel(UiRenderContext ctx)
|
||||||
|
{
|
||||||
// Centered text label over the sprite (retail draws button captions as text;
|
// Centered text label over the sprite (retail draws button captions as text;
|
||||||
// their dat sprites are blank frames).
|
// their dat sprites are blank frames).
|
||||||
if (Label is { Length: > 0 } label && LabelFont is { } lf)
|
if (Label is { Length: > 0 } label && LabelFont is { } lf)
|
||||||
|
|
|
||||||
|
|
@ -809,9 +809,8 @@ public sealed class AppraisalUiControllerTests
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
new uint[] { 0x06000010u + 2_000u, 0x06000011u + 2_000u },
|
new uint[] { 0x06000010u + 2_000u, 0x06000011u + 2_000u },
|
||||||
formula.Children
|
formula.Children
|
||||||
.SelectMany(cell => cell.Children)
|
.OfType<UiDatElement>()
|
||||||
.OfType<UiTextureElement>()
|
.Select(cell => cell.RuntimeImageTexture!.Value));
|
||||||
.Select(texture => texture.Texture));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AppraisalUiController? Bind(
|
private static AppraisalUiController? Bind(
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,9 @@ public static class FixtureLoader
|
||||||
public static ElementInfo LoadExaminationRowTemplateInfos()
|
public static ElementInfo LoadExaminationRowTemplateInfos()
|
||||||
=> LoadInfos("examine_row_2100006B_10000166.json");
|
=> LoadInfos("examine_row_2100006B_10000166.json");
|
||||||
|
|
||||||
|
public static ElementInfo LoadExaminationComponentTemplateInfos()
|
||||||
|
=> LoadInfos("examine_component_2100006B_1000032E.json");
|
||||||
|
|
||||||
public static ImportedLayout LoadPowerbar()
|
public static ImportedLayout LoadPowerbar()
|
||||||
=> LayoutImporter.Build(LoadPowerbarInfos(), _ => (0u, 0, 0), null);
|
=> LayoutImporter.Build(LoadPowerbarInfos(), _ => (0u, 0, 0), null);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,8 @@ public sealed class RetailLayoutFixtureGenerator
|
||||||
(0x2100006Bu, 0x100005F2u, "examine_2100006B_100005F2.json"),
|
(0x2100006Bu, 0x100005F2u, "examine_2100006B_100005F2.json"),
|
||||||
(AppraisalUiController.LayoutId, CreatureAppraisalRowTemplateFactory.TemplateId,
|
(AppraisalUiController.LayoutId, CreatureAppraisalRowTemplateFactory.TemplateId,
|
||||||
"examine_row_2100006B_10000166.json"),
|
"examine_row_2100006B_10000166.json"),
|
||||||
|
(AppraisalUiController.LayoutId, SpellExamineComponentTemplateFactory.TemplateId,
|
||||||
|
"examine_component_2100006B_1000032E.json"),
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
ElementInfo? panelPart = LayoutImporter.ImportInfos(dats, layoutId, rootId);
|
ElementInfo? panelPart = LayoutImporter.ImportInfos(dats, layoutId, rootId);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using AcDream.App.UI;
|
||||||
|
using AcDream.App.UI.Layout;
|
||||||
|
|
||||||
|
namespace AcDream.App.Tests.UI.Layout;
|
||||||
|
|
||||||
|
public sealed class SpellExamineComponentTemplateFactoryTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true, false)]
|
||||||
|
[InlineData(false, true)]
|
||||||
|
public void Create_InstallsIconOnRetailRootAndKeepsMissingOverlayAboveIt(
|
||||||
|
bool owned,
|
||||||
|
bool missingVisible)
|
||||||
|
{
|
||||||
|
ElementInfo template =
|
||||||
|
FixtureLoader.LoadExaminationComponentTemplateInfos();
|
||||||
|
var factory = new SpellExamineComponentTemplateFactory(
|
||||||
|
template,
|
||||||
|
did => (did + 1_000u, 32, 32),
|
||||||
|
defaultFont: null);
|
||||||
|
|
||||||
|
UiDatElement root = Assert.IsType<UiDatElement>(
|
||||||
|
factory.Create(0xABCDu, owned));
|
||||||
|
UiDatElement missing = Assert.IsType<UiDatElement>(
|
||||||
|
Assert.Single(root.Children));
|
||||||
|
|
||||||
|
Assert.Equal(SpellExamineComponentTemplateFactory.TemplateId, root.ElementId);
|
||||||
|
Assert.Equal(0xABCDu, root.RuntimeImageTexture);
|
||||||
|
Assert.Empty(root.Children.OfType<UiTextureElement>());
|
||||||
|
Assert.Equal(
|
||||||
|
SpellExamineComponentTemplateFactory.MissingOverlayId,
|
||||||
|
missing.ElementId);
|
||||||
|
Assert.Equal(missingVisible, missing.Visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"Id": 268436270,
|
||||||
|
"Type": 3,
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Width": 32,
|
||||||
|
"Height": 32,
|
||||||
|
"OriginalParentWidth": 0,
|
||||||
|
"OriginalParentHeight": 0,
|
||||||
|
"HasOriginalParentSize": false,
|
||||||
|
"Left": 0,
|
||||||
|
"Top": 0,
|
||||||
|
"Right": 0,
|
||||||
|
"Bottom": 0,
|
||||||
|
"ReadOrder": 1,
|
||||||
|
"ZLevel": 0,
|
||||||
|
"States": {
|
||||||
|
"4294967295": {
|
||||||
|
"Id": 4294967295,
|
||||||
|
"Name": "",
|
||||||
|
"PassToChildren": false,
|
||||||
|
"IncorporationFlags": 30,
|
||||||
|
"Image": null,
|
||||||
|
"Cursor": null,
|
||||||
|
"Properties": {
|
||||||
|
"Values": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DefaultStateId": 0,
|
||||||
|
"FontDid": 0,
|
||||||
|
"HJustify": 1,
|
||||||
|
"VJustify": 1,
|
||||||
|
"FontColor": null,
|
||||||
|
"StateMedia": {},
|
||||||
|
"StateCursors": {},
|
||||||
|
"DefaultStateName": "",
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"Id": 268436272,
|
||||||
|
"Type": 3,
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Width": 32,
|
||||||
|
"Height": 32,
|
||||||
|
"OriginalParentWidth": 32,
|
||||||
|
"OriginalParentHeight": 32,
|
||||||
|
"HasOriginalParentSize": true,
|
||||||
|
"Left": 0,
|
||||||
|
"Top": 0,
|
||||||
|
"Right": 0,
|
||||||
|
"Bottom": 0,
|
||||||
|
"ReadOrder": 1,
|
||||||
|
"ZLevel": 0,
|
||||||
|
"States": {
|
||||||
|
"4294967295": {
|
||||||
|
"Id": 4294967295,
|
||||||
|
"Name": "",
|
||||||
|
"PassToChildren": false,
|
||||||
|
"IncorporationFlags": 30,
|
||||||
|
"Image": {
|
||||||
|
"File": 100682946,
|
||||||
|
"DrawMode": 3
|
||||||
|
},
|
||||||
|
"Cursor": null,
|
||||||
|
"Properties": {
|
||||||
|
"Values": {
|
||||||
|
"59": {
|
||||||
|
"Kind": 1,
|
||||||
|
"MasterPropertyId": 59,
|
||||||
|
"UnsignedValue": 0,
|
||||||
|
"IntegerValue": 0,
|
||||||
|
"FloatValue": 0,
|
||||||
|
"BoolValue": false,
|
||||||
|
"StringInfoValue": {
|
||||||
|
"Token": 0,
|
||||||
|
"StringId": 0,
|
||||||
|
"TableId": 0,
|
||||||
|
"Override": 0,
|
||||||
|
"English": 0,
|
||||||
|
"Comment": 0
|
||||||
|
},
|
||||||
|
"ColorValue": {
|
||||||
|
"Blue": 0,
|
||||||
|
"Green": 0,
|
||||||
|
"Red": 0,
|
||||||
|
"Alpha": 0
|
||||||
|
},
|
||||||
|
"VectorValue": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Z": 0
|
||||||
|
},
|
||||||
|
"ArrayValue": [],
|
||||||
|
"StructValue": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DefaultStateId": 0,
|
||||||
|
"FontDid": 0,
|
||||||
|
"HJustify": 1,
|
||||||
|
"VJustify": 1,
|
||||||
|
"FontColor": null,
|
||||||
|
"StateMedia": {
|
||||||
|
"": {
|
||||||
|
"Item1": 100682946,
|
||||||
|
"Item2": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"StateCursors": {},
|
||||||
|
"DefaultStateName": "",
|
||||||
|
"Children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue