Can now switch the skeletal mesh on a character

This commit is contained in:
2026-02-17 15:49:52 -05:00
parent 3f975dbada
commit a987754b38
16 changed files with 157 additions and 125 deletions

View File

@@ -3,7 +3,12 @@
"allow": [ "allow": [
"WebFetch(domain:dev.epicgames.com)", "WebFetch(domain:dev.epicgames.com)",
"WebFetch(domain:github.com)", "WebFetch(domain:github.com)",
"Bash(grep:*)" "Bash(grep:*)",
"WebSearch",
"Bash(clangd:*)",
"Bash(clangd-16:*)",
"Bash(ssh jyelon-office \"clangd --version 2>/dev/null || clangd-16 --version 2>/dev/null || clangd-18 --version 2>/dev/null || ls /usr/bin/clangd*\")",
"Bash(git check-ignore:*)"
], ],
"deny": [ "deny": [
"Bash(git commit *)", "Bash(git commit *)",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,52 @@
# Error Handling in Blueprints
## Format Log Message Node
We have implemented "Format Message", which is an improved version of Unreal's
"Format Text". Unlike "Format Text", it has built-in support to print
vectors, rotations, enums, and quite a few other types.
We have also implemented "Format Log Message", which is like Format Message
except that the output goes to the unreal logs. It might help to familiarize
yourself with Unreal's built-in logging function, UE_LOG. Format Log Message
is meant to be the Blueprint front end to UE_LOG.
Format Message and Format Log Message both require a format string, which
will typically look something like this:
"Hello, {Name}, the weather today will be {Weather}"
When you set a format string such as the one above, the Format Message node
will add pins for the placeholders - in the example above, the pins
Name and Weather would be added. These are wildcard pins that you can
connect any printable value to.
To make a new type printable, look at FormatDataLibrary.h
Format Log Message accepts a severity level, this is directly based on
the severity levels supported by UE_LOG. It adds *ThrottledDisplay* and
*ThrottledLog*, which do the same thing as *Display* and *Log*, except
that output is limited to one message per second.
## The Blueprint Debugger Pauses on Error Messages
The blueprint debugger will pause whenever you log an error message. This is functionality we have added to Unreal.
You can control the severity at which it pauses: in the GameMode, there is a dropdown for the severity level.
You can also effectively turn it off by telling to only pause on fatal errors.
There is a quirk: the debugger pauses before the error gets put into the logs. So when you're in the
blueprint debugger,
the only place the error will appear is in the lower-right corner of the screen, where debugger messages are
reported. You won't see the error in the unreal output log. If you single-step, the error will appear
in the output log as well.
To understand how this is implemented, it helps to understand that log messages in unreal go to a bunch of
different output devices: the unreal editor output window, the visual studio output window, a log file, and
several more places. To dispatch messages to all these different destinations, Unreal has an output device
list that you can add an output device to.
To implement this break-on-error-message functionality, we implemented a pseudo-output-device.
The pseudo device doesn't actually send
the error message anywhere, it just triggers the debugger. For more information about implementation,
see BreakToDebugger.h

View File

@@ -143,3 +143,6 @@ it adds those string to the UlxConsoleOutput. The UlxConsoleOutput
turns those individual lines into one big string. From there, turns those individual lines into one big string. From there,
the LuprexGameMode copies the entire string into the body of the LuprexGameMode copies the entire string into the body of
a UMG text widget. a UMG text widget.
## A Possible new lua print function

View File

@@ -627,45 +627,43 @@ void UlxAnimationStepLibrary::AnimationStepApplyMaterials(const FlxAnimationStep
} }
} }
void UlxAnimationStepLibrary::AnimationStepApplyMesh(const FlxAnimationStep& step, bool FallbackToBP, AActor* actor) { void UlxAnimationStepLibrary::AnimationStepApplyStaticMesh(const FlxAnimationStep& step, bool FallbackToBP,
if (actor == nullptr) return; UStaticMeshComponent* MeshComp, UStaticMesh* Fallback) {
if (MeshComp == nullptr) return;
// Step 1: Look for a "mesh" or "bp" string field in the animation step.
//
FString MeshName = AnimationStepGetString(step, TEXT("mesh")); FString MeshName = AnimationStepGetString(step, TEXT("mesh"));
if (MeshName.IsEmpty() && FallbackToBP) { if (MeshName.IsEmpty() && FallbackToBP) {
MeshName = AnimationStepGetString(step, TEXT("bp")); MeshName = AnimationStepGetString(step, TEXT("bp"));
} }
if (MeshName.IsEmpty()) return;
// Step 2: Find the actor's mesh component. There must be exactly one. UStaticMesh* NewMesh = nullptr;
// if (!MeshName.IsEmpty()) {
TInlineComponentArray<UMeshComponent*> MeshComponents; UlxAssetLookup::LoadStaticMeshAsset(NewMesh, MeshComp, MeshName);
actor->GetComponents<UMeshComponent>(MeshComponents);
if (MeshComponents.Num() != 1) {
UE_LOG(LogLuprexIntegration, Error, TEXT("AnimationStepApplyMesh: Actor %s has %d mesh components, expected exactly 1"), *actor->GetName(), MeshComponents.Num());
return;
} }
UMeshComponent* MeshComp = MeshComponents[0]; if (NewMesh == nullptr) NewMesh = Fallback;
if (NewMesh == nullptr) return;
// Step 3: Apply the mesh based on the component type. if (MeshComp->GetStaticMesh() != NewMesh) {
// MeshComp->SetStaticMesh(NewMesh);
if (UStaticMeshComponent* StaticComp = Cast<UStaticMeshComponent>(MeshComp)) { }
UStaticMesh* NewMesh = nullptr; }
UlxAssetLookup::LoadStaticMeshAsset(NewMesh, actor, MeshName, false);
if (NewMesh == nullptr) return; void UlxAnimationStepLibrary::AnimationStepApplySkeletalMesh(const FlxAnimationStep& step, bool FallbackToBP,
if (StaticComp->GetStaticMesh() != NewMesh) { USkeletalMeshComponent* MeshComp, USkeletalMesh* Fallback) {
StaticComp->SetStaticMesh(NewMesh); if (MeshComp == nullptr) return;
}
} else if (USkeletalMeshComponent* SkelComp = Cast<USkeletalMeshComponent>(MeshComp)) { FString MeshName = AnimationStepGetString(step, TEXT("mesh"));
USkeletalMesh* NewMesh = nullptr; if (MeshName.IsEmpty() && FallbackToBP) {
UlxAssetLookup::LoadSkeletalMeshAsset(NewMesh, actor, MeshName, true); MeshName = AnimationStepGetString(step, TEXT("bp"));
if (NewMesh == nullptr) return; }
if (SkelComp->GetSkeletalMeshAsset() != NewMesh) {
SkelComp->SetSkeletalMeshAsset(NewMesh); USkeletalMesh* NewMesh = nullptr;
} if (!MeshName.IsEmpty()) {
} else { UlxAssetLookup::LoadSkeletalMeshAsset(NewMesh, MeshComp, MeshName);
UE_LOG(LogLuprexIntegration, Error, TEXT("AnimationStepApplyMesh: Actor %s has unsupported mesh component type"), *actor->GetName()); }
if (NewMesh == nullptr) NewMesh = Fallback;
if (NewMesh == nullptr) return;
if (MeshComp->GetSkeletalMeshAsset() != NewMesh) {
MeshComp->SetSkeletalMeshAsset(NewMesh);
} }
} }

View File

@@ -125,55 +125,40 @@ public:
UFUNCTION(BlueprintPure, meta = (BlueprintAutocast), Category = "Luprex|Animation Step") UFUNCTION(BlueprintPure, meta = (BlueprintAutocast), Category = "Luprex|Animation Step")
static int64 AnimationStepID(const FlxAnimationStep& step) { return step.Hash; } static int64 AnimationStepID(const FlxAnimationStep& step) { return step.Hash; }
<<<<<<< HEAD
// Using mat_xxxx values from the animation step, update the actor's // Using mat_xxxx values from the animation step, update the actor's
// material parameters. Doing this may involve creating or replacing // material parameters. Doing this may involve creating or replacing
// dynamic material instances for the actor. // dynamic material instances for the actor.
=======
// Scan an animation step for key-value pairs of the
// form mat_XXXX={x,y,z}. For each match, create a
// dynamic material instance on the actor's mesh
// components and set the vector parameter XXXX.
// Materials are restored to their base (non-dynamic)
// state before applying, so parameters from previous
// calls do not persist.
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
// //
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step") UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step")
static void AnimationStepApplyMaterials(const FlxAnimationStep& step, AActor* actor); static void AnimationStepApplyMaterials(const FlxAnimationStep& step, AActor* actor);
<<<<<<< HEAD // Loads a new static mesh, using the animation step to choose it.
// Look for a mesh=name key-value pair in the animation step. // If the chosen mesh is already installed, no changes are made.
// If found, load the named mesh and apply it to the actor's // Looks for 'mesh=name' first; if not found and FallbackToBP is
// mesh component. The actor must have exactly one mesh component. // true, looks for 'bp=name'. If no mesh is successfully loaded,
// If FallbackToBP is true, and mesh=name is not present, looks // uses the Fallback mesh. Failed loads are logged once.
// for a bp=name pair instead.
=======
// Look for a mesh=name key-value pair. If found, load
// the named mesh and apply it to the actor's mesh
// component. The actor must have exactly one mesh
// component.
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
// //
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step") UFUNCTION(BlueprintCallable, Category = "Luprex|Animation Step")
static void AnimationStepApplyMesh(const FlxAnimationStep& step, bool FallbackToBP, AActor* actor); static void AnimationStepApplyStaticMesh(const FlxAnimationStep& step, bool FallbackToBP,
UStaticMeshComponent* MeshComp, UStaticMesh* Fallback = nullptr);
// Loads a new skeletal mesh, using the animation step to choose it.
// If the chosen mesh is already installed, no changes are made.
// Looks for 'mesh=name' first; if not found and FallbackToBP is
// true, looks for 'bp=name'. If no mesh is successfully loaded,
// uses the Fallback mesh. Failed loads are logged once.
//
UFUNCTION(BlueprintCallable, Category = "Luprex|Animation Step")
static void AnimationStepApplySkeletalMesh(const FlxAnimationStep& step, bool FallbackToBP,
USkeletalMeshComponent* MeshComp, USkeletalMesh* Fallback = nullptr);
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
<<<<<<< HEAD
// An animation step that doesn't actually store the step, // An animation step that doesn't actually store the step,
// it just contains a pointer to the string. // it just contains a pointer to the string.
// //
////////////////////////////////////////////////
=======
// FlxAnimationStepView
//
// A lightweight, non-owning view of an animation
// step (hash + body as a string_view).
//
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
struct FlxAnimationStepView { struct FlxAnimationStepView {
int64 Hash; int64 Hash;
@@ -266,13 +251,8 @@ private:
FlxStreamBuffer Decoder; FlxStreamBuffer Decoder;
public: public:
<<<<<<< HEAD
// Initialize the FlxAnimationStepDecoder.
//
=======
// Initialize from an encoded step body. // Initialize from an encoded step body.
// //
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {} FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {}
// Return true if the parser has reached EOF. // Return true if the parser has reached EOF.

View File

@@ -20,7 +20,7 @@ void UlxAssetLookup::RebuildIndex()
IAssetRegistry::GetChecked().WaitForCompletion(); IAssetRegistry::GetChecked().WaitForCompletion();
AssetPaths.Empty(); AssetPaths.Empty();
AddAssets(TEXT("/Game/StaticMeshes"), UStaticMesh::StaticClass(), TEXT("SM_")); AddAssets(TEXT("/Game/StaticMeshes"), UStaticMesh::StaticClass(), TEXT("SM_"));
AddAssets(TEXT("/Game/SkeletalMeshes"), USkeletalMesh::StaticClass(), TEXT("SK_")); AddAssets(TEXT("/Game/SkeletalMeshes"), USkeletalMesh::StaticClass(), TEXT("SKM_"));
AddAssets(TEXT("/Game/AnimSequences"), UAnimSequence::StaticClass(), TEXT("SEQ_")); AddAssets(TEXT("/Game/AnimSequences"), UAnimSequence::StaticClass(), TEXT("SEQ_"));
AddAssets(TEXT("/Game/Tangibles"), UBlueprint::StaticClass(), TEXT("TAN_")); AddAssets(TEXT("/Game/Tangibles"), UBlueprint::StaticClass(), TEXT("TAN_"));
AddAssets(TEXT("/Game/Widgets"), UWidgetBlueprint::StaticClass(), TEXT("WB_")); AddAssets(TEXT("/Game/Widgets"), UWidgetBlueprint::StaticClass(), TEXT("WB_"));
@@ -52,16 +52,22 @@ void UlxAssetLookup::AddAssets(const TCHAR *Path, UClass *Class, const TCHAR *Na
FoundData.Num(), *Class->GetName(), Path); FoundData.Num(), *Class->GetName(), Path);
} }
UObject *UlxAssetLookup::LoadAsset(const UObject *Context, UClass *Class, UClass *ChildOf, const FString &Name, bool ErrorIfNotFound) void UlxAssetLookup::ReportFailedLoad(const FString &ClassName, const FString &Name, const FString &Reason)
{
static TSet<FString> Reported;
FString Key = ClassName + TEXT(":") + Name + TEXT(":") + Reason;
if (Reported.Contains(Key)) return;
Reported.Add(Key);
UE_LOG(LogLuprexIntegration, Display, TEXT("Loading %s %s: %s"), *ClassName, *Name, *Reason);
}
UObject *UlxAssetLookup::LoadAsset(const UObject *Context, UClass *Class, UClass *ChildOf, const FString &Name)
{ {
const UlxAssetLookup *Lookup = ALuprexGameModeBase::FromContext(Context)->GetAssetLookup(); const UlxAssetLookup *Lookup = ALuprexGameModeBase::FromContext(Context)->GetAssetLookup();
const FString *Path = Lookup->AssetPaths.Find(MakeTuple(Class->GetName(), FName(Name))); const FString *Path = Lookup->AssetPaths.Find(MakeTuple(Class->GetName(), FName(Name)));
if (Path == nullptr) if (Path == nullptr)
{ {
if (ErrorIfNotFound) ReportFailedLoad(Class->GetName(), Name, TEXT("asset not found"));
{
UE_LOG(LogLuprexIntegration, Error, TEXT("Loading %s %s: asset not found"), *Class->GetName(), *Name);
}
return nullptr; return nullptr;
} }
@@ -77,7 +83,7 @@ UObject *UlxAssetLookup::LoadAsset(const UObject *Context, UClass *Class, UClass
if (Result == nullptr) if (Result == nullptr)
{ {
UE_LOG(LogLuprexIntegration, Error, TEXT("Loading %s %s: unknown load failure"), *Class->GetName(), *Name); ReportFailedLoad(Class->GetName(), Name, TEXT("unknown load failure"));
return nullptr; return nullptr;
} }
@@ -86,7 +92,7 @@ UObject *UlxAssetLookup::LoadAsset(const UObject *Context, UClass *Class, UClass
UClass *ResClass = (UClass *)Result; UClass *ResClass = (UClass *)Result;
if (!ResClass->IsChildOf(ChildOf)) if (!ResClass->IsChildOf(ChildOf))
{ {
UE_LOG(LogLuprexIntegration, Error, TEXT("Loading %s %s: blueprint not a child of %s"), *Class->GetName(), *Name, *ChildOf->GetName()); ReportFailedLoad(Class->GetName(), Name, FString::Printf(TEXT("blueprint not a child of %s"), *ChildOf->GetName()));
return nullptr; return nullptr;
} }
} }
@@ -95,50 +101,50 @@ UObject *UlxAssetLookup::LoadAsset(const UObject *Context, UClass *Class, UClass
} }
ElxValidOrNotValid UlxAssetLookup::LoadStaticMeshAsset( ElxValidOrNotValid UlxAssetLookup::LoadStaticMeshAsset(
UStaticMesh *&Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) UStaticMesh *&Result, const UObject *Context, const FString &Name)
{ {
Result = (UStaticMesh *)LoadAsset(Context, UStaticMesh::StaticClass(), nullptr, Name, ErrorIfNotFound); Result = (UStaticMesh *)LoadAsset(Context, UStaticMesh::StaticClass(), nullptr, Name);
return Result ? Valid : NotValid; return Result ? Valid : NotValid;
} }
ElxValidOrNotValid UlxAssetLookup::LoadSkeletalMeshAsset( ElxValidOrNotValid UlxAssetLookup::LoadSkeletalMeshAsset(
USkeletalMesh *&Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) USkeletalMesh *&Result, const UObject *Context, const FString &Name)
{ {
Result = (USkeletalMesh *)LoadAsset(Context, USkeletalMesh::StaticClass(), nullptr, Name, ErrorIfNotFound); Result = (USkeletalMesh *)LoadAsset(Context, USkeletalMesh::StaticClass(), nullptr, Name);
return Result ? Valid : NotValid; return Result ? Valid : NotValid;
} }
ElxValidOrNotValid UlxAssetLookup::LoadAnimSequenceAsset( ElxValidOrNotValid UlxAssetLookup::LoadAnimSequenceAsset(
UAnimSequence *&Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) UAnimSequence *&Result, const UObject *Context, const FString &Name)
{ {
Result = (UAnimSequence *)LoadAsset(Context, UAnimSequence::StaticClass(), nullptr, Name, ErrorIfNotFound); Result = (UAnimSequence *)LoadAsset(Context, UAnimSequence::StaticClass(), nullptr, Name);
return Result ? Valid : NotValid; return Result ? Valid : NotValid;
} }
ElxValidOrNotValid UlxAssetLookup::LoadTangibleBlueprintAsset( ElxValidOrNotValid UlxAssetLookup::LoadTangibleBlueprintAsset(
TSubclassOf<AActor> &Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) TSubclassOf<AActor> &Result, const UObject *Context, const FString &Name)
{ {
Result = (UClass*)LoadAsset(Context, UBlueprint::StaticClass(), AActor::StaticClass(), Name, ErrorIfNotFound); Result = (UClass*)LoadAsset(Context, UBlueprint::StaticClass(), AActor::StaticClass(), Name);
if (Result == nullptr) return NotValid; if (Result == nullptr) return NotValid;
UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed"))); UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0)) if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0))
{ {
UE_LOG(LogLuprexIntegration, Error, TEXT("Loading Blueprint %s: Tangible does not have 'Animation Queue Changed' function"), *Name); ReportFailedLoad(TEXT("Blueprint"), Name, TEXT("tangible does not have 'Animation Queue Changed' function"));
Result = nullptr; return NotValid; Result = nullptr; return NotValid;
} }
return Valid; return Valid;
} }
ElxValidOrNotValid UlxAssetLookup::LoadUserWidgetAsset( ElxValidOrNotValid UlxAssetLookup::LoadUserWidgetAsset(
TSubclassOf<UUserWidget> &Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) TSubclassOf<UUserWidget> &Result, const UObject *Context, const FString &Name)
{ {
Result = (UClass *)LoadAsset(Context, UWidgetBlueprint::StaticClass(), UUserWidget::StaticClass(), Name, ErrorIfNotFound); Result = (UClass *)LoadAsset(Context, UWidgetBlueprint::StaticClass(), UUserWidget::StaticClass(), Name);
return Result ? Valid : NotValid; return Result ? Valid : NotValid;
} }
ElxValidOrNotValid UlxAssetLookup::LoadLuaWidgetAsset( ElxValidOrNotValid UlxAssetLookup::LoadLuaWidgetAsset(
TSubclassOf<UlxLuaWidget> &Result, const UObject *Context, const FString &Name, bool ErrorIfNotFound) TSubclassOf<UlxLuaWidget> &Result, const UObject *Context, const FString &Name)
{ {
Result = (UClass *)LoadAsset(Context, UWidgetBlueprint::StaticClass(), UlxLuaWidget::StaticClass(), Name, ErrorIfNotFound); Result = (UClass *)LoadAsset(Context, UWidgetBlueprint::StaticClass(), UlxLuaWidget::StaticClass(), Name);
return Result ? Valid : NotValid; return Result ? Valid : NotValid;
} }

View File

@@ -43,7 +43,9 @@ private:
void AddAssets(const TCHAR *Path, UClass *Class, const TCHAR *NamePrefix); void AddAssets(const TCHAR *Path, UClass *Class, const TCHAR *NamePrefix);
static UObject *LoadAsset(const UObject *Context, UClass *Class, UClass *ChildOf, const FString &Name, bool ErrorIfNotFound); static void ReportFailedLoad(const FString &ClassName, const FString &Name, const FString &Reason);
static UObject *LoadAsset(const UObject *Context, UClass *Class, UClass *ChildOf, const FString &Name);
public: public:
void RebuildIndex(); void RebuildIndex();
@@ -52,41 +54,35 @@ public:
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadStaticMeshAsset( static ElxValidOrNotValid LoadStaticMeshAsset(
UStaticMesh *&Result, UStaticMesh *&Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a skeletal mesh by name. // Get a skeletal mesh by name.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadSkeletalMeshAsset( static ElxValidOrNotValid LoadSkeletalMeshAsset(
USkeletalMesh *&Result, USkeletalMesh *&Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get an animation sequence by name. // Get an animation sequence by name.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadAnimSequenceAsset( static ElxValidOrNotValid LoadAnimSequenceAsset(
UAnimSequence *&Result, UAnimSequence *&Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a tangible class by name. // Get a tangible class by name.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadTangibleBlueprintAsset( static ElxValidOrNotValid LoadTangibleBlueprintAsset(
TSubclassOf<AActor> &Result, TSubclassOf<AActor> &Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a widget blueprint by name. // Get a widget blueprint by name.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadUserWidgetAsset( static ElxValidOrNotValid LoadUserWidgetAsset(
TSubclassOf<UUserWidget> &Result, TSubclassOf<UUserWidget> &Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a look-at widget blueprint by name. // Get a look-at widget blueprint by name.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading") UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context", ExpandEnumAsExecs="ReturnValue"), Category = "Luprex|Asset Loading")
static ElxValidOrNotValid LoadLuaWidgetAsset( static ElxValidOrNotValid LoadLuaWidgetAsset(
TSubclassOf<UlxLuaWidget> &Result, TSubclassOf<UlxLuaWidget> &Result, const UObject *Context, const FString &Name);
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
}; };

View File

@@ -15,18 +15,12 @@
#pragma once #pragma once
#include "Containers/UnrealString.h" #include "Containers/UnrealString.h"
#include "ConsoleOutput.generated.h" #include "ConsoleOutput.generated.h"
<<<<<<< HEAD
//////////////////////////////////////////////////////////////
=======
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
// //
// UlxConsoleOutput // UlxConsoleOutput
// //
<<<<<<< HEAD
// When the lua code executes a print statement, the text // When the lua code executes a print statement, the text
// eventually gets passed to the GameMode blueprint: see // eventually gets passed to the GameMode blueprint: see
// Docs/Print-Statement-Handling.md for more information. // Docs/Print-Statement-Handling.md for more information.
@@ -52,10 +46,7 @@
// If the GameMode wants to use some other framework to // If the GameMode wants to use some other framework to
// implement the virtual console, that's perfectly fine. // implement the virtual console, that's perfectly fine.
// //
//////////////////////////////////////////////////////////////
=======
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
>>>>>>> 9b1dd00a45a7b17c3546f8574d00e5ec78f17c75
UCLASS(BlueprintType) UCLASS(BlueprintType)
class UlxConsoleOutput : public UObject class UlxConsoleOutput : public UObject

View File

@@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Engine/HitResult.h"
#include "GameFramework/GameModeBase.h" #include "GameFramework/GameModeBase.h"
#include "lpx-enginewrapper.hpp" #include "lpx-enginewrapper.hpp"
#include "StringDecoder.h" #include "StringDecoder.h"

View File

@@ -10,7 +10,7 @@ function login.init()
global.set("nextplayer", player + 1) global.set("nextplayer", player + 1)
dprint("login.init initializing player ", player) dprint("login.init initializing player ", player)
actor.player = player actor.player = player
tangible.animinit{tan=actor, anim={bp="character", plane="earth", xyz={player * 100, 0, 90}}} tangible.animinit{tan=actor, anim={bp="character", mesh="manny", plane="earth", xyz={player * 100, 0, 90}}}
end end
-- This gets called on the admin user. You can call login.init in here if you want. -- This gets called on the admin user. You can call login.init in here if you want.