Skip to content

Build and editor

All · 15 min · Building C++ section needs C++

Problems loading the right experience, Blueprint changes that do not behave the way the graph suggests, packaging, and building the C++ code. For where things live, read Architecture.

The first three sections are for everyone. Building C++, at the end, covers compile errors. Everyone compiles once, because XenoCore is delivered as source and builds the first time the project opens; after that, only whoever changes C++ sees those errors.

Loading the right content

Play loads the wrong experience, whatever the map's World Settings say

Why: an Experience Override in Lyra's developer settings beats the map's World Settings in Play-in-Editor. It is saved in your per-user settings under Saved/Config, which is not in source control, so it survives across sessions and differs between machines. A small toast, "Developer Settings Override", appears for two seconds when Play starts.

Fix: open Edit › Editor Preferences, find the category named after your project (Lyra for a project named Lyra), open Lyra Developer Settings and clear Experience Override. It is an Editor Preference, not a Project Setting, because it is saved per user. The Output Log confirms the result: Identified experience <name> (Source: <source>).

Avoid it next time: Tour of the project.

The experience in my own Game Feature plugin can't be found

Why: Lyra finds experiences through the Asset Manager, and a plugin's experience folder is not scanned by default. A DefaultGame.ini inside the plugin does not help. The log says EXPERIENCE: Wanted to use <id> but couldn't find it, falling back to the default.

Fix: open your plugin's Game Feature Data asset (the one named after the plugin, at its content root) and add your experience folder under Primary Asset Types to Scan, the way the XenoCore Game Feature Data does.

Avoid it next time: Subclass a mechanic.

Blueprints

A Blueprint uses a default value instead of the one I expected, with no error

Fails silently

The Blueprint compiles cleanly.

Why: an input pin with no wire and no typed value gives the function the type's default: empty text, zero, none. A getter node sitting right beside it, with its output going nowhere, is the tell.

Fix: follow each input pin on the node that behaves oddly and check it has a wire or a value. A column that is hidden on most screens can hide this for a long time.

Avoid it next time: Add a menu screen.

A base Blueprint I made by duplicating a character won't compile after reparenting

Why: a duplicate carries all of the original's components and functions. When the original is reparented onto its duplicate, both define functions like Death or Ragdoll, and the names collide. Its specifics (tags, effects, cooldowns) also end up on every future child.

Fix: create the base Blueprint empty, from the C++ class, and move only what every child needs into it. Keep identity (mesh, pawn data, abilities, stats) on the children.

Avoid it next time: Add a party member.

Packaging

My replacement screen works in the editor, but the packaged game shows the shipped one

Fails silently

Nothing is shown to the player. The game log (not present in a Shipping build) says XenoCore UI setting '...' did not load - using the shipped ....

Why: a screen, HUD widget or asset named in Project Settings › Game › XenoCore UI or XenoCore Content is a soft reference, and the cooker does not follow soft references in settings. XenoCore's own folders /XenoCore/UserInterface and /XenoCore/Characters/NPC are always cooked; your folder is not, so your replacement is left out of the build and XenoCore falls back to the shipped asset. A menu entry's Screen or Action has the same problem.

Fix: add your folder (for example /Game/MyGame/UI) to Project Settings › Packaging › Additional Asset Directories to Cook (DirectoriesToAlwaysCook in DefaultGame.ini), or make sure a cooked asset references it.

Avoid it next time: Restyle the menus.

Building C++

The build says it succeeded, but my C++ change isn't in the game

Why: one of four:

  • The build failed, but reported success. Unreal's Build.bat can exit with success after a failure. Scripts and some IDE integrations trust the exit code.
  • Live Coding was used for a reflected change. Live Coding cannot add or change a UPROPERTY, UFUNCTION, UCLASS or USTRUCT. It patches what it can and the reflected part silently keeps its old shape.
  • The editor is still running. Closing the editor window does not always end the process. UnrealEditor.exe and LiveCodingConsole.exe can stay resident, holding the Live Coding lock, and the build then cannot replace the module.
  • The data is a cached function-local static, such as static const TArray<...> X = ...; in a function. It is built once per editor session, so new code runs with the old data.

Fix:

  1. Read the end of the build output, not just the exit code. Look for Result: Succeeded.
  2. For any reflected change: close the editor, confirm in Task Manager that no UnrealEditor.exe or LiveCodingConsole.exe remains, build, then reopen.
  3. Restart the editor after changing anything held in a function-local static.

Avoid it next time: Subclass a mechanic.

The C++ build fails inside the VRM4U plugin

You see this on the first build of a new project if the install step Let Lyra's editor build compile VRM4U was skipped: Unreal compiles VRM4U's C++ from source along with XenoCore's.

The build stops with dozens of header-tool errors like:

VRM4U\Source\VRM4U\Public\VrmAnimInstance.h(74): Error: Native pointer usage in member
declaration detected [[[UVrmMetaObject *]]]. This is disallowed for the target/module,
consider TObjectPtr as an alternative.

Lyra's editor target refuses raw object pointers in reflected members, and VRM4U's public source still uses them.

Fix: open Source/LyraEditor.Target.cs in your project and change one line:

NativePointerMemberBehaviorOverride = PointerMemberBehavior.Disallow;

to

NativePointerMemberBehaviorOverride = PointerMemberBehavior.AllowAndLog;

Then build again. This only relaxes a code-style check for C++ that is compiled; it changes no behaviour and no data. If you do not use the VRoid characters, you can instead remove them and disable VRM4U; see Replace the sample content.

Avoid it next time: before updating VRM4U, read Compatibility.

Linker error "unresolved external symbol" for a Lyra class

Why: several Lyra classes are not exported from the LyraGame module (they have no LYRAGAME_API), so C++ outside Lyra cannot derive from them or call their functions. It compiles, then fails at link. Examples: ULyraAnimInstance, ULyraButtonBase, ULyraGameplayAbility_Interact.

XenoCore's own classes are all exported (XENOCORERUNTIME_API), so this error on a UXenoCore* or AXenoCore* class means a missing module in your Build.cs instead.

Fix: check for LYRAGAME_API on the class before designing around it. A Blueprint can still derive from an unexported class, so keep that part in Blueprint. Do not add the macro to Lyra's headers: that is an engine-side change you would have to carry through every update.

Avoid it next time: Subclass a mechanic.

A compile error points into a .gen.cpp file I never wrote

Why: Unreal Header Tool generated code that does not match your declaration. The usual causes:

  • A BlueprintImplementableEvent takes a pointer to a class declared UCLASS(..., Const), such as UXenoCoreQuestDefinition. The generated code makes the pointer const; declare it const yourself.
  • A UFUNCTION parameter on an actor is called Instigator, which shadows AActor::Instigator. Rename it, for example Interactor.
  • "redefinition; multiple initialization" of a gameplay tag appears only on a full build. Two .cpp files define the same UE_DEFINE_GAMEPLAY_TAG_STATIC; unity builds merge them into one file. Incremental builds compile the files separately, which hides it until a clean build.

Fix: as above. For tags that C++ names in more than one place, declare them once as native tags in a header, the way XenoCoreGameplayTags.h does.

Avoid it next time: Subclass a mechanic.

A gameplay tag lookup in C++ returns an empty tag

Fails silently

It compiles, and fails at run time as a message nobody receives or a flag stuck false.

Why: FGameplayTag::RequestGameplayTag(FName("...")) looks a tag up by string. If the tag is renamed or misspelled it still compiles and returns an empty tag.

Fix: use the native tag symbols in XenoCoreGameplayTags.h, for example XenoCoreGameplayTags::Status_XenoCore_Arming. Add new tags your C++ uses there too; they still appear in the editor's tag picker.

Avoid it next time: Gameplay tags reference.

Everything works in Play-in-Editor but a standalone or packaged game crashes on launch

Why: Play-in-Editor runs inside an editor whose game instance is already up, so it cannot show some startup problems. A common one: a world subsystem that registers a gameplay message listener in Initialize. That runs for every world, including a temporary one created before the game instance exists, and the message system asserts.

Fix: register listeners in OnWorldBeginPlay, not Initialize. Test with a standalone launch before believing a startup change works: run UnrealEditor.exe with the project, a map and -game -log. On Windows, launch it from PowerShell or a shortcut; some shells rewrite a map path that starts with /.

Avoid it next time: Package a build.

A packaged game halts on the title screen with "breaking Disregard for GC assumptions"

Why: in a cooked game, objects created at startup (project settings objects among them) live in a pool the garbage collector never walks. An asset cached in a variable on one of them is not kept alive by it. A Development build stops with "Encountered N object(s) breaking Disregard for GC assumptions"; a Shipping build frees the asset later and crashes on it. Play-in-Editor never shows this.

Fix: in your own settings class, keep any asset you cache alive explicitly; XenoCore's own settings caches go through XenoCoreSettingsCache::KeepAlive (in XenoCoreRuntime's private headers). Or do not cache: resolve the soft reference where it is used. Then test a packaged Development build.

Avoid it next time: Loading and ticking.

The editor builds, but the packaged game fails to compile

Why: some engine functions exist only in editor builds (they sit inside WITH_EDITOR). The editor target compiles them happily; the game target used for packaging does not have them.

Fix: wrap the call in #if WITH_EDITOR, or use a runtime alternative. Build the game target (for example Build.bat LyraGame Win64 Development -Project=...) after touching engine APIs, rather than finding out at package time.

Avoid it next time: Package a build.