Initial UE5 project with RalphaPlugin

- UE5.7 project configured with LFS for binary assets
- RalphaPlugin for MCP-based AI rendering control
- Ready for content creation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamestagg 2026-01-14 16:35:00 -06:00
commit 8a4b9a3f06
26 changed files with 2294 additions and 0 deletions

41
.gitattributes vendored Normal file
View File

@ -0,0 +1,41 @@
# UE5 LFS tracking
# Unreal binary assets
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
# Textures
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.hdr filter=lfs diff=lfs merge=lfs -text
# Audio
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
# Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
# 3D formats
*.fbx filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.abc filter=lfs diff=lfs merge=lfs -text
# Fonts
*.ttf filter=lfs diff=lfs merge=lfs -text
*.otf filter=lfs diff=lfs merge=lfs -text
# Compiled/binary
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# UE5 Project .gitignore
# Build artifacts (rebuilt locally)
Binaries/
Intermediate/
DerivedDataCache/
Build/
# Saved data (user-specific, logs, autosaves)
Saved/
# Plugin binaries (rebuilt per machine)
Plugins/**/Binaries/
Plugins/**/Intermediate/
# Visual Studio
.vs/
*.sln
*.suo
*.sdf
*.VC.db
*.VC.opendb
# JetBrains Rider
.idea/
# VS Code
.vscode/
# macOS
.DS_Store
*.DS_Store
# Windows
Thumbs.db
Desktop.ini
# Cooked content (generated)
**/Cooked/
# Starter content (if using)
**/StarterContent/

10
Config/DefaultEditor.ini Normal file
View File

@ -0,0 +1,10 @@
[/Script/UnrealEd.EditorPerformanceSettings]
bMonitorEditorPerformance=True
[/Script/UnrealEd.CrashReporterSettings]
bHideLogFilesOption=False
bHideRestartOption=False
[ContentBrowser]
ShowEngineContent=False
ShowPluginContent=True

29
Config/DefaultEngine.ini Normal file
View File

@ -0,0 +1,29 @@
[/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/Maps/Main
GameDefaultMap=/Game/Maps/Main
[/Script/Engine.RendererSettings]
r.DefaultFeature.AutoExposure=True
r.DefaultFeature.MotionBlur=True
r.DefaultFeature.Bloom=True
r.DefaultFeature.AmbientOcclusion=True
r.DefaultFeature.AmbientOcclusionStaticFraction=True
r.Lumen.DiffuseIndirect.Allow=True
r.Lumen.Reflections.Allow=True
r.RayTracing=True
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
[/Script/Engine.Engine]
+ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/Ralpha")
+ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/Ralpha")
[URL]
GameName=Ralpha
[/Script/Engine.GarbageCollectionSettings]
gc.MaxObjectsNotConsideredByGC=1
[ConsoleVariables]
r.Lumen.ScreenProbeGather.FullResolutionJitterWidth=1

8
Config/DefaultGame.ini Normal file
View File

@ -0,0 +1,8 @@
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=Ralpha2026
ProjectName=Ralpha
CompanyName=Ralpha
CopyrightNotice=Copyright Ralpha Team
Description=AI-driven style transfer for infinite world generation
bStartInVR=False
bStartInAR=False

13
Config/DefaultInput.ini Normal file
View File

@ -0,0 +1,13 @@
[/Script/Engine.InputSettings]
-AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Sensitivity=1.f,Exponent=1.f,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
-AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Sensitivity=1.f,Exponent=1.f,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
-AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Sensitivity=1.f,Exponent=1.f,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
-AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Sensitivity=1.f,Exponent=1.f,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
bCaptureMouseOnLaunch=True
DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown
bDefaultViewportMouseLock=False
DefaultViewportMouseLockMode=DoNotLock

View File

@ -0,0 +1,8 @@
[FilterPlugin]
; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and
; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively.
;
; Examples:
; /README.txt
; /Extras/...
; /Binaries/ThirdParty/*.dll

View File

@ -0,0 +1,29 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "Ralpha - AI Style Transfer",
"Description": "AI-driven style transfer system for Unreal Engine 5. Enables Claude to control rendering parameters via MCP.",
"Category": "Rendering",
"CreatedBy": "Ralpha Team",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": true,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "RalphaCore",
"Type": "Runtime",
"LoadingPhase": "Default"
},
{
"Name": "RalphaEditor",
"Type": "Editor",
"LoadingPhase": "PostEngineInit"
}
]
}

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<rect width="20" height="20" rx="3" fill="#1a1a2e"/>
<path d="M4 10 L8 6 L12 10 L16 4" stroke="#00d4ff" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="10" cy="14" r="2" fill="#ff6b6b"/>
<path d="M6 16 L14 16" stroke="#4ecdc4" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 412 B

View File

@ -0,0 +1,29 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaCore.h"
#define LOCTEXT_NAMESPACE "FRalphaCoreModule"
void FRalphaCoreModule::StartupModule()
{
UE_LOG(LogTemp, Log, TEXT("Ralpha Core Module Started"));
}
void FRalphaCoreModule::ShutdownModule()
{
UE_LOG(LogTemp, Log, TEXT("Ralpha Core Module Shutdown"));
}
FRalphaCoreModule& FRalphaCoreModule::Get()
{
return FModuleManager::LoadModuleChecked<FRalphaCoreModule>("RalphaCore");
}
bool FRalphaCoreModule::IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("RalphaCore");
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FRalphaCoreModule, RalphaCore)

View File

@ -0,0 +1,448 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaMCPServer.h"
#include "RalphaParameterBridge.h"
#include "RalphaScreenCapture.h"
#include "Dom/JsonObject.h"
#include "Dom/JsonValue.h"
#include "Serialization/JsonSerializer.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonWriter.h"
#include "Misc/Base64.h"
#include "Engine/World.h"
#include "Engine/Engine.h"
#include "Kismet/GameplayStatics.h"
DEFINE_LOG_CATEGORY(LogRalphaMCP);
URalphaMCPServer* URalphaMCPServer::Instance = nullptr;
URalphaMCPServer::URalphaMCPServer()
: ListenerSocket(nullptr)
, ServerPort(30010)
, bIsRunning(false)
, ParameterBridge(nullptr)
, ScreenCapture(nullptr)
{
}
URalphaMCPServer::~URalphaMCPServer()
{
Stop();
}
URalphaMCPServer* URalphaMCPServer::Get()
{
if (!Instance)
{
Instance = NewObject<URalphaMCPServer>();
Instance->AddToRoot(); // Prevent garbage collection
}
return Instance;
}
bool URalphaMCPServer::Start(int32 Port)
{
if (bIsRunning)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Server already running on port %d"), ServerPort);
return true;
}
ServerPort = Port;
// Create socket
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
if (!SocketSubsystem)
{
UE_LOG(LogRalphaMCP, Error, TEXT("Failed to get socket subsystem"));
return false;
}
ListenerSocket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("RalphaMCPServer"), false);
if (!ListenerSocket)
{
UE_LOG(LogRalphaMCP, Error, TEXT("Failed to create socket"));
return false;
}
// Configure socket
ListenerSocket->SetReuseAddr(true);
ListenerSocket->SetNonBlocking(true);
// Bind to port
TSharedRef<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
Addr->SetAnyAddress();
Addr->SetPort(ServerPort);
if (!ListenerSocket->Bind(*Addr))
{
UE_LOG(LogRalphaMCP, Error, TEXT("Failed to bind to port %d"), ServerPort);
SocketSubsystem->DestroySocket(ListenerSocket);
ListenerSocket = nullptr;
return false;
}
// Start listening
if (!ListenerSocket->Listen(8))
{
UE_LOG(LogRalphaMCP, Error, TEXT("Failed to listen on port %d"), ServerPort);
SocketSubsystem->DestroySocket(ListenerSocket);
ListenerSocket = nullptr;
return false;
}
// Create parameter bridge and screen capture
ParameterBridge = NewObject<URalphaParameterBridge>(this);
ScreenCapture = NewObject<URalphaScreenCapture>(this);
// Register tick
TickDelegateHandle = FTSTicker::GetCoreTicker().AddTicker(
FTickerDelegate::CreateUObject(this, &URalphaMCPServer::Tick), 0.0f);
bIsRunning = true;
UE_LOG(LogRalphaMCP, Log, TEXT("Ralpha MCP Server started on port %d"), ServerPort);
return true;
}
void URalphaMCPServer::Stop()
{
if (!bIsRunning)
{
return;
}
// Unregister tick
FTSTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
// Close all client connections
ClientConnections.Empty();
// Close listener socket
if (ListenerSocket)
{
ListenerSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenerSocket);
ListenerSocket = nullptr;
}
bIsRunning = false;
UE_LOG(LogRalphaMCP, Log, TEXT("Ralpha MCP Server stopped"));
}
bool URalphaMCPServer::IsRunning() const
{
return bIsRunning;
}
bool URalphaMCPServer::Tick(float DeltaTime)
{
if (!bIsRunning || !ListenerSocket)
{
return true;
}
// Check for new connections
bool bHasPendingConnection = false;
if (ListenerSocket->HasPendingConnection(bHasPendingConnection) && bHasPendingConnection)
{
TSharedRef<FInternetAddr> RemoteAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
FSocket* ClientSocket = ListenerSocket->Accept(*RemoteAddress, TEXT("RalphaClient"));
if (ClientSocket)
{
ClientSocket->SetNonBlocking(true);
TSharedPtr<FRalphaClientConnection> NewConnection = MakeShared<FRalphaClientConnection>(ClientSocket, this);
ClientConnections.Add(NewConnection);
UE_LOG(LogRalphaMCP, Log, TEXT("New client connected from %s"), *RemoteAddress->ToString(true));
}
}
// Process existing connections
for (int32 i = ClientConnections.Num() - 1; i >= 0; --i)
{
if (ClientConnections[i]->IsValid())
{
ClientConnections[i]->Tick();
}
else
{
ClientConnections.RemoveAt(i);
}
}
return true;
}
FString URalphaMCPServer::ProcessCommand(const FString& JsonCommand)
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonCommand);
if (!FJsonSerializer::Deserialize(Reader, JsonObject) || !JsonObject.IsValid())
{
return TEXT("{\"success\": false, \"error\": \"Invalid JSON\"}");
}
FString CommandType;
if (!JsonObject->TryGetStringField(TEXT("type"), CommandType))
{
return TEXT("{\"success\": false, \"error\": \"Missing command type\"}");
}
TSharedPtr<FJsonObject> ResponseObject = MakeShared<FJsonObject>();
// Route commands
if (CommandType == TEXT("capture_screenshot"))
{
int32 Width = JsonObject->HasField(TEXT("width")) ? JsonObject->GetIntegerField(TEXT("width")) : 1920;
int32 Height = JsonObject->HasField(TEXT("height")) ? JsonObject->GetIntegerField(TEXT("height")) : 1080;
FString Base64Image;
FString FilePath;
bool bSuccess = ScreenCapture->CaptureScreenshot(Width, Height, Base64Image, FilePath);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
if (bSuccess)
{
ResponseObject->SetStringField(TEXT("base64"), Base64Image);
ResponseObject->SetStringField(TEXT("path"), FilePath);
}
}
else if (CommandType == TEXT("get_all_parameters"))
{
TSharedPtr<FJsonObject> ParamsObject = ParameterBridge->GetAllParameters();
ResponseObject->SetBoolField(TEXT("success"), true);
ResponseObject->SetObjectField(TEXT("data"), ParamsObject);
}
else if (CommandType == TEXT("set_post_process"))
{
const TSharedPtr<FJsonObject>* Params;
if (JsonObject->TryGetObjectField(TEXT("parameters"), Params))
{
bool bSuccess = ParameterBridge->SetPostProcessParameters(*Params);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing parameters"));
}
}
else if (CommandType == TEXT("set_directional_light"))
{
const TSharedPtr<FJsonObject>* Params;
if (JsonObject->TryGetObjectField(TEXT("parameters"), Params))
{
bool bSuccess = ParameterBridge->SetDirectionalLightParameters(*Params);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing parameters"));
}
}
else if (CommandType == TEXT("set_sky_light"))
{
const TSharedPtr<FJsonObject>* Params;
if (JsonObject->TryGetObjectField(TEXT("parameters"), Params))
{
bool bSuccess = ParameterBridge->SetSkyLightParameters(*Params);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing parameters"));
}
}
else if (CommandType == TEXT("set_exponential_height_fog"))
{
const TSharedPtr<FJsonObject>* Params;
if (JsonObject->TryGetObjectField(TEXT("parameters"), Params))
{
bool bSuccess = ParameterBridge->SetFogParameters(*Params);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing parameters"));
}
}
else if (CommandType == TEXT("set_camera"))
{
const TSharedPtr<FJsonObject>* Params;
if (JsonObject->TryGetObjectField(TEXT("parameters"), Params))
{
bool bSuccess = ParameterBridge->SetCameraParameters(*Params);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing parameters"));
}
}
else if (CommandType == TEXT("search_assets"))
{
FString Query = JsonObject->GetStringField(TEXT("query"));
FString AssetType = JsonObject->HasField(TEXT("asset_type")) ? JsonObject->GetStringField(TEXT("asset_type")) : TEXT("All");
int32 MaxResults = JsonObject->HasField(TEXT("max_results")) ? JsonObject->GetIntegerField(TEXT("max_results")) : 20;
TArray<TSharedPtr<FJsonValue>> Results = ParameterBridge->SearchAssets(Query, AssetType, MaxResults);
ResponseObject->SetBoolField(TEXT("success"), true);
ResponseObject->SetArrayField(TEXT("results"), Results);
}
else if (CommandType == TEXT("spawn_actor"))
{
FString AssetPath = JsonObject->GetStringField(TEXT("asset_path"));
const TSharedPtr<FJsonObject>* LocationObj;
FVector Location = FVector::ZeroVector;
if (JsonObject->TryGetObjectField(TEXT("location"), LocationObj))
{
Location.X = (*LocationObj)->GetNumberField(TEXT("x"));
Location.Y = (*LocationObj)->GetNumberField(TEXT("y"));
Location.Z = (*LocationObj)->GetNumberField(TEXT("z"));
}
FRotator Rotation = FRotator::ZeroRotator;
const TSharedPtr<FJsonObject>* RotationObj;
if (JsonObject->TryGetObjectField(TEXT("rotation"), RotationObj))
{
Rotation.Pitch = (*RotationObj)->HasField(TEXT("pitch")) ? (*RotationObj)->GetNumberField(TEXT("pitch")) : 0.0f;
Rotation.Yaw = (*RotationObj)->HasField(TEXT("yaw")) ? (*RotationObj)->GetNumberField(TEXT("yaw")) : 0.0f;
Rotation.Roll = (*RotationObj)->HasField(TEXT("roll")) ? (*RotationObj)->GetNumberField(TEXT("roll")) : 0.0f;
}
float Scale = JsonObject->HasField(TEXT("scale")) ? JsonObject->GetNumberField(TEXT("scale")) : 1.0f;
FString ActorLabel = JsonObject->HasField(TEXT("actor_label")) ? JsonObject->GetStringField(TEXT("actor_label")) : TEXT("");
FString ActorId;
bool bSuccess = ParameterBridge->SpawnActor(AssetPath, Location, Rotation, Scale, ActorLabel, ActorId);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
if (bSuccess)
{
ResponseObject->SetStringField(TEXT("actor_id"), ActorId);
}
}
else if (CommandType == TEXT("delete_actor"))
{
FString ActorId = JsonObject->GetStringField(TEXT("actor_id"));
bool bSuccess = ParameterBridge->DeleteActor(ActorId);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else if (CommandType == TEXT("list_actors"))
{
FString ClassFilter = JsonObject->HasField(TEXT("class_filter")) ? JsonObject->GetStringField(TEXT("class_filter")) : TEXT("");
FString NameFilter = JsonObject->HasField(TEXT("name_filter")) ? JsonObject->GetStringField(TEXT("name_filter")) : TEXT("");
bool bIncludeTransforms = JsonObject->HasField(TEXT("include_transforms")) ? JsonObject->GetBoolField(TEXT("include_transforms")) : true;
TArray<TSharedPtr<FJsonValue>> Actors = ParameterBridge->ListActors(ClassFilter, NameFilter, bIncludeTransforms);
ResponseObject->SetBoolField(TEXT("success"), true);
ResponseObject->SetArrayField(TEXT("actors"), Actors);
}
else if (CommandType == TEXT("set_render_quality"))
{
const TSharedPtr<FJsonObject>* Settings;
if (JsonObject->TryGetObjectField(TEXT("settings"), Settings))
{
bool bSuccess = ParameterBridge->SetRenderQuality(*Settings);
ResponseObject->SetBoolField(TEXT("success"), bSuccess);
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing settings"));
}
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);
ResponseObject->SetStringField(TEXT("error"), FString::Printf(TEXT("Unknown command type: %s"), *CommandType));
}
// Serialize response
FString ResponseString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&ResponseString);
FJsonSerializer::Serialize(ResponseObject.ToSharedRef(), Writer);
return ResponseString;
}
// FRalphaClientConnection implementation
FRalphaClientConnection::FRalphaClientConnection(FSocket* InSocket, URalphaMCPServer* InServer)
: Socket(InSocket)
, Server(InServer)
{
}
FRalphaClientConnection::~FRalphaClientConnection()
{
if (Socket)
{
Socket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);
Socket = nullptr;
}
}
bool FRalphaClientConnection::IsValid() const
{
return Socket != nullptr && Socket->GetConnectionState() == SCS_Connected;
}
void FRalphaClientConnection::Tick()
{
if (!IsValid())
{
return;
}
// Receive data
uint32 PendingDataSize = 0;
while (Socket->HasPendingData(PendingDataSize) && PendingDataSize > 0)
{
TArray<uint8> ReceivedData;
ReceivedData.SetNumUninitialized(FMath::Min(PendingDataSize, 65536u));
int32 BytesRead = 0;
if (Socket->Recv(ReceivedData.GetData(), ReceivedData.Num(), BytesRead))
{
ReceiveBuffer += FString(UTF8_TO_TCHAR(reinterpret_cast<const char*>(ReceivedData.GetData())));
}
}
// Process complete messages (newline-delimited JSON)
int32 NewlineIndex;
while (ReceiveBuffer.FindChar(TEXT('\n'), NewlineIndex))
{
FString Message = ReceiveBuffer.Left(NewlineIndex);
ReceiveBuffer = ReceiveBuffer.Mid(NewlineIndex + 1);
if (!Message.IsEmpty())
{
FString Response = Server->ProcessCommand(Message);
SendResponse(Response);
}
}
}
void FRalphaClientConnection::SendResponse(const FString& Response)
{
if (!IsValid())
{
return;
}
FString ResponseWithNewline = Response + TEXT("\n");
FTCHARToUTF8 Converter(*ResponseWithNewline);
int32 BytesSent = 0;
Socket->Send(reinterpret_cast<const uint8*>(Converter.Get()), Converter.Length(), BytesSent);
}

View File

@ -0,0 +1,881 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaParameterBridge.h"
#include "RalphaMCPServer.h"
#include "Engine/Engine.h"
#include "Engine/World.h"
#include "Engine/PostProcessVolume.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "Engine/ExponentialHeightFog.h"
#include "CineCameraActor.h"
#include "CineCameraComponent.h"
#include "Components/PostProcessComponent.h"
#include "Components/DirectionalLightComponent.h"
#include "Components/SkyLightComponent.h"
#include "Components/ExponentialHeightFogComponent.h"
#include "Kismet/GameplayStatics.h"
#include "EngineUtils.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Engine/StaticMeshActor.h"
#include "Engine/StaticMesh.h"
#include "Dom/JsonObject.h"
#include "Dom/JsonValue.h"
#include "Serialization/JsonSerializer.h"
URalphaParameterBridge::URalphaParameterBridge()
{
}
UWorld* URalphaParameterBridge::GetCurrentWorld()
{
if (GEngine && GEngine->GetWorldContexts().Num() > 0)
{
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if (Context.WorldType == EWorldType::Editor || Context.WorldType == EWorldType::PIE)
{
return Context.World();
}
}
}
return nullptr;
}
APostProcessVolume* URalphaParameterBridge::FindPostProcessVolume()
{
UWorld* World = GetCurrentWorld();
if (!World) return nullptr;
for (TActorIterator<APostProcessVolume> It(World); It; ++It)
{
if (It->bUnbound) // Prefer unbound (global) volumes
{
return *It;
}
}
// Return any post-process volume if no unbound one found
for (TActorIterator<APostProcessVolume> It(World); It; ++It)
{
return *It;
}
return nullptr;
}
ADirectionalLight* URalphaParameterBridge::FindDirectionalLight()
{
UWorld* World = GetCurrentWorld();
if (!World) return nullptr;
for (TActorIterator<ADirectionalLight> It(World); It; ++It)
{
return *It;
}
return nullptr;
}
ASkyLight* URalphaParameterBridge::FindSkyLight()
{
UWorld* World = GetCurrentWorld();
if (!World) return nullptr;
for (TActorIterator<ASkyLight> It(World); It; ++It)
{
return *It;
}
return nullptr;
}
AExponentialHeightFog* URalphaParameterBridge::FindExponentialHeightFog()
{
UWorld* World = GetCurrentWorld();
if (!World) return nullptr;
for (TActorIterator<AExponentialHeightFog> It(World); It; ++It)
{
return *It;
}
return nullptr;
}
ACineCameraActor* URalphaParameterBridge::FindCineCamera()
{
UWorld* World = GetCurrentWorld();
if (!World) return nullptr;
for (TActorIterator<ACineCameraActor> It(World); It; ++It)
{
return *It;
}
return nullptr;
}
FLinearColor URalphaParameterBridge::ParseHexColor(const FString& HexColor)
{
FString CleanHex = HexColor;
CleanHex.RemoveFromStart(TEXT("#"));
FColor Color = FColor::FromHex(CleanHex);
return FLinearColor(Color);
}
FString URalphaParameterBridge::ColorToHex(const FLinearColor& Color)
{
FColor SRGBColor = Color.ToFColor(true);
return FString::Printf(TEXT("#%02X%02X%02X"), SRGBColor.R, SRGBColor.G, SRGBColor.B);
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetAllParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
Result->SetObjectField(TEXT("post_process"), GetPostProcessParameters());
Result->SetObjectField(TEXT("directional_light"), GetDirectionalLightParameters());
Result->SetObjectField(TEXT("sky_light"), GetSkyLightParameters());
Result->SetObjectField(TEXT("fog"), GetFogParameters());
Result->SetObjectField(TEXT("camera"), GetCameraParameters());
return Result;
}
// ============================================================================
// Post-Process Volume
// ============================================================================
bool URalphaParameterBridge::SetPostProcessParameters(const TSharedPtr<FJsonObject>& Params)
{
APostProcessVolume* PPV = FindPostProcessVolume();
if (!PPV)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No PostProcessVolume found in scene"));
return false;
}
FPostProcessSettings& Settings = PPV->Settings;
// Exposure
if (Params->HasField(TEXT("exposure_compensation")))
{
Settings.bOverride_AutoExposureBias = true;
Settings.AutoExposureBias = Params->GetNumberField(TEXT("exposure_compensation"));
}
// Color Grading
if (Params->HasField(TEXT("color_saturation")))
{
Settings.bOverride_ColorSaturation = true;
float Sat = Params->GetNumberField(TEXT("color_saturation"));
Settings.ColorSaturation = FVector4(Sat, Sat, Sat, 1.0f);
}
if (Params->HasField(TEXT("color_contrast")))
{
Settings.bOverride_ColorContrast = true;
float Contrast = Params->GetNumberField(TEXT("color_contrast"));
Settings.ColorContrast = FVector4(Contrast, Contrast, Contrast, 1.0f);
}
// White Balance
if (Params->HasField(TEXT("white_balance_temp")))
{
Settings.bOverride_WhiteTemp = true;
Settings.WhiteTemp = Params->GetNumberField(TEXT("white_balance_temp"));
}
if (Params->HasField(TEXT("white_balance_tint")))
{
Settings.bOverride_WhiteTint = true;
Settings.WhiteTint = Params->GetNumberField(TEXT("white_balance_tint"));
}
// Bloom
if (Params->HasField(TEXT("bloom_intensity")))
{
Settings.bOverride_BloomIntensity = true;
Settings.BloomIntensity = Params->GetNumberField(TEXT("bloom_intensity"));
}
if (Params->HasField(TEXT("bloom_threshold")))
{
Settings.bOverride_BloomThreshold = true;
Settings.BloomThreshold = Params->GetNumberField(TEXT("bloom_threshold"));
}
// Vignette
if (Params->HasField(TEXT("vignette_intensity")))
{
Settings.bOverride_VignetteIntensity = true;
Settings.VignetteIntensity = Params->GetNumberField(TEXT("vignette_intensity"));
}
// Film Grain
if (Params->HasField(TEXT("film_grain_intensity")))
{
Settings.bOverride_FilmGrainIntensity = true;
Settings.FilmGrainIntensity = Params->GetNumberField(TEXT("film_grain_intensity"));
}
// Chromatic Aberration
if (Params->HasField(TEXT("chromatic_aberration_intensity")))
{
Settings.bOverride_SceneFringeIntensity = true;
Settings.SceneFringeIntensity = Params->GetNumberField(TEXT("chromatic_aberration_intensity"));
}
PPV->MarkPackageDirty();
return true;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetPostProcessParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
APostProcessVolume* PPV = FindPostProcessVolume();
if (!PPV)
{
return Result;
}
const FPostProcessSettings& Settings = PPV->Settings;
Result->SetNumberField(TEXT("exposure_compensation"), Settings.AutoExposureBias);
Result->SetNumberField(TEXT("color_saturation"), Settings.ColorSaturation.X);
Result->SetNumberField(TEXT("color_contrast"), Settings.ColorContrast.X);
Result->SetNumberField(TEXT("white_balance_temp"), Settings.WhiteTemp);
Result->SetNumberField(TEXT("white_balance_tint"), Settings.WhiteTint);
Result->SetNumberField(TEXT("bloom_intensity"), Settings.BloomIntensity);
Result->SetNumberField(TEXT("bloom_threshold"), Settings.BloomThreshold);
Result->SetNumberField(TEXT("vignette_intensity"), Settings.VignetteIntensity);
Result->SetNumberField(TEXT("film_grain_intensity"), Settings.FilmGrainIntensity);
Result->SetNumberField(TEXT("chromatic_aberration_intensity"), Settings.SceneFringeIntensity);
return Result;
}
// ============================================================================
// Directional Light
// ============================================================================
bool URalphaParameterBridge::SetDirectionalLightParameters(const TSharedPtr<FJsonObject>& Params)
{
ADirectionalLight* Light = FindDirectionalLight();
if (!Light)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No DirectionalLight found in scene"));
return false;
}
UDirectionalLightComponent* LightComp = Cast<UDirectionalLightComponent>(Light->GetLightComponent());
if (!LightComp) return false;
if (Params->HasField(TEXT("intensity")))
{
LightComp->SetIntensity(Params->GetNumberField(TEXT("intensity")));
}
if (Params->HasField(TEXT("color")))
{
FLinearColor Color = ParseHexColor(Params->GetStringField(TEXT("color")));
LightComp->SetLightColor(Color);
}
if (Params->HasField(TEXT("temperature")))
{
LightComp->bUseTemperature = true;
LightComp->SetTemperature(Params->GetNumberField(TEXT("temperature")));
}
if (Params->HasField(TEXT("pitch")) || Params->HasField(TEXT("yaw")))
{
FRotator CurrentRot = Light->GetActorRotation();
if (Params->HasField(TEXT("pitch")))
{
CurrentRot.Pitch = Params->GetNumberField(TEXT("pitch"));
}
if (Params->HasField(TEXT("yaw")))
{
CurrentRot.Yaw = Params->GetNumberField(TEXT("yaw"));
}
Light->SetActorRotation(CurrentRot);
}
if (Params->HasField(TEXT("source_angle")))
{
LightComp->LightSourceAngle = Params->GetNumberField(TEXT("source_angle"));
}
if (Params->HasField(TEXT("source_soft_angle")))
{
LightComp->LightSourceSoftAngle = Params->GetNumberField(TEXT("source_soft_angle"));
}
LightComp->MarkRenderStateDirty();
return true;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetDirectionalLightParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
ADirectionalLight* Light = FindDirectionalLight();
if (!Light) return Result;
UDirectionalLightComponent* LightComp = Cast<UDirectionalLightComponent>(Light->GetLightComponent());
if (!LightComp) return Result;
Result->SetNumberField(TEXT("intensity"), LightComp->Intensity);
Result->SetStringField(TEXT("color"), ColorToHex(LightComp->GetLightColor()));
Result->SetNumberField(TEXT("temperature"), LightComp->Temperature);
Result->SetNumberField(TEXT("pitch"), Light->GetActorRotation().Pitch);
Result->SetNumberField(TEXT("yaw"), Light->GetActorRotation().Yaw);
Result->SetNumberField(TEXT("source_angle"), LightComp->LightSourceAngle);
Result->SetNumberField(TEXT("source_soft_angle"), LightComp->LightSourceSoftAngle);
return Result;
}
// ============================================================================
// Sky Light
// ============================================================================
bool URalphaParameterBridge::SetSkyLightParameters(const TSharedPtr<FJsonObject>& Params)
{
ASkyLight* Light = FindSkyLight();
if (!Light)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No SkyLight found in scene"));
return false;
}
USkyLightComponent* LightComp = Light->GetLightComponent();
if (!LightComp) return false;
if (Params->HasField(TEXT("intensity")))
{
LightComp->SetIntensity(Params->GetNumberField(TEXT("intensity")));
}
if (Params->HasField(TEXT("color")))
{
FLinearColor Color = ParseHexColor(Params->GetStringField(TEXT("color")));
LightComp->SetLightColor(Color);
}
LightComp->MarkRenderStateDirty();
return true;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetSkyLightParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
ASkyLight* Light = FindSkyLight();
if (!Light) return Result;
USkyLightComponent* LightComp = Light->GetLightComponent();
if (!LightComp) return Result;
Result->SetNumberField(TEXT("intensity"), LightComp->Intensity);
Result->SetStringField(TEXT("color"), ColorToHex(LightComp->GetLightColor()));
return Result;
}
// ============================================================================
// Exponential Height Fog
// ============================================================================
bool URalphaParameterBridge::SetFogParameters(const TSharedPtr<FJsonObject>& Params)
{
AExponentialHeightFog* Fog = FindExponentialHeightFog();
if (!Fog)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No ExponentialHeightFog found in scene"));
return false;
}
UExponentialHeightFogComponent* FogComp = Fog->GetComponent();
if (!FogComp) return false;
if (Params->HasField(TEXT("enabled")))
{
FogComp->SetVisibility(Params->GetBoolField(TEXT("enabled")));
}
if (Params->HasField(TEXT("fog_density")))
{
FogComp->SetFogDensity(Params->GetNumberField(TEXT("fog_density")));
}
if (Params->HasField(TEXT("fog_height_falloff")))
{
FogComp->SetFogHeightFalloff(Params->GetNumberField(TEXT("fog_height_falloff")));
}
if (Params->HasField(TEXT("fog_inscattering_color")))
{
FLinearColor Color = ParseHexColor(Params->GetStringField(TEXT("fog_inscattering_color")));
FogComp->SetFogInscatteringColor(Color);
}
if (Params->HasField(TEXT("fog_max_opacity")))
{
FogComp->SetFogMaxOpacity(Params->GetNumberField(TEXT("fog_max_opacity")));
}
if (Params->HasField(TEXT("start_distance")))
{
FogComp->SetStartDistance(Params->GetNumberField(TEXT("start_distance")));
}
if (Params->HasField(TEXT("volumetric_fog")))
{
FogComp->SetVolumetricFog(Params->GetBoolField(TEXT("volumetric_fog")));
}
if (Params->HasField(TEXT("volumetric_fog_scattering_distribution")))
{
FogComp->VolumetricFogScatteringDistribution = Params->GetNumberField(TEXT("volumetric_fog_scattering_distribution"));
}
FogComp->MarkRenderStateDirty();
return true;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetFogParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
AExponentialHeightFog* Fog = FindExponentialHeightFog();
if (!Fog) return Result;
UExponentialHeightFogComponent* FogComp = Fog->GetComponent();
if (!FogComp) return Result;
Result->SetBoolField(TEXT("enabled"), FogComp->IsVisible());
Result->SetNumberField(TEXT("fog_density"), FogComp->FogDensity);
Result->SetNumberField(TEXT("fog_height_falloff"), FogComp->FogHeightFalloff);
Result->SetNumberField(TEXT("fog_max_opacity"), FogComp->FogMaxOpacity);
Result->SetNumberField(TEXT("start_distance"), FogComp->StartDistance);
Result->SetBoolField(TEXT("volumetric_fog"), FogComp->bEnableVolumetricFog);
Result->SetNumberField(TEXT("volumetric_fog_scattering_distribution"), FogComp->VolumetricFogScatteringDistribution);
return Result;
}
// ============================================================================
// Camera
// ============================================================================
bool URalphaParameterBridge::SetCameraParameters(const TSharedPtr<FJsonObject>& Params)
{
ACineCameraActor* Camera = FindCineCamera();
if (!Camera)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No CineCameraActor found in scene"));
return false;
}
UCineCameraComponent* CameraComp = Camera->GetCineCameraComponent();
if (!CameraComp) return false;
if (Params->HasField(TEXT("focal_length")))
{
CameraComp->SetCurrentFocalLength(Params->GetNumberField(TEXT("focal_length")));
}
if (Params->HasField(TEXT("aperture")))
{
CameraComp->CurrentAperture = Params->GetNumberField(TEXT("aperture"));
}
if (Params->HasField(TEXT("focus_distance")))
{
CameraComp->FocusSettings.ManualFocusDistance = Params->GetNumberField(TEXT("focus_distance"));
}
if (Params->HasField(TEXT("dof_enabled")))
{
CameraComp->PostProcessSettings.bOverride_DepthOfFieldFstop = Params->GetBoolField(TEXT("dof_enabled"));
}
if (Params->HasField(TEXT("motion_blur_amount")))
{
CameraComp->PostProcessSettings.bOverride_MotionBlurAmount = true;
CameraComp->PostProcessSettings.MotionBlurAmount = Params->GetNumberField(TEXT("motion_blur_amount"));
}
CameraComp->MarkRenderStateDirty();
return true;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetCameraParameters()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
ACineCameraActor* Camera = FindCineCamera();
if (!Camera) return Result;
UCineCameraComponent* CameraComp = Camera->GetCineCameraComponent();
if (!CameraComp) return Result;
Result->SetNumberField(TEXT("focal_length"), CameraComp->CurrentFocalLength);
Result->SetNumberField(TEXT("aperture"), CameraComp->CurrentAperture);
Result->SetNumberField(TEXT("focus_distance"), CameraComp->FocusSettings.ManualFocusDistance);
Result->SetNumberField(TEXT("motion_blur_amount"), CameraComp->PostProcessSettings.MotionBlurAmount);
return Result;
}
// ============================================================================
// Render Quality
// ============================================================================
bool URalphaParameterBridge::SetRenderQuality(const TSharedPtr<FJsonObject>& Settings)
{
// This would typically use console commands or project settings
// For now, we'll log what we would set
if (Settings->HasField(TEXT("lumen_quality")))
{
float Quality = Settings->GetNumberField(TEXT("lumen_quality"));
UE_LOG(LogRalphaMCP, Log, TEXT("Would set Lumen quality to: %f"), Quality);
// r.Lumen.ScreenTracing.MaxIterations, etc.
}
if (Settings->HasField(TEXT("shadow_quality")))
{
FString Quality = Settings->GetStringField(TEXT("shadow_quality"));
UE_LOG(LogRalphaMCP, Log, TEXT("Would set shadow quality to: %s"), *Quality);
// sg.ShadowQuality
}
if (Settings->HasField(TEXT("resolution_scale")))
{
float Scale = Settings->GetNumberField(TEXT("resolution_scale"));
UE_LOG(LogRalphaMCP, Log, TEXT("Would set resolution scale to: %f"), Scale);
// r.ScreenPercentage
}
return true;
}
// ============================================================================
// Asset Search
// ============================================================================
TArray<TSharedPtr<FJsonValue>> URalphaParameterBridge::SearchAssets(const FString& Query, const FString& AssetType, int32 MaxResults)
{
TArray<TSharedPtr<FJsonValue>> Results;
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
FARFilter Filter;
Filter.bRecursivePaths = true;
Filter.PackagePaths.Add(TEXT("/Game"));
if (AssetType == TEXT("StaticMesh"))
{
Filter.ClassPaths.Add(UStaticMesh::StaticClass()->GetClassPathName());
}
// Add more type filters as needed
TArray<FAssetData> AssetList;
AssetRegistry.GetAssets(Filter, AssetList);
int32 Count = 0;
for (const FAssetData& Asset : AssetList)
{
if (Count >= MaxResults) break;
FString AssetName = Asset.AssetName.ToString();
if (AssetName.Contains(Query, ESearchCase::IgnoreCase))
{
TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
AssetObj->SetStringField(TEXT("name"), AssetName);
AssetObj->SetStringField(TEXT("asset_path"), Asset.GetObjectPathString());
AssetObj->SetStringField(TEXT("class"), Asset.AssetClassPath.GetAssetName().ToString());
Results.Add(MakeShared<FJsonValueObject>(AssetObj));
Count++;
}
}
return Results;
}
TArray<TSharedPtr<FJsonValue>> URalphaParameterBridge::ListAssets(const FString& FolderPath, const FString& AssetType, bool bRecursive)
{
TArray<TSharedPtr<FJsonValue>> Results;
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
FARFilter Filter;
Filter.bRecursivePaths = bRecursive;
Filter.PackagePaths.Add(*FolderPath);
TArray<FAssetData> AssetList;
AssetRegistry.GetAssets(Filter, AssetList);
for (const FAssetData& Asset : AssetList)
{
TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
AssetObj->SetStringField(TEXT("asset_path"), Asset.GetObjectPathString());
AssetObj->SetStringField(TEXT("class"), Asset.AssetClassPath.GetAssetName().ToString());
Results.Add(MakeShared<FJsonValueObject>(AssetObj));
}
return Results;
}
// ============================================================================
// Actor Management
// ============================================================================
bool URalphaParameterBridge::SpawnActor(const FString& AssetPath, const FVector& Location, const FRotator& Rotation, float Scale, const FString& ActorLabel, FString& OutActorId)
{
UWorld* World = GetCurrentWorld();
if (!World) return false;
// Load the asset
UObject* LoadedAsset = StaticLoadObject(UStaticMesh::StaticClass(), nullptr, *AssetPath);
UStaticMesh* StaticMesh = Cast<UStaticMesh>(LoadedAsset);
if (!StaticMesh)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to load static mesh: %s"), *AssetPath);
return false;
}
// Spawn the actor
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AStaticMeshActor* NewActor = World->SpawnActor<AStaticMeshActor>(Location, Rotation, SpawnParams);
if (!NewActor)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to spawn actor"));
return false;
}
NewActor->GetStaticMeshComponent()->SetStaticMesh(StaticMesh);
NewActor->SetActorScale3D(FVector(Scale));
#if WITH_EDITOR
if (!ActorLabel.IsEmpty())
{
NewActor->SetActorLabel(ActorLabel);
}
#endif
OutActorId = NewActor->GetName();
return true;
}
bool URalphaParameterBridge::DeleteActor(const FString& ActorId)
{
UWorld* World = GetCurrentWorld();
if (!World) return false;
for (TActorIterator<AActor> It(World); It; ++It)
{
if (It->GetName() == ActorId)
{
World->DestroyActor(*It);
return true;
}
}
return false;
}
TArray<TSharedPtr<FJsonValue>> URalphaParameterBridge::ListActors(const FString& ClassFilter, const FString& NameFilter, bool bIncludeTransforms)
{
TArray<TSharedPtr<FJsonValue>> Results;
UWorld* World = GetCurrentWorld();
if (!World) return Results;
for (TActorIterator<AActor> It(World); It; ++It)
{
AActor* Actor = *It;
// Apply filters
if (!ClassFilter.IsEmpty() && !Actor->GetClass()->GetName().Contains(ClassFilter))
{
continue;
}
#if WITH_EDITOR
if (!NameFilter.IsEmpty() && !Actor->GetActorLabel().Contains(NameFilter))
{
continue;
}
#else
if (!NameFilter.IsEmpty() && !Actor->GetName().Contains(NameFilter))
{
continue;
}
#endif
TSharedPtr<FJsonObject> ActorObj = MakeShared<FJsonObject>();
ActorObj->SetStringField(TEXT("actor_id"), Actor->GetName());
#if WITH_EDITOR
ActorObj->SetStringField(TEXT("label"), Actor->GetActorLabel());
#else
ActorObj->SetStringField(TEXT("label"), Actor->GetName());
#endif
ActorObj->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
if (bIncludeTransforms)
{
FVector Location = Actor->GetActorLocation();
FRotator Rotation = Actor->GetActorRotation();
FVector Scale = Actor->GetActorScale3D();
TSharedPtr<FJsonObject> TransformObj = MakeShared<FJsonObject>();
TSharedPtr<FJsonObject> LocObj = MakeShared<FJsonObject>();
LocObj->SetNumberField(TEXT("x"), Location.X);
LocObj->SetNumberField(TEXT("y"), Location.Y);
LocObj->SetNumberField(TEXT("z"), Location.Z);
TransformObj->SetObjectField(TEXT("location"), LocObj);
TSharedPtr<FJsonObject> RotObj = MakeShared<FJsonObject>();
RotObj->SetNumberField(TEXT("pitch"), Rotation.Pitch);
RotObj->SetNumberField(TEXT("yaw"), Rotation.Yaw);
RotObj->SetNumberField(TEXT("roll"), Rotation.Roll);
TransformObj->SetObjectField(TEXT("rotation"), RotObj);
TSharedPtr<FJsonObject> ScaleObj = MakeShared<FJsonObject>();
ScaleObj->SetNumberField(TEXT("x"), Scale.X);
ScaleObj->SetNumberField(TEXT("y"), Scale.Y);
ScaleObj->SetNumberField(TEXT("z"), Scale.Z);
TransformObj->SetObjectField(TEXT("scale"), ScaleObj);
ActorObj->SetObjectField(TEXT("transform"), TransformObj);
}
Results.Add(MakeShared<FJsonValueObject>(ActorObj));
}
return Results;
}
bool URalphaParameterBridge::SetActorTransform(const FString& ActorId, const FVector* Location, const FRotator* Rotation, const float* Scale, bool bRelative)
{
UWorld* World = GetCurrentWorld();
if (!World) return false;
for (TActorIterator<AActor> It(World); It; ++It)
{
if (It->GetName() == ActorId)
{
AActor* Actor = *It;
if (Location)
{
if (bRelative)
{
Actor->SetActorLocation(Actor->GetActorLocation() + *Location);
}
else
{
Actor->SetActorLocation(*Location);
}
}
if (Rotation)
{
if (bRelative)
{
Actor->SetActorRotation(Actor->GetActorRotation() + *Rotation);
}
else
{
Actor->SetActorRotation(*Rotation);
}
}
if (Scale)
{
Actor->SetActorScale3D(FVector(*Scale));
}
return true;
}
}
return false;
}
TSharedPtr<FJsonObject> URalphaParameterBridge::GetActorDetails(const FString& ActorId, bool bIncludeComponents, bool bIncludeMaterials)
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
UWorld* World = GetCurrentWorld();
if (!World) return Result;
for (TActorIterator<AActor> It(World); It; ++It)
{
if (It->GetName() == ActorId)
{
AActor* Actor = *It;
Result->SetStringField(TEXT("actor_id"), Actor->GetName());
#if WITH_EDITOR
Result->SetStringField(TEXT("label"), Actor->GetActorLabel());
#else
Result->SetStringField(TEXT("label"), Actor->GetName());
#endif
Result->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
// Transform
FVector Location = Actor->GetActorLocation();
FRotator Rotation = Actor->GetActorRotation();
FVector Scale = Actor->GetActorScale3D();
TSharedPtr<FJsonObject> TransformObj = MakeShared<FJsonObject>();
TSharedPtr<FJsonObject> LocObj = MakeShared<FJsonObject>();
LocObj->SetNumberField(TEXT("x"), Location.X);
LocObj->SetNumberField(TEXT("y"), Location.Y);
LocObj->SetNumberField(TEXT("z"), Location.Z);
TransformObj->SetObjectField(TEXT("location"), LocObj);
TSharedPtr<FJsonObject> RotObj = MakeShared<FJsonObject>();
RotObj->SetNumberField(TEXT("pitch"), Rotation.Pitch);
RotObj->SetNumberField(TEXT("yaw"), Rotation.Yaw);
RotObj->SetNumberField(TEXT("roll"), Rotation.Roll);
TransformObj->SetObjectField(TEXT("rotation"), RotObj);
Result->SetObjectField(TEXT("transform"), TransformObj);
if (bIncludeComponents)
{
TArray<TSharedPtr<FJsonValue>> ComponentsArray;
TArray<UActorComponent*> Components;
Actor->GetComponents(Components);
for (UActorComponent* Component : Components)
{
TSharedPtr<FJsonObject> CompObj = MakeShared<FJsonObject>();
CompObj->SetStringField(TEXT("name"), Component->GetName());
CompObj->SetStringField(TEXT("class"), Component->GetClass()->GetName());
ComponentsArray.Add(MakeShared<FJsonValueObject>(CompObj));
}
Result->SetArrayField(TEXT("components"), ComponentsArray);
}
return Result;
}
}
return Result;
}

View File

@ -0,0 +1,166 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaScreenCapture.h"
#include "RalphaMCPServer.h"
#include "Modules/ModuleManager.h"
#include "Engine/GameViewportClient.h"
#include "Engine/Engine.h"
#include "Slate/SceneViewport.h"
#include "ImageUtils.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
#include "Misc/Base64.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "HAL/PlatformFileManager.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/SWindow.h"
#include "UnrealClient.h"
#if WITH_EDITOR
#include "Editor.h"
#include "LevelEditorViewport.h"
#endif
URalphaScreenCapture::URalphaScreenCapture()
{
}
bool URalphaScreenCapture::CaptureScreenshot(int32 Width, int32 Height, FString& OutBase64, FString& OutFilePath)
{
// Get the game viewport
UGameViewportClient* ViewportClient = GEngine ? GEngine->GameViewport : nullptr;
// In editor, we might not have a game viewport, try to get the active viewport
FViewport* Viewport = nullptr;
if (ViewportClient && ViewportClient->Viewport)
{
Viewport = ViewportClient->Viewport;
}
#if WITH_EDITOR
else
{
// Try to get the editor viewport
if (GEditor)
{
for (FLevelEditorViewportClient* LevelVC : GEditor->GetLevelViewportClients())
{
if (LevelVC && LevelVC->Viewport)
{
Viewport = LevelVC->Viewport;
break;
}
}
}
}
#endif
if (!Viewport)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("No viewport available for screenshot"));
return false;
}
// Read pixels from the viewport
TArray<FColor> Bitmap;
int32 ViewportWidth = Viewport->GetSizeXY().X;
int32 ViewportHeight = Viewport->GetSizeXY().Y;
if (ViewportWidth <= 0 || ViewportHeight <= 0)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Invalid viewport size: %dx%d"), ViewportWidth, ViewportHeight);
return false;
}
// Read the viewport pixels
bool bSuccess = Viewport->ReadPixels(Bitmap);
if (!bSuccess || Bitmap.Num() == 0)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to read pixels from viewport"));
return false;
}
// Convert to base64 PNG
OutBase64 = PixelsToBase64PNG(Bitmap, ViewportWidth, ViewportHeight);
// Save to disk as well
FString ScreenshotDir = GetScreenshotDirectory();
FString Filename = FString::Printf(TEXT("Ralpha_%s.png"), *FDateTime::Now().ToString(TEXT("%Y%m%d_%H%M%S")));
OutFilePath = ScreenshotDir / Filename;
// Save the PNG
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
if (ImageWrapper.IsValid() && ImageWrapper->SetRaw(Bitmap.GetData(), Bitmap.Num() * sizeof(FColor), ViewportWidth, ViewportHeight, ERGBFormat::BGRA, 8))
{
TArray64<uint8> PNGData = ImageWrapper->GetCompressed(0);
if (PNGData.Num() > 0)
{
FFileHelper::SaveArrayToFile(PNGData, *OutFilePath);
}
}
UE_LOG(LogRalphaMCP, Log, TEXT("Screenshot captured: %dx%d, saved to %s"), ViewportWidth, ViewportHeight, *OutFilePath);
return true;
}
bool URalphaScreenCapture::CaptureHighResScreenshot(int32 Width, int32 Height, FString& OutBase64)
{
// For high-res screenshots, we would use FHighResScreenshotConfig
// This is a simplified implementation
FString FilePath;
return CaptureScreenshot(Width, Height, OutBase64, FilePath);
}
FString URalphaScreenCapture::PixelsToBase64PNG(const TArray<FColor>& Pixels, int32 Width, int32 Height)
{
// Load the image wrapper module
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
if (!ImageWrapper.IsValid())
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to create image wrapper"));
return FString();
}
// Set the raw pixel data
if (!ImageWrapper->SetRaw(Pixels.GetData(), Pixels.Num() * sizeof(FColor), Width, Height, ERGBFormat::BGRA, 8))
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to set raw pixel data"));
return FString();
}
// Compress to PNG
TArray64<uint8> PNGData = ImageWrapper->GetCompressed(0);
if (PNGData.Num() == 0)
{
UE_LOG(LogRalphaMCP, Warning, TEXT("Failed to compress to PNG"));
return FString();
}
// Convert to base64
TArray<uint8> PNGData32;
PNGData32.Append(PNGData.GetData(), PNGData.Num());
return FBase64::Encode(PNGData32);
}
FString URalphaScreenCapture::GetScreenshotDirectory()
{
FString ScreenshotDir = FPaths::ProjectSavedDir() / TEXT("Screenshots") / TEXT("Ralpha");
// Create directory if it doesn't exist
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if (!PlatformFile.DirectoryExists(*ScreenshotDir))
{
PlatformFile.CreateDirectoryTree(*ScreenshotDir);
}
return ScreenshotDir;
}

View File

@ -0,0 +1,20 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class RALPHACORE_API FRalphaCoreModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
/** Get the module instance */
static FRalphaCoreModule& Get();
/** Check if module is loaded */
static bool IsAvailable();
};

View File

@ -0,0 +1,98 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "Containers/Ticker.h"
#include "RalphaMCPServer.generated.h"
class FRalphaClientConnection;
class URalphaParameterBridge;
class URalphaScreenCapture;
DECLARE_LOG_CATEGORY_EXTERN(LogRalphaMCP, Log, All);
/**
* TCP Server that receives JSON-RPC commands from the Python MCP server
* and executes them against UE5 systems.
*/
UCLASS(BlueprintType)
class RALPHACORE_API URalphaMCPServer : public UObject
{
GENERATED_BODY()
public:
URalphaMCPServer();
virtual ~URalphaMCPServer();
/** Get the singleton instance */
UFUNCTION(BlueprintCallable, Category = "Ralpha")
static URalphaMCPServer* Get();
/** Start the TCP server */
UFUNCTION(BlueprintCallable, Category = "Ralpha")
bool Start(int32 Port = 30010);
/** Stop the TCP server */
UFUNCTION(BlueprintCallable, Category = "Ralpha")
void Stop();
/** Check if server is running */
UFUNCTION(BlueprintCallable, Category = "Ralpha")
bool IsRunning() const;
/** Get the port number */
UFUNCTION(BlueprintCallable, Category = "Ralpha")
int32 GetPort() const { return ServerPort; }
/** Process a JSON command and return response */
FString ProcessCommand(const FString& JsonCommand);
protected:
/** Tick function to accept new connections */
bool Tick(float DeltaTime);
private:
static URalphaMCPServer* Instance;
FSocket* ListenerSocket;
int32 ServerPort;
bool bIsRunning;
TArray<TSharedPtr<FRalphaClientConnection>> ClientConnections;
UPROPERTY()
URalphaParameterBridge* ParameterBridge;
UPROPERTY()
URalphaScreenCapture* ScreenCapture;
FTSTicker::FDelegateHandle TickDelegateHandle;
};
/**
* Handles a single client connection
*/
class RALPHACORE_API FRalphaClientConnection : public TSharedFromThis<FRalphaClientConnection>
{
public:
FRalphaClientConnection(FSocket* InSocket, URalphaMCPServer* InServer);
~FRalphaClientConnection();
/** Process incoming data */
void Tick();
/** Check if connection is valid */
bool IsValid() const;
/** Send response to client */
void SendResponse(const FString& Response);
private:
FSocket* Socket;
URalphaMCPServer* Server;
FString ReceiveBuffer;
};

View File

@ -0,0 +1,80 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Dom/JsonObject.h"
#include "Dom/JsonValue.h"
#include "RalphaParameterBridge.generated.h"
class APostProcessVolume;
class ADirectionalLight;
class ASkyLight;
class AExponentialHeightFog;
class ACineCameraActor;
/**
* Bridge between MCP commands and UE5 rendering systems.
* Handles getting/setting parameters on post-process volumes, lights, fog, cameras, etc.
*/
UCLASS(BlueprintType)
class RALPHACORE_API URalphaParameterBridge : public UObject
{
GENERATED_BODY()
public:
URalphaParameterBridge();
// Get all current rendering parameters
TSharedPtr<FJsonObject> GetAllParameters();
// Post-Process Volume
bool SetPostProcessParameters(const TSharedPtr<FJsonObject>& Params);
TSharedPtr<FJsonObject> GetPostProcessParameters();
// Directional Light (Sun)
bool SetDirectionalLightParameters(const TSharedPtr<FJsonObject>& Params);
TSharedPtr<FJsonObject> GetDirectionalLightParameters();
// Sky Light
bool SetSkyLightParameters(const TSharedPtr<FJsonObject>& Params);
TSharedPtr<FJsonObject> GetSkyLightParameters();
// Exponential Height Fog
bool SetFogParameters(const TSharedPtr<FJsonObject>& Params);
TSharedPtr<FJsonObject> GetFogParameters();
// Camera
bool SetCameraParameters(const TSharedPtr<FJsonObject>& Params);
TSharedPtr<FJsonObject> GetCameraParameters();
// Render Quality
bool SetRenderQuality(const TSharedPtr<FJsonObject>& Settings);
// Asset Search
TArray<TSharedPtr<FJsonValue>> SearchAssets(const FString& Query, const FString& AssetType, int32 MaxResults);
TArray<TSharedPtr<FJsonValue>> ListAssets(const FString& FolderPath, const FString& AssetType, bool bRecursive);
// Actor Management
bool SpawnActor(const FString& AssetPath, const FVector& Location, const FRotator& Rotation, float Scale, const FString& ActorLabel, FString& OutActorId);
bool DeleteActor(const FString& ActorId);
TArray<TSharedPtr<FJsonValue>> ListActors(const FString& ClassFilter, const FString& NameFilter, bool bIncludeTransforms);
bool SetActorTransform(const FString& ActorId, const FVector* Location, const FRotator* Rotation, const float* Scale, bool bRelative);
TSharedPtr<FJsonObject> GetActorDetails(const FString& ActorId, bool bIncludeComponents, bool bIncludeMaterials);
private:
// Find actors of specific types in the world
APostProcessVolume* FindPostProcessVolume();
ADirectionalLight* FindDirectionalLight();
ASkyLight* FindSkyLight();
AExponentialHeightFog* FindExponentialHeightFog();
ACineCameraActor* FindCineCamera();
// Get the current world
UWorld* GetCurrentWorld();
// Parse hex color string to FLinearColor
FLinearColor ParseHexColor(const FString& HexColor);
FString ColorToHex(const FLinearColor& Color);
};

View File

@ -0,0 +1,47 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "RalphaScreenCapture.generated.h"
/**
* Handles viewport screenshot capture for the style convergence loop.
*/
UCLASS(BlueprintType)
class RALPHACORE_API URalphaScreenCapture : public UObject
{
GENERATED_BODY()
public:
URalphaScreenCapture();
/**
* Capture the current viewport as a PNG image.
* @param Width Desired width (may be clamped to viewport size)
* @param Height Desired height (may be clamped to viewport size)
* @param OutBase64 The captured image as base64-encoded PNG
* @param OutFilePath Path where the image was saved (if saved to disk)
* @return True if capture succeeded
*/
UFUNCTION(BlueprintCallable, Category = "Ralpha")
bool CaptureScreenshot(int32 Width, int32 Height, FString& OutBase64, FString& OutFilePath);
/**
* Capture a high-resolution screenshot.
* @param Width Desired width
* @param Height Desired height
* @param OutBase64 The captured image as base64-encoded PNG
* @return True if capture succeeded
*/
UFUNCTION(BlueprintCallable, Category = "Ralpha")
bool CaptureHighResScreenshot(int32 Width, int32 Height, FString& OutBase64);
private:
/** Convert raw pixel data to base64 PNG */
FString PixelsToBase64PNG(const TArray<FColor>& Pixels, int32 Width, int32 Height);
/** Get the screenshot save directory */
FString GetScreenshotDirectory();
};

View File

@ -0,0 +1,59 @@
// Copyright Ralpha Team. All Rights Reserved.
using UnrealBuildTool;
public class RalphaCore : ModuleRules
{
public RalphaCore(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
}
);
PrivateIncludePaths.AddRange(
new string[] {
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"Sockets",
"Networking",
"Json",
"JsonUtilities",
"RenderCore",
"Renderer",
"RHI",
"ImageWrapper",
"AssetRegistry",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Slate",
"SlateCore",
"CinematicCamera",
}
);
if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("UnrealEd");
}
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
}
);
}
}

View File

@ -0,0 +1,74 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaEditor.h"
#include "RalphaEditorCommands.h"
#include "RalphaEditorStyle.h"
#include "ToolMenus.h"
#include "RalphaMCPServer.h"
#define LOCTEXT_NAMESPACE "FRalphaEditorModule"
void FRalphaEditorModule::StartupModule()
{
FRalphaEditorStyle::Initialize();
FRalphaEditorStyle::ReloadTextures();
FRalphaEditorCommands::Register();
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FRalphaEditorCommands::Get().StartServer,
FExecuteAction::CreateLambda([]()
{
URalphaMCPServer* Server = URalphaMCPServer::Get();
if (Server)
{
if (!Server->IsRunning())
{
Server->Start();
}
else
{
Server->Stop();
}
}
}),
FCanExecuteAction()
);
UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FRalphaEditorModule::RegisterMenus));
UE_LOG(LogTemp, Log, TEXT("Ralpha Editor Module Started"));
}
void FRalphaEditorModule::ShutdownModule()
{
UToolMenus::UnRegisterStartupCallback(this);
UToolMenus::UnregisterOwner(this);
FRalphaEditorStyle::Shutdown();
FRalphaEditorCommands::Unregister();
UE_LOG(LogTemp, Log, TEXT("Ralpha Editor Module Shutdown"));
}
void FRalphaEditorModule::RegisterMenus()
{
FToolMenuOwnerScoped OwnerScoped(this);
{
UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar");
{
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("Ralpha");
{
FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FRalphaEditorCommands::Get().StartServer));
Entry.SetCommandList(PluginCommands);
}
}
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FRalphaEditorModule, RalphaEditor)

View File

@ -0,0 +1,12 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaEditorCommands.h"
#define LOCTEXT_NAMESPACE "FRalphaEditorModule"
void FRalphaEditorCommands::RegisterCommands()
{
UI_COMMAND(StartServer, "Ralpha", "Start/Stop the Ralpha MCP Server", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,59 @@
// Copyright Ralpha Team. All Rights Reserved.
#include "RalphaEditorStyle.h"
#include "Styling/SlateStyleRegistry.h"
#include "Framework/Application/SlateApplication.h"
#include "Slate/SlateGameResources.h"
#include "Interfaces/IPluginManager.h"
#include "Styling/SlateStyleMacros.h"
#define RootToContentDir Style->RootToContentDir
TSharedPtr<FSlateStyleSet> FRalphaEditorStyle::StyleInstance = nullptr;
void FRalphaEditorStyle::Initialize()
{
if (!StyleInstance.IsValid())
{
StyleInstance = Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
}
}
void FRalphaEditorStyle::Shutdown()
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
ensure(StyleInstance.IsUnique());
StyleInstance.Reset();
}
FName FRalphaEditorStyle::GetStyleSetName()
{
static FName StyleSetName(TEXT("RalphaEditorStyle"));
return StyleSetName;
}
const ISlateStyle& FRalphaEditorStyle::Get()
{
return *StyleInstance;
}
void FRalphaEditorStyle::ReloadTextures()
{
if (FSlateApplication::IsInitialized())
{
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
}
}
TSharedRef<FSlateStyleSet> FRalphaEditorStyle::Create()
{
TSharedRef<FSlateStyleSet> Style = MakeShareable(new FSlateStyleSet("RalphaEditorStyle"));
Style->SetContentRoot(IPluginManager::Get().FindPlugin("RalphaPlugin")->GetBaseDir() / TEXT("Resources"));
Style->Set("Ralpha.StartServer", new IMAGE_BRUSH_SVG(TEXT("Icon20"), FVector2D(20.0f, 20.0f)));
return Style;
}
#undef RootToContentDir

View File

@ -0,0 +1,22 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FToolBarBuilder;
class FMenuBuilder;
class RALPHAEDITOR_API FRalphaEditorModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
private:
void RegisterMenus();
TSharedPtr<class FUICommandList> PluginCommands;
};

View File

@ -0,0 +1,25 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"
#include "RalphaEditorStyle.h"
class FRalphaEditorCommands : public TCommands<FRalphaEditorCommands>
{
public:
FRalphaEditorCommands()
: TCommands<FRalphaEditorCommands>(
TEXT("Ralpha"),
NSLOCTEXT("Contexts", "Ralpha", "Ralpha Plugin"),
NAME_None,
FRalphaEditorStyle::GetStyleSetName())
{
}
virtual void RegisterCommands() override;
public:
TSharedPtr<FUICommandInfo> StartServer;
};

View File

@ -0,0 +1,20 @@
// Copyright Ralpha Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Styling/SlateStyle.h"
class FRalphaEditorStyle
{
public:
static void Initialize();
static void Shutdown();
static void ReloadTextures();
static const ISlateStyle& Get();
static FName GetStyleSetName();
private:
static TSharedRef<class FSlateStyleSet> Create();
static TSharedPtr<class FSlateStyleSet> StyleInstance;
};

View File

@ -0,0 +1,52 @@
// Copyright Ralpha Team. All Rights Reserved.
using UnrealBuildTool;
public class RalphaEditor : ModuleRules
{
public RalphaEditor(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
}
);
PrivateIncludePaths.AddRange(
new string[] {
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"RalphaCore",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"UnrealEd",
"EditorStyle",
"ToolMenus",
"LevelEditor",
"AssetRegistry",
"ContentBrowser",
"Projects",
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
}
);
}
}

16
Ralpha.uproject Normal file
View File

@ -0,0 +1,16 @@
{
"FileVersion": 3,
"EngineAssociation": "5.7",
"Category": "",
"Description": "AI-driven style transfer for infinite world generation",
"Modules": [],
"Plugins": [
{
"Name": "RalphaPlugin",
"Enabled": true
}
],
"TargetPlatforms": [
"Windows"
]
}