Migrating from LGUI, LexUI or early builds
Moving assets saved against LGUI / LexUI, a project on the early single-module 1.x builds, and C++ written against the plugin to DreamGUI — before you open the project, install, what the redirects borrowed from 2.1.0 carry, what no longer exists, behaviour to check, C++ changes, and what to do when something does not come across.
This page is for three kinds of project:
- one with assets saved against LGUI or LexUI — the upstream this fork started from;
- one on an early build of this fork — the single-module 1.x builds (not 1.0.0), before the module split, the input rework and the renderer rework;
- one with C++ of its own against the plugin — subclasses, custom visuals, a viewport client of its own.
The seven sections below bring such a project onto the current structure. Afterwards read Upgrading from the development builds: the default and behaviour changes of the 2.0 → 2.1 → 1.0.0 steps apply to a project coming from further back as well. Everything here is about keeping what you have; starting from nothing is in Installation.
1. Before you open the project
- Engine 5.8. The plugin builds against 5.8 only; there is no 5.7 branch of it.
- Put the project under source control first, or copy it. Opening it with the new plugin is harmless — redirects rewrite names in memory, not on disk — but the first save of an asset writes the new names into it, and there is no way back from that save to the old plugin.
- Take the old plugin out. An LGUI or LexUI folder under
Plugins/has to go before DreamGUI goes in: its classes would be live under the names the redirects map from, and a redirect never applies to a name that still resolves. - Put the redirect block into your
Config/DefaultEngine.ini. 1.0.0 ships no redirects (see From 2.1 to 1.0.0): copy the[CoreRedirects]section of 2.1.0'sConfig/DefaultDreamGUI.ini(commit3049561a) there, once. A copy of an older block that is already there goes first — two redirects for one old name with different new names are an error, and the first one registered wins.
2. Install
Clone into the project's Plugins/ directory, regenerate project files, build:
git clone https://github.com/TypeDreamMoon/DreamGUI.git Plugins/DreamGUIThe plugin needs EnhancedInput, which it enables itself. Nothing else is required of the project: no engine source
build, no private engine headers, no settings to copy.
3. What the redirects carry
The block from 2.1.0, once it is in the project's Config/DefaultEngine.ini, is applied by the engine before the first
package loads. It holds 763 redirects:
| Kind | Entries | What they cover |
|---|---|---|
| Package | 4 | The /LGUI/ content mount to /DreamGUI/, and the /Script/LGUI, /Script/LGUIEditor and /Script/LTween modules to their DreamGUI names |
| Class | 395 | Every LGUI/LexUI class; the prefab vocabulary the class model replaced; the control renames (UIButtonComponent → UIButton and its thirteen siblings); every class the module split moved out of the core, from its old /Script/DreamGUI name to its module |
| Struct, enum | 96, 124 | The same, for data |
| Function | 74 | Functions a Blueprint calls or overrides that were renamed or moved — UDreamUIBehaviour's Update → Tick, UDreamUINavigationScope's events that lost their On |
| Object | 70 | The delegate signatures the module split moved with their classes |
Then resave, and take the block out. A redirect is applied every time an asset that needs it loads. Once the
project opens and the UI looks right, resave the assets that use DreamGUI (File ▸ Save All after opening them, or the
ResavePackages commandlet over your content), so they name the current types themselves, and delete the block from
Config/DefaultEngine.ini: nothing needs it after that, and 1.0.0 does not keep a copy of its own.
4. What no longer exists
These have no redirect, because there is nothing left for one to point at. An asset that still names one of them loses that part on load, and the engine logs a warning naming it.
- The root Blueprints
WorldSpaceRoot_DreamRenderer,WorldSpaceRoot_UERenderer,ScreenSpaceRootandDreamWorldSpaceRaycasterSource_Mouse. A level that places one drops that actor — its class no longer resolves, so the whole export is discarded and a warning is logged. Nothing is left behind to fix up: drag the widget Blueprint into the level again, as aUDreamWorldWidgetComponenton an actor of your own or through the level editor's drop. UDreamWidgetPresenterComponent. The abstract baseUDreamWidgetPresenterComponentBasestays;UDreamWorldWidgetComponentis what you place.- The
UDreamWorldSpaceRaycasterBase/ForWorldTrigger/Sourcefamily —UDreamWorldSpaceRaycasterabsorbed all of it. - The plugin settings
ScreenSpaceRootClass,WorldSpaceRootClass,WorldSpaceUERendererRootClass,WorldSpaceRaycasterSourceClass, andbLegacyTouchPointerIds(see section 5). - The Lex layout family —
ULexLayoutContainerFlexBox,ULexLayoutContainerGrid,ULexLayoutSelfFlexBox,ULexLayoutSelfGridand theELexUILayoutModeswitch. The UMG-shaped panels replace them; a tree laid out by one of these is laid out again by hand. - The prefab machinery and its types, which the widget class model replaced before any of the above —
SavePrefab,Apply,ClearLoadedPrefaband Save on Apply with it. - Two console variables that put earlier renderer behaviour back —
r.DreamUI.MaterialWrappersandr.DreamUI.RTDrawer— together with the behaviour they put back (see section 5).
5. Behaviour to check
What an asset does can differ from what it did, with nothing renamed. Worth a look in any project that has run an earlier version:
Input
- Pointer ids have ranges. The mouse is pointer 0, a finger is 100 plus its index, and ids a script makes up start
at 1000. A finger used to be its own index, so the first finger and the mouse were the same pointer and fought over
hover and selection. Code that reads touch pointers by finger index asks
DreamUIPointerIds::ForTouchinstead; the setting that restored the old ids is gone. - The Enhanced Input preset binds the actions it is given, as they are. It used to play with runtime copies of them,
whose
bTriggerWhenPausedit rewrote every frame. Now a paused game is decided per event: while the game is paused andUDreamUISettings::bScreenSpaceUIAffectByGamePauseis set, the preset drops what arrives. For a paused frame's click to arrive at all, its action must trigger while paused — the shippedIA_*actions do; setbTriggerWhenPausedon actions of your own that the preset binds. - Focus and text input belong to a player. A split screen's second player focuses and types on its own.
UUITextInput::GetActiveTextInputForPlayeranswers per player;GetActiveTextInputanswers across worlds. - Characters reach a text field through the game viewport client. Use
UDreamGameViewportClient, or callDreamUITextInputRouter::RouteViewportCharacterfrom your own viewport client'sInputChar, after the console and before the base class (see Installation). - The Slate input source is optional and off. Project Settings ▸ Plugins ▸ Dream GUI ▸ Input ▸ Use Slate Input
Source hears every pointer, key and stick before the viewport, so the UI keeps working in the engine's own UI-only
input mode; the preset actors stand down while it is on, and
SlateInputConsumePolicydecides what it keeps from the game.
Rendering
- A canvas makes no material instance of its own. It answers the parameters it gives a material — the main and font textures, its data textures — through a render-thread proxy of that material. A material instance you give a widget is answered for the same way and never written to, so parameters you set on it stay yours. Nothing a canvas draws with is an object in the level, and nothing of it is copied into a play session or a paste.
- A render-target canvas draws whether or not anything renders its world. It is drawn by a render command and a graph of its own after its sections change, not inside one of its world's views.
- Background blur, pixelate and pixel sort look as they did, with two fixes: a full-size blur on a multisampled canvas shows (it was lost to the canvas's resolve), and a full-size blur into an output target blurs the screen (it blurred an empty texture).
Seeing it
DreamUI.Capture writes a PNG of the viewport and of every render-target canvas, and DreamUI.Stats prints what the UI
cost stage by stage — enough to compare a migrated screen with how it looked before. If something is drawn wrong or not
drawn, run with r.DreamUI.VerifyPartialPrepare 1 and include the ensure it raises in the report. See
Debugging.
6. C++ of your own
Modules
The runtime is several modules now. Add to your Build.cs the ones whose types you use: DreamGUIRenderer (drawing,
effects' render proxies), DreamGUI (widgets, visuals, canvases), DreamGUIInput (event systems, raycasters,
navigation, the viewport client), DreamGUIControls (the Dream* controls and the UI* behaviours),
DreamGUIExtensions (lines, rings, effects, render-target helpers). What is where is in
Project layout.
Includes
Every header kept its path except these:
| Include that was | Is now |
|---|---|
Core/DreamUIRender/*, Core/DreamUIMesh/DreamUIGizmoMesh.h, Core/DreamUIMeshVertex.h, Core/DreamUIMeshIndex.h, Core/DreamUIBlendMode.h, Core/DreamVisualPostProcessRenderProxy.h | DreamUIRender/ and the same file name |
Extensions/DreamGameViewportClient.h | Event/DreamGameViewportClient.h |
Extensions/DreamUMGWidget.h, Extensions/DreamUMGWidgetInteraction.h | UMG/ and the same file name |
Core/DreamUIEachAdapter.h | Binding/DreamUIEachAdapter.h |
Core/Components/DreamBackgroundBlur.h, Core/Components/DreamBackgroundPixelate.h, Core/Components/DreamPixelSort.h | Extensions/Effects/ and the same file name |
Calls
What moved with the module split:
| Call that was | Is now |
|---|---|
UUITextInput::RouteCharacterInputToActiveInput | DreamUITextInputRouter::RouteViewportCharacter, called before the base class (see Installation) |
UDreamCanvas::CalculateRenderScaledSize | FDreamUIRenderer::CalculateRenderScaledSize |
DreamPixelSort::ResolveRegionSize | DreamUIPostProcessEffects::ResolvePixelSortRegionSize (DreamUIRender/DreamUIPostProcessEffects.h) |
UDreamUIManagerWorldSubsystem's event-system registry and player interaction: GetEventSystemByUserIndex, GetMapUserIndexToEventSystem, AddEventSystem, RemoveEventSystem, EnsureInteractionForPlayer, GetInteractionHost | The same names on UDreamUIInputSubsystem (Event/DreamUIInputSubsystem.h); UDreamUIInputSubsystem::Get(WorldContext) finds it |
UDreamUIManagerWorldSubsystem::AddSelectable, RemoveSelectable and GetAllSelectableArray, with UUISelectable | The same, with UDreamUIBehaviour |
UDreamGUISettings::DefaultStyleSheet as a UDreamUIStyleSheet | A TSoftObjectPtr<UDataAsset>; UDreamUIStyleSheet::GetProjectSheet() does the cast |
And what changed after the split — the material callback a visual overrode, and the input and renderer calls that went with the old code paths:
| Was | Is now |
|---|---|
UDreamVisual::OnMaterialInstanceDynamicCreated(UMaterialInstanceDynamic*) | UDreamVisual::AddMaterialParameters(FDreamUIMaterialParameters&): give the parameters your visual's material needs, and the canvas answers them for its proxy |
DreamUITextInputRouter::RouteCharacter(TCHAR) | RouteViewportCharacter from a viewport client, or RouteCharacter(WorldContext, UserIndex, Character) |
UDreamGUISettings::bLegacyTouchPointerIds | Gone; DreamUIPointerIds::ForTouch gives a finger's pointer id |
ADreamEnhancedInputEventSystemActor::GetOriginalAction | Gone: the actions the actor holds are the ones it was given |
FDreamUIRenderer::IsRenderTargetDrawerEnabled | Gone: a render-target canvas is always drawn by DrawRenderTarget_GameThread |
UDreamUIMeshComponent::OnSceneProxyCreated | OnRenderRootCreated, broadcast with the mesh's render root. The root holds the canvas's sections and outlives the scene proxies made for it |
FDreamVisualPostProcessRenderProxy::RenderMeshOnScreen_RenderThread taking RHI textures | Takes the graph's textures (FRDGTextureRef). An effect of your own reads the screen with ReadScreen_RenderThread and GrabRegion_RenderThread, works in textures from CreateWorkTexture, and writes back with WriteBack_RenderThread |
Settings in code
UDreamGUISettings is Project Settings ▸ Plugins ▸ Dream GUI; UDreamUISettings is Project Settings ▸ Plugins ▸
DreamUI. Both are read where they are used, so a value changed at runtime applies from the next frame.
7. When something does not come across
The automation suite that ships with the plugin loads assets saved by the plugin and holds them to what was saved
(DreamGUI.Compatibility.*, DreamGUI.Assets.*); the redirect block itself was checked by 2.1.0's suite — that every
entry reached the engine, that no old name was still a live type, that none hopped into another redirect, and that every
new name existed. An asset of yours that fails to load with the block in place is worth a report with the warning the engine logged for it:
a name DreamGUI renamed and did not redirect is a bug.
Fonts and packaging
What a DreamGUI text needs to look in a packaged game the way it does in the editor — which fonts ship by themselves, how to add colour emoji, which ICU data to package, and how to check a package.
Upgrading from the development builds
What to know when a project on the 2.1 or 2.0 development build moves to 1.0.0 — what can look different, which defaults moved, which switches put the old behaviour back, and what your own C++ has to change.