Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changelogs/NEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

## Added

- Demo showcase: 9 themed zones in a walkable linear corridor demonstrating all MCP tool categories (Actor, Material, Niagara VFX, Blueprint, Audio, Widget, Animation/AI, Data Systems)
- 17 materials, 4 Niagara VFX systems, 44 text labels with navigation signs, PlayerStart at corridor entrance
- UE 5.7 Blueprint API compatibility layer using SubobjectDataSubsystem + BlueprintEditorLibrary
- SCS helpers in blueprint_helpers.py: compile_blueprint, get_scs, add_component_subobject, find_component_handle, gather_component_handles, get_component_template, find_root_handle

## Fixed

- blueprint_add_component broken on UE 5.7 (simple_construction_script removed from Python API)
- blueprint_compile broken on UE 5.7 (KismetEditorUtilities and mark_package_dirty removed)
- blueprint_modify_component broken on UE 5.7
- Hot-reload not clearing utils.* modules, causing stale cached imports after code changes

## Changed

- Demo layout: replaced 3x3 calibration grid with linear walkable corridor (X=0 to X=20000)
- Reset baseline prefixes: simplified to Demo_ prefix (replaces old Calib_/Marker_ prefixes)
Comment thread
atomantic marked this conversation as resolved.
Outdated
- Demo.uproject engine association updated from 5.6 to 5.7
- All KismetEditorUtilities.compile_blueprint calls replaced with version-compatible compile_blueprint helper
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ Demo/*
# Keep only the project file and documentation
!Demo/*.uproject
!Demo/README_CALIBRATION.md
# Include Blueprint test system (part of UEMCP development)
# Include demo showcase content and test assets
!Demo/Content/
!Demo/Content/*.umap
!Demo/Content/TestBlueprints/
!Demo/Content/TestBlueprints/**
!Demo/Content/Demo/
!Demo/Content/Demo/**
# Demo/Content/Tests/ is excluded — created by test runs, cleaned by reset_demo_scene
# Always ignore Unreal's generated folders
Demo/Saved/
Demo/Intermediate/
Expand Down
Binary file modified Demo/Content/Calibration.umap
Binary file not shown.
Binary file added Demo/Content/CalibrationMap.umap
Binary file not shown.
Binary file added Demo/Content/Demo/Blueprints/BP_DemoWalker.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Actor.uasset
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Data.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Ground.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Hub.uasset
Binary file not shown.
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Niagara.uasset
Binary file not shown.
Binary file not shown.
Binary file added Demo/Content/Demo/Materials/M_Demo_Widget.uasset
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Demo/Content/Demo/VFX/NS_Demo_Burst.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/VFX/NS_Demo_Explosion.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/VFX/NS_Demo_Fountain.uasset
Binary file not shown.
Binary file added Demo/Content/Demo/VFX/NS_Demo_Trails.uasset
Binary file not shown.
2 changes: 1 addition & 1 deletion Demo/Demo.uproject
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"FileVersion": 3,
"EngineAssociation": "5.6",
"EngineAssociation": "5.7",
"Category": "",
"Description": "",
"Plugins": [
Expand Down
201 changes: 97 additions & 104 deletions Demo/README_CALIBRATION.md
Original file line number Diff line number Diff line change
@@ -1,135 +1,128 @@
# Simple Calibration Grid - Demo Project
# UEMCP Feature Showcase - Demo Project

## Overview

The Demo project now uses a **simple calibration grid** made of colored geometric shapes instead of complex text rendering. This approach is:
- Much easier to manipulate programmatically
- More performant
- Free from text rendering complications
- Visually clearer for calibration purposes
The Demo project is a **walkable feature showcase** organized as a linear corridor of themed zones, each demonstrating a category of MCP tools. Every zone includes a dedicated **E2E test area** where integration tests operate and reset. Press **Play** in the editor to fly through the corridor using WASD + mouse look.

## Grid Structure
## Layout (Linear Corridor, 2500-unit spacing along X axis)

### Main Grid
- **8x10 grid** of colored cubes (8 rows × 10 columns)
- **150 units** spacing between elements
- **Center markers** at corners for orientation
- **8 distinct colors**: Red, Green, Blue, Yellow, Cyan, Magenta, Orange, White

### Markers
- **4 corner cones** (NW, NE, SW, SE) in yellow
- Help with orientation and grid boundaries

### Ground Plane
- Dark gray plane for visual reference
- 20x20 scale units

## Color Manipulation
```
PlayerStart Hub Actor Material Niagara Blueprint Audio Widget Anim Data
X: -1500 0 2500 5000 7500 10000 12500 15000 17500 20000
```

### Using Python in UE Console
Navigation signs between each zone guide you to the next area.

You can manipulate the grid colors directly in the UE Python console:
## Zone Details

```python
import unreal
### Central Hub (X=0)
- Welcome title and subtitle text
- Globe with emissive material on metallic pedestal
- Forward/back corridor arrows

# Get all calibration grid actors
actors = unreal.get_editor_subsystem(unreal.EditorActorSubsystem).get_all_level_actors()
grid_actors = [a for a in actors if 'CalibCube' in a.get_actor_label()]
### Actor Operations (X=2500) - Red
- Shape gallery: Cube, Sphere, Cylinder, Cone
- Wall and pillar demonstrations
- Batch spawn array (3 spheres)
- Organized/rotated cubes
- **Tools**: spawn, modify, duplicate, delete, batch_spawn, organize, snap_to_socket

# Change colors using dynamic materials
for actor in grid_actors:
mesh_comp = actor.get_component_by_class(unreal.StaticMeshComponent)
if mesh_comp:
material = mesh_comp.get_material(0)
dynamic_mat = mesh_comp.create_dynamic_material_instance(0)
# Set to red (R=1, G=0, B=0)
dynamic_mat.set_vector_parameter_value("BaseColor", unreal.LinearColor(1, 0, 0, 1))
```
### Material System (X=5000) - Blue
- Material spheres: Metallic, Rough, Emissive, Gold, Copper, Neon
- Cube variants with metallic/gold finishes
- **Tools**: create_simple_material, create_instance, apply, graph editing

### Using MCP Tools
### Niagara VFX (X=7500) - Purple
- 4 live particle effects on pedestals: Fountain, Burst, Explosion, Trails
- **Tools**: create_system, spawn, set_parameter, compile, list_templates

```javascript
// Change individual element colors
mcp.python_proxy({
code: `
actor = unreal.get_editor_subsystem(unreal.EditorActorSubsystem).get_actor_reference("CalibCube_3_3_Orange")
mesh_comp = actor.get_component_by_class(unreal.StaticMeshComponent)
mid = mesh_comp.create_dynamic_material_instance(0)
mid.set_vector_parameter_value("BaseColor", unreal.LinearColor(1, 0, 1, 1))
`
})
```
### Blueprint System (X=10000) - Green
- 3 pedestals with demo shapes (Components, Variables, Functions)
- Visual graph wall with node blocks and connection
- **Tools**: create, compile, add_variable, add_component, add_function, graph

## Advantages Over Text-Based Calibration
### Audio/MetaSound (X=12500) - Orange
- 3 speaker cones
- Sound wave visualization rings
- MetaSound node graph wall (Oscillator, Filter, Output)
- **Tools**: import, create_metasound, add_node, connect_nodes, set_parameter

1. **Simple Materials**: Uses basic dynamic material instances with just color parameters
2. **No Font Dependencies**: No text rendering issues or font loading problems
3. **Easy Color Control**: Direct RGB values without complex material graphs
4. **Better Performance**: Geometric shapes render faster than text
5. **Predictable Behavior**: No text alignment or scaling issues
### Widget/UMG (X=15000) - Cyan
- 2 screen panels
- 3 button blocks
- Slider with knob
- Progress bar
- **Tools**: create, add_component, set_layout, set_property, bind_event

## Element Naming Convention
### Animation & AI (X=17500) - Yellow
- 3 humanoid figures (cylinder body + sphere head)
- State machine visualization wall with 3 state nodes
- **Tools**: anim_create_blueprint, state_machine, montage, statetree_create

Each grid element follows this naming pattern:
```
Calib[Shape]_[Row]_[Column]_[ColorName]
```
### Data Systems (X=20000) - Magenta
- DataTable visualization (table + 3 rows)
- Struct block with field layers
- Enum wheel with arrow
- PCG grid (5 procedural cubes)
- **Tools**: datatable, struct, enum, PCG, input, mesh/LOD, performance

Examples:
- `CalibCube_0_0_Red` - Top-left red cube
- `CalibSphere_3_3_Orange` - Center orange sphere
- `CalibCube_6_6_Magenta` - Bottom-right magenta cube
## Naming Convention

## Folder Structure
All showcase elements use these prefixes (preserved during reset):

All calibration elements are organized in the World Outliner:
```
CalibrationGrid/
├── CalibCube_* (grid elements)
├── CalibSphere_* (center marker)
├── CalibrationGround (ground plane)
└── Markers/
├── Marker_NW
├── Marker_NE
├── Marker_SW
└── Marker_SE
```
| Prefix | Purpose |
|--------|---------|
| `Demo_` | Showcase objects (actors, shapes, pedestals) |
| `DemoFloor_` | Zone platform floors |
| `DemoLabel_` | Text labels (zone titles, feature lists, test areas) |
| `DemoTestArea_` | E2E test area platforms |

## Modifying the Grid
## E2E Test Areas

The grid is built into the Demo project's Calibration.umap level. To modify it:
Each zone has a grey platform labeled "E2E TEST AREA" where integration tests:
1. Create test actors/assets
2. Perform operations
3. Verify results
4. Clean up (via `reset_demo_scene` or targeted deletion)

1. Open the level in Unreal Engine
2. Select grid actors in the World Outliner (under CalibrationGrid folder)
3. Adjust properties like position, scale, or materials
4. Save the level to preserve changes
Test actors do NOT use the `Demo_` prefix, so `reset_demo_scene` removes them while preserving the showcase.

## Customization
## Reset Mechanism

The Demo project's calibration grid uses:
```javascript
// Reset to clean showcase state
mcp.level_reset_demo_scene({ save: true, delete_test_assets: true })
```

- **Grid Size**: 8 rows × 10 columns
- **Cell Size**: 150 units spacing between elements
- **Element Scale**: 0.8 scale for each shape
**Preserved**: All `Demo_*`, `DemoFloor_*`, `DemoLabel_*`, `DemoTestArea_*` actors + lighting/atmosphere
**Removed**: Any actor without these prefixes (test artifacts)

You can modify these values in the creation scripts to suit your needs.
## Materials

## Troubleshooting
### Zone Materials (`/Game/Demo/Materials/`)
M_Demo_Ground, M_Demo_Hub, M_Demo_Actor, M_Demo_Material, M_Demo_Niagara, M_Demo_Blueprint, M_Demo_Audio, M_Demo_Widget, M_Demo_Animation, M_Demo_Data, M_Demo_TestArea

If colors don't appear:
1. Make sure the Python listener is running
2. Try using different parameter names: "BaseColor", "Color", "Base Color"
3. Check that dynamic material instances are being created properly
4. Verify the base material supports color parameters
### Showcase Materials (`/Game/Demo/Materials/Showcase/`)
M_Demo_Metallic, M_Demo_Rough, M_Demo_Emissive, M_Demo_Gold, M_Demo_Copper, M_Demo_Neon

## Next Steps
### VFX Assets (`/Game/Demo/VFX/`)
NS_Demo_Fountain, NS_Demo_Burst, NS_Demo_Explosion, NS_Demo_Trails

This simple calibration grid can be extended with:
- Different shapes per row/column
- Gradient patterns
- Animation through color cycling
- Interactive color picking
- Save/load color configurations
## World Outliner Structure

The key benefit is that all manipulation is now straightforward RGB color changes on simple geometric shapes!
```
Demo/
Hub/ - Central hub objects
Infrastructure/ - Floors, test areas
Labels/ - Zone titles
Features/ - Feature sub-labels
Zones/
Actor/ - Actor zone objects
Animation/ - Animation zone objects
Audio/ - Audio zone objects
Blueprint/ - Blueprint zone objects
Data/ - Data zone objects
Material/ - Material zone objects
Niagara/ - Niagara zone objects
Widget/ - Widget zone objects
```
12 changes: 12 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ Required for character-driven games.
- [x] `mesh_auto_generate_lods` — Built-in mesh reduction
- [x] `mesh_get_instance_breakdown` — Rendering cost per LOD

## Demo Showcase Redesign ✅

Replaced the old calibration grid with a full feature showcase:
- 9 themed zones in a walkable linear corridor demonstrating all MCP tool categories
- Central hub with navigation arrows along the corridor
- 17 showcase materials (11 zone + 6 showcase)
- 4 live Niagara particle effects
- TextRenderActor labels for all zones and features
- E2E test areas in each zone with reset-safe naming
- Updated baseline prefixes (Demo_ instead of Calib_)
- 151 baseline actors, all organized in World Outliner folders

## Backlog

- [ ] Streamable HTTP transport (MCP SDK supports this)
Expand Down
22 changes: 14 additions & 8 deletions plugin/Content/Python/ops/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import unreal

from utils.blueprint_helpers import compile_blueprint as _compile_bp
from utils.error_handling import (
AssetPathRule,
ProcessingError,
Expand Down Expand Up @@ -137,7 +138,7 @@ def create_blueprint(
details={"asset_path": asset_path},
)

unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)
unreal.EditorAssetLibrary.save_asset(asset_path)

log_debug(f"Created Animation Blueprint: {asset_path}")
Expand Down Expand Up @@ -186,7 +187,7 @@ def create_state_machine(
anim_graph.add_node(sm_node, False, False)
# Pin wiring to the final animation pose output is handled by UE compilation

unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)
unreal.EditorAssetLibrary.save_asset(blueprint_path)

log_debug(f"Created state machine '{machine_name}' in {blueprint_path}")
Expand Down Expand Up @@ -264,7 +265,7 @@ def add_state(
if bound_graph:
bound_graph.add_node(play_node, False, False)

unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)
unreal.EditorAssetLibrary.save_asset(blueprint_path)

log_debug(f"Added state '{state_name}' to machine '{machine_name}' in {blueprint_path}")
Expand Down Expand Up @@ -362,7 +363,7 @@ def add_transition(
if crossfade is not None:
transition_node.set_editor_property("crossfade_duration", duration)

unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)
unreal.EditorAssetLibrary.save_asset(blueprint_path)

log_debug(f"Added transition {source_state} -> {target_state} in '{machine_name}'")
Expand Down Expand Up @@ -429,19 +430,24 @@ def add_variable(
pin_type.set_editor_property("container_type", unreal.EPinContainerType.NONE)

name_field = unreal.Name(variable_name)
added = unreal.KismetEditorUtilities.add_blueprint_variable(anim_bp, name_field, pin_type)
if hasattr(unreal, "KismetEditorUtilities"):
added = unreal.KismetEditorUtilities.add_blueprint_variable(anim_bp, name_field, pin_type)
elif hasattr(unreal, "BlueprintEditorLibrary"):
added = unreal.BlueprintEditorLibrary.add_member_variable(anim_bp, variable_name, pin_type)
else:
added = False
if not added:
log_debug(f"add_blueprint_variable returned falsy for '{variable_name}', attempting save anyway")

# Compile first so the CDO has the new variable property available
unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)

Comment thread
atomantic marked this conversation as resolved.
if default_value is not None:
cdo = anim_bp.generated_class().get_default_object()
if cdo and hasattr(cdo, variable_name):
cdo.set_editor_property(variable_name, default_value)
# Re-compile after setting default to persist the CDO change
unreal.KismetEditorUtilities.compile_blueprint(anim_bp)
_compile_bp(anim_bp)

unreal.EditorAssetLibrary.save_asset(blueprint_path, only_if_is_dirty=False)

Expand Down Expand Up @@ -685,7 +691,7 @@ def link_layer(
inner_node.set_editor_property("interface", layer_class)
anim_graph.add_node(layer_node, False, False)

unreal.KismetEditorUtilities.compile_blueprint(base_bp)
_compile_bp(base_bp)
unreal.EditorAssetLibrary.save_asset(blueprint_path)

log_debug(f"Linked layer '{layer_comment}' to {blueprint_path}")
Expand Down
Loading
Loading