Start the process of standardizing the formatting of documentation inside our header files.

This commit is contained in:
2026-02-14 02:14:19 -05:00
parent dd159b064d
commit d046ef8161
11 changed files with 567 additions and 399 deletions

View File

@@ -0,0 +1,57 @@
# Comment Formatting Standards
## Line Width
Wrap comments at approximately 60 columns. Code and function signatures are not wrapped.
## Comment Style
Use C++ style (`//`) for all comments. Use `/** */` only for UENUM/UPROPERTY values that should appear as tooltips in the blueprint editor.
## Section Banners
Each class, struct, or enum gets a banner block. The banner line is 60 characters of slashes. The banner names the type and gives a brief description.
```cpp
////////////////////////////////////////////////////////////
//
// FlxExampleClass
//
// Brief description of what this class does.
//
////////////////////////////////////////////////////////////
```
## Header File Banners
Ideally, we'd like to have documentation about what a header
file is for. This would be a banner block at the top of the
header file, before the pragma once. If you're claude code,
and there is no documentation yet, generate a little, but
mark it "DOCUMENTATION GENERATED BY CLAUDE."
## Member Comments
Comments on member variables and functions use `//` followed by a blank `//` line:
```cpp
// Brief description of what this does.
//
void DoSomething();
```
## UFUNCTION Spacing
UFUNCTION-decorated members should be followed by a single blank line to visually separate them from the next member:
```cpp
// Get the value.
//
UFUNCTION(BlueprintCallable)
int32 GetValue() const;
// Set the value.
//
UFUNCTION(BlueprintCallable)
void SetValue(int32 Val);
```

View File

@@ -8,17 +8,17 @@
#include "AnimQueue.generated.h" #include "AnimQueue.generated.h"
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// An single animation step. // FlxAnimationStep
// //
// This struct contains an entire animation step. The // A single animation step. The key-value pairs
// key-value pairs are stored in an encoded form, which is not // are stored in an encoded form, which is not
// directly accessible to blueprints. To read these key-value // directly accessible to blueprints. To read
// pairs, blueprints will need to use UnpackAnimationStep or // them, use UnpackAnimationStep or the
// AnimationStepGetXXX. // AnimationStepGetXXX functions.
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
USTRUCT(BlueprintType) USTRUCT(BlueprintType)
struct INTEGRATION_API FlxAnimationStep { struct INTEGRATION_API FlxAnimationStep {
@@ -28,14 +28,16 @@ public:
UPROPERTY() UPROPERTY()
bool Finished; bool Finished;
// The hash of the animation step, a 63-bit unique identifier. // The hash of the animation step, a 63-bit
// unique identifier.
// //
UPROPERTY() UPROPERTY()
int64 Hash; int64 Hash;
// The Body contains all the key-value pairs in an encoded form. To // The Body contains all the key-value pairs
// obtain these in a useful form, you will need to use // in an encoded form. To obtain these in a
// UnpackAnimationStep or AnimationStepGetXXX. // useful form, use UnpackAnimationStep or the
// AnimationStepGetXXX functions.
// //
UPROPERTY() UPROPERTY()
TArray<uint8> Body; TArray<uint8> Body;
@@ -48,25 +50,26 @@ public:
// Auto-Execute // Auto-Execute
// //
// These functions automatically update certain actor // These functions automatically update certain
// properties: // actor properties:
// //
// AutoUpdateXYZ(AActor *actor); // uses 'xyz' keyword // AutoUpdateXYZ - uses 'xyz' keyword
// AutoUpdateFacing(AActor *actor); // uses 'facing' keyword. // AutoUpdateFacing - uses 'facing' keyword
// AutoUpdatePlane(FName *plane); // uses 'plane' keyword // AutoUpdatePlane - uses 'plane' keyword
// //
void AutoUpdateXYZ(AActor *actor) const; void AutoUpdateXYZ(AActor *actor) const;
void AutoUpdateFacing(AActor *actor) const; void AutoUpdateFacing(AActor *actor) const;
void AutoUpdatePlane(FName *plane) const; void AutoUpdatePlane(FName *plane) const;
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// This UClass is never instantiated. It exists to // UlxAnimationStepLibrary
// expose certain static functions to the blueprint
// library.
// //
//////////////////////////////////////////////// // Blueprint function library for reading and
// applying animation steps.
//
////////////////////////////////////////////////////////////
UCLASS() UCLASS()
class INTEGRATION_API UlxAnimationStepLibrary : public UBlueprintFunctionLibrary class INTEGRATION_API UlxAnimationStepLibrary : public UBlueprintFunctionLibrary
@@ -77,26 +80,23 @@ public:
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step") UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static FString AnimationStepDebugString(const FlxAnimationStep& step); static FString AnimationStepDebugString(const FlxAnimationStep& step);
// Stores the key-value pairs in properties of the target object. // Stores the key-value pairs in properties of the
// target object.
// //
// The animation step contains key-value pairs. The goal of this function // The prefix parameter is prepended to the property
// is to store these in properties of the target. The prefix parameter // names. For example, if the pairs are "color=blue,
// is prepended to the property names. // speed=20" and the prefix is "aq", then "aq Color" is
// set to "blue" and "aq Speed" is set to 20. A
// property "aq Animation Step" is also written,
// containing the entire animation step.
// //
// For example, suppose the key-value pairs are "color=blue, speed=20", // If a key has no corresponding property, it is
// and suppose the prefix is "aq". In that case, two properties would // silently ignored. If a property has no corresponding
// be written: "aq Color" would be set to "blue", and "aq Speed" would be // key, it is cleared.
// set to 20. In addition, a property "aq Animation Step" would
// be written, containing the entire animation step.
// //
// If the step contains a key-value pair, but there is no corresponding // Returns bChanged=true if the hash of the "aq
// property in the target, then the key-value pair is silently // Animation Step" property has changed. Returns the
// ignored. If the target contains properties that begin with the prefix, // Action string from action=xxx.
// but which don't have any corresponding key-value pair, those properties
// are cleared.
//
// Returns 'Changed' if the hash-value of the "aq Animation Step" property
// has changed. Returns 'Action' string from the action=xxx property.
// //
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = "Luprex|Animation Step") UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = "Luprex|Animation Step")
static void UnpackAnimationStep(bool &bChanged, FString &Action, const FlxAnimationStep& step, UObject* target, const FString& VariableNamePrefix = TEXT("aq")); static void UnpackAnimationStep(bool &bChanged, FString &Action, const FlxAnimationStep& step, UObject* target, const FString& VariableNamePrefix = TEXT("aq"));
@@ -125,27 +125,34 @@ 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; }
// Scan an animation step for key-value pairs of the form mat_XXXX={x,y,z}. // Scan an animation step for key-value pairs of the
// For each match, create a dynamic material instance on the actor's mesh // form mat_XXXX={x,y,z}. For each match, create a
// components and set the vector parameter XXXX. Materials are restored to // dynamic material instance on the actor's mesh
// their base (non-dynamic) state before applying, so parameters from // components and set the vector parameter XXXX.
// previous calls do not persist. // Materials are restored to their base (non-dynamic)
// state before applying, so parameters from previous
// calls do not persist.
// //
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);
// Look for a mesh=name key-value pair in the animation step. // Look for a mesh=name key-value pair. If found, load
// If found, load the named mesh and apply it to the actor's // the named mesh and apply it to the actor's mesh
// mesh component. The actor must have exactly one mesh component. // component. The actor must have exactly one mesh
// component.
// //
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step") UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step")
static void AnimationStepApplyMesh(const FlxAnimationStep& step, bool FallbackToBP, AActor* actor); static void AnimationStepApplyMesh(const FlxAnimationStep& step, bool FallbackToBP, AActor* actor);
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// FlxAnimationStepView
// //
//////////////////////////////////////////////// // A lightweight, non-owning view of an animation
// step (hash + body as a string_view).
//
////////////////////////////////////////////////////////////
struct FlxAnimationStepView { struct FlxAnimationStepView {
int64 Hash; int64 Hash;
@@ -155,19 +162,17 @@ struct FlxAnimationStepView {
FlxAnimationStepView(int64 h, std::string_view b) : Hash(h), Body(b) {} FlxAnimationStepView(int64 h, std::string_view b) : Hash(h), Body(b) {}
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// A single animation field. // FlxAnimationField
// //
// A field consists of a variable name, // A single field from an animation step: a variable name, a
// a persistent flag, a type, and some fields // persistent flag, a type, and value storage.
// to hold the values.
// //
// If the value is boolean, it is stored in // Boolean values are stored in X as 1 or 0. Double values
// X, as either 1 or 0. If the value is double, // are stored in X.
// it is stored in X.
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
struct FlxAnimationField { struct FlxAnimationField {
std::string_view Name; std::string_view Name;
@@ -177,28 +182,27 @@ struct FlxAnimationField {
std::string_view S; std::string_view S;
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// An Animation Queue Decoder. // FlxAnimQueueDecoder
// //
// This acts a lot like a stream reader, // Stream reader for animation queues. Reads one
// it reads one AnimEntry at a time from // FlxAnimationStepView at a time until EOF.
// the animation queue until you reach
// 'end-of-file'.
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class FlxAnimQueueDecoder { class FlxAnimQueueDecoder {
private: private:
FlxStreamBuffer Decoder; FlxStreamBuffer Decoder;
// These values are immediately read from the header. // Read from the header immediately on
// construction.
// //
int SizeLimit; int SizeLimit;
int ActualSize; int ActualSize;
public: public:
// Initialize the FlxAnimQueueDecoder with the encoded animation queue. // Initialize with an encoded animation queue.
// //
FlxAnimQueueDecoder(std::string_view s); FlxAnimQueueDecoder(std::string_view s);
@@ -206,11 +210,11 @@ public:
// //
int GetSizeLimit() const { return SizeLimit; } int GetSizeLimit() const { return SizeLimit; }
// Get the Actual Size of the animation queue. // Get the actual size of the animation queue.
// //
int GetActualSize() const { return ActualSize; } int GetActualSize() const { return ActualSize; }
// Return true if the parser has reached the end of the string. // Return true if the parser has reached EOF.
// //
bool AtEOF() { return Decoder.empty(); } bool AtEOF() { return Decoder.empty(); }
@@ -218,7 +222,7 @@ public:
// //
FlxAnimationStepView ReadStep(); FlxAnimationStepView ReadStep();
// Peek at the hash of the next animation step. // Peek at the hash of the next step.
// //
int64 PeekHash(); int64 PeekHash();
@@ -227,27 +231,25 @@ public:
// static FString DebugString(std::string_view s); // static FString DebugString(std::string_view s);
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// An Animation Step Decoder. // FlxAnimationStepDecoder
// //
// This acts a lot like a stream reader, // Stream reader for a single animation step. Reads one
// it reads one FlxAnimationField at a time from // FlxAnimationField at a time until EOF.
// the animation queue until you reach
// 'end-of-file'.
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class FlxAnimationStepDecoder { class FlxAnimationStepDecoder {
private: private:
FlxStreamBuffer Decoder; FlxStreamBuffer Decoder;
public: public:
// Initialize the FlxAnimationStepDecoder from the FlxAnimationStepView. // Initialize from an encoded step body.
// //
FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {} FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {}
// Return true if the parser has reached the end of the string. // Return true if the parser has reached EOF.
// //
bool AtEOF() { return Decoder.empty(); } bool AtEOF() { return Decoder.empty(); }
@@ -255,28 +257,25 @@ public:
// //
FlxAnimationField ReadField(); FlxAnimationField ReadField();
// Convert an AnimStep to an FString. // Convert an animation step to a debug string.
// //
static FString DebugString(bool finished, int64 hash, std::string_view body); static FString DebugString(bool finished, int64 hash, std::string_view body);
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// FlxAnimTracker // FlxAnimTracker
// //
// This class monitors the animation queue for a single // Monitors the animation queue for a single tangible.
// tangible. It can identify when a new animation has // Identifies when animations appear or are removed, and
// appeared on the animation queue, and when animations have // tracks which ones have been marked as finished.
// been removed from the animation queue. It also
// keeps track of which animations have been started.
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class FlxAnimTracker { class FlxAnimTracker {
public: public:
// Our own copy of the animation queue. We only // Our copy of the animation queue. The first element
// store the hashes, not the steps. The First element // is the oldest item.
// of the queue is the oldest item.
// //
TArray<FlxAnimationStep> AQ; TArray<FlxAnimationStep> AQ;
@@ -285,57 +284,48 @@ public:
bool Changed; bool Changed;
public: public:
// Construct a tracker. // Construct a tracker in the empty (Clear) state.
//
// Initially, the tracker is in the empty (Clear) state.
// //
FlxAnimTracker(); FlxAnimTracker();
// Clear everything, reset to the initial state. // Clear everything, reset to initial state.
// //
void Clear(); void Clear();
// Update from the specified animation queue. // Update from the specified animation queue. After the
// // update, AQ will be a copy of the queue that was
// After the update is done, AQ will be a copy // passed in.
// of the animation queue that is passed in.
// //
void Update(std::string_view encqueue); void Update(std::string_view encqueue);
// Get the current blueprint name, as a string. // Get the current blueprint name.
// //
FString GetCurrentBlueprintName(); FString GetCurrentBlueprintName();
// Get the current animation step. // Get the current animation step. This is the step
// // that the blueprint should currently be playing.
// Get the current animation step. This is the step that the
// blueprint should currently be playing.
// //
FlxAnimationStep GetCurrentAnimation(); FlxAnimationStep GetCurrentAnimation();
// Declare that an animation is finished. // Declare that an animation is finished. The blueprint
// // calls this to indicate that it is done playing the
// The blueprint uses this function call to indicate that it // specified animation. This causes GetCurrentAnimation
// is done playing the specified animation. This will cause the // to advance to the next step.
// animation to be marked as finished, which in turn causes
// 'GetCurrentStep' to advance to the next animation.
// //
void FinishedAnimation(int64 Hash); void FinishedAnimation(int64 Hash);
// Return true if an animation step is marked finished. // Return true if an animation step is marked finished.
// // Also returns true if the step is not found.
// Also return true if the animation step is not found.
// //
bool IsFinished(int64 Hash); bool IsFinished(int64 Hash);
// Skip to the end of the animation queue. // Skip to the end of the animation queue. Equivalent to
// // calling FinishedAnimation on every animation in the
// This is equivalent to calling 'FinishedHash' on every // queue.
// animation in the entire queue.
// //
void SkipToEnd(); void SkipToEnd();
// Get all the hashes of all the animation steps. // Get the hashes of all animation steps.
// //
TArray<int64> GetHashes(); TArray<int64> GetHashes();
@@ -347,24 +337,25 @@ public:
// //
const FlxAnimationStep *LastFinished() const; const FlxAnimationStep *LastFinished() const;
// Return the first animation with the specified hash. // Return the first animation with the
// specified hash.
// //
const FlxAnimationStep *FindAnimation(int64 hash) const; const FlxAnimationStep *FindAnimation(int64 hash) const;
// Clear the 'Changed' flag. // Clear the Changed flag.
// //
void ClearChanged() { Changed = false; } void ClearChanged() { Changed = false; }
// Get the 'Changed' flag. // Get the Changed flag.
// //
// The changed flag is set to true whenever the Luprex animation // Set to true whenever the animation queue changes, or
// queue changes from its previous state. The changed flag is also // when FinishedAnimation marks a step. Only cleared by
// set to true whenever 'SetFinished' marks an animation as finished. // ClearChanged.
// The changed flag can only be set to false by 'ClearChanged,' above.
// //
bool IsChanged() const { return Changed; } bool IsChanged() const { return Changed; }
// Return a debug string for the entire animation tracker. // Return a debug string for the entire animation
// tracker.
// //
FString DebugString() const; FString DebugString() const;
}; };

View File

@@ -1,3 +1,14 @@
////////////////////////////////////////////////////////////
//
// AssetLookup.h
//
// Provides asset loading by short name. At
// initialization, scans asset directories and builds
// a lookup table mapping (class, short name) pairs
// to full asset paths. Blueprint-callable functions
// let blueprints load assets by short name.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
@@ -14,20 +25,18 @@ class UStaticMesh;
class USkeletalMesh; class USkeletalMesh;
class UAnimSequence; class UAnimSequence;
////////////////////////////////////////////////////////////
//
// UlxAssetLookup
//
////////////////////////////////////////////////////////////
UCLASS(MinimalAPI) UCLASS(MinimalAPI)
class UlxAssetLookup : public UObject class UlxAssetLookup : public UObject
{ {
GENERATED_BODY() GENERATED_BODY()
private: private:
//
// At initialization time, we scan the asset directories
// to see what assets are present. These maps store the
// result of the scan. Each entry in the map contains a
// classname, a short name, and a path:
//
// <UAnimSequence, Jump> -> "/Game/AnimSequences/SEQ_Jump"
//
TMap<TTuple<FString, FName>, FString> AssetPaths; TMap<TTuple<FString, FName>, FString> AssetPaths;
private: private:
@@ -39,37 +48,43 @@ private:
public: public:
void RebuildIndex(); void RebuildIndex();
// Get a static mesh by name // Get a static 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 LoadStaticMeshAsset( static ElxValidOrNotValid LoadStaticMeshAsset(
UStaticMesh *&Result, UStaticMesh *&Result,
const UObject *Context, const FString &Name, bool ErrorIfNotFound = false); 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, bool ErrorIfNotFound = false); 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, bool ErrorIfNotFound = false); 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, bool ErrorIfNotFound = false); 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, bool ErrorIfNotFound = false); 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,

View File

@@ -56,25 +56,25 @@
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxBreakToDebuggerThreshold : uint8 { enum class ElxBreakToDebuggerThreshold : uint8 {
/* Break on errors. */ /** Break on errors. */
Error, Error,
/* Break on warnings and above. */ /** Break on warnings and above. */
Warning, Warning,
/* Break on display messages and above. */ /** Break on display messages and above. */
Display, Display,
/* Break on log messages and above. */ /** Break on log messages and above. */
Log, Log,
/* Break on verbose messages and above. */ /** Break on verbose messages and above. */
Verbose, Verbose,
/* Break on all messages. */ /** Break on all messages. */
VeryVerbose, VeryVerbose,
/* Break on fatal errors only (ie, never break -- the process crashes instead). */ /** Break on fatal errors only (ie, never break -- the process crashes instead). */
Fatal, Fatal,
}; };

View File

@@ -1,37 +1,50 @@
////////////////////////////////////////////////////////////
//
// Common.h
//
// Simple data types used throughout the Unreal
// interface to Luprex: type aliases, blueprint
// enums for branching, and log categories.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
#include <string_view> #include <string_view>
#include "Common.generated.h" #include "Common.generated.h"
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// A bunch of simple data types that are used throughout the // LpxCommonTypes
// unreal interface to Luprex.
// //
///////////////////////////////////////////////////////////////// // Type aliases used throughout the integration.
//
////////////////////////////////////////////////////////////
namespace LpxCommonTypes { namespace LpxCommonTypes {
// Array of tangible IDs. // Array of tangible IDs.
//
using IdArray = TArray<int64>; using IdArray = TArray<int64>;
// View of Array of tangible IDs. // View of Array of tangible IDs.
//
using IdView = TArrayView<const int64>; using IdView = TArrayView<const int64>;
// Array of std::string_view // Array of std::string_view.
//
using StringViewVec = TArray<std::string_view>; using StringViewVec = TArray<std::string_view>;
} }
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// Luprex exports a header-only library called "base-buffer.hpp", // ElxLuaValueType
// which includes a "struct LuaValueHolder" which contains a tag
// field of type "enum LuaValueType." The following enum is a
// direct copy of that enum, and the values must match one-for-one.
// Note that "token" has been renamed to "name", those are
// synonymous.
// //
///////////////////////////////////////////////////////////////// // Mirror of LuaValueType from base-buffer.hpp.
// Values must match one-for-one. Note that "token"
// has been renamed to "name" (synonymous).
//
////////////////////////////////////////////////////////////
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxLuaValueType : uint8 { enum class ElxLuaValueType : uint8 {
@@ -43,13 +56,14 @@ enum class ElxLuaValueType : uint8 {
Vector Vector
}; };
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// A variety of boolean-like results that can be conveniently // Branching Enums
// be used in conjunction with 'ExpandEnumAsExecs' to create
// branching functions.
// //
///////////////////////////////////////////////////////////////// // Boolean-like results used with ExpandEnumAsExecs
// to create branching blueprint functions.
//
////////////////////////////////////////////////////////////
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxSuccessOrError : uint8 { enum class ElxSuccessOrError : uint8 {
@@ -81,16 +95,16 @@ enum class ElxSuccessOrWrongType : uint8 {
WrongType, WrongType,
}; };
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// Two log categories that are used throughout the Unreal // Log Categories
// Luprex integration.
// //
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Messages from inside the Luprex Core.
// Messages that come from inside the Luprex Core. //
DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Display, All); DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Display, All);
// Messages that pertain to our Luprex integration with Unreal. // Messages about the Luprex integration with Unreal.
//
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All); DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All);

View File

@@ -1,25 +1,16 @@
////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// ConsoleOutput // ConsoleOutput.h
// //
// This class can optionally be used by the GameMode // Optional helper for the console window. The
// blueprint to help implement the console window. There is // GameMode blueprint can use this class to store
// no requirement that the blueprint use this class, it can // console text as one big string with newlines.
// implement the console window any way it wants, this is
// just here in case it is desired.
// //
// This class stores the text that's in the unreal console. // A dirty bit is set whenever text is appended,
// It stores it as one great big string, which contains // so the blueprint only needs to update the widget
// newlines to denote line breaks. // when the text has actually changed.
// //
// This class also contains a 'dirty' bit. Each time ////////////////////////////////////////////////////////////
// somebody appends a line of text to the console, the dirty
// bit is automatically set. The bit can be checked using
// 'IsDirty' and cleared using 'ClearDirty'. This makes it
// so that you don't have to update the unreal widget unless
// the text has actually changed.
//
//////////////////////////////////////////////////////////////
#pragma once #pragma once
@@ -27,6 +18,11 @@
#include "ConsoleOutput.generated.h" #include "ConsoleOutput.generated.h"
////////////////////////////////////////////////////////////
//
// UlxConsoleOutput
//
////////////////////////////////////////////////////////////
UCLASS(BlueprintType) UCLASS(BlueprintType)
class UlxConsoleOutput : public UObject class UlxConsoleOutput : public UObject
@@ -38,36 +34,46 @@ private:
bool Dirty; bool Dirty;
private: private:
// Truncate the console to a reasonable number of // Truncate the console to a reasonable number of lines.
// lines. The length is hardwired. // The length is hardwired.
//
void Truncate(); void Truncate();
// Add a newline if there isn't one. Returns true if it changed anything. // Add a newline if there isn't one.
//
// Returns true if it changed anything.
//
bool MaybeAppendNewline(); bool MaybeAppendNewline();
// Append text. Returns true if it changed anything. // Append text.
//
// Returns true if it changed anything.
//
bool MaybeAppendText(const FString& text); bool MaybeAppendText(const FString& text);
public: public:
// Append a line of text to the console. // Append text to the console.
//
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void Append(const FString& text); void Append(const FString& text);
// Append a line of text to the console on a line by itself. // Append text on a line by itself.
//
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void AppendLine(const FString& text); void AppendLine(const FString& text);
// Get the console text as a string. // Get the console text as a string.
//
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
const FString& Get() const { return Content; } const FString& Get() const { return Content; }
// Return if the dirty flag is set. // Return if the dirty flag is set.
//
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
bool IsDirty() const { return Dirty; } bool IsDirty() const { return Dirty; }
// Clear the dirty flag. // Clear the dirty flag.
//
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void ClearDirty() { Dirty = false; } void ClearDirty() { Dirty = false; }
}; };

View File

@@ -1,7 +1,12 @@
////////////////////////////////////////////////////////////
// //
// FormatDataLibrary: Functions that convert data into FFormatArgumentData // FormatDataLibrary.h
// structs, so that the data can be passed to FText::Format.
// //
// Functions that convert data into
// FFormatArgumentData structs, so that the data
// can be passed to FText::Format.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
@@ -18,17 +23,18 @@ class UlxLuaValues;
struct FlxAnimationStep; struct FlxAnimationStep;
struct FlxMovementComponentState; struct FlxMovementComponentState;
/* ////////////////////////////////////////////////////////////
* A library that contains functions that convert data into FFormatArgumentData //
* structs, so that the data can be passed to FTextFormatter::Format. // UlxFormatDataLibrary
* //
* The FormatLogMessage K2Node scans this library using reflection, // The FormatLogMessage K2Node scans this library using
* looking for functions that have a parameter named "AutoConvertedValue". // reflection, looking for functions that have a parameter
* It uses the type of that parameter to determine which function to // named "AutoConvertedValue". It uses the type of that
* call for a given pin type. Functions without an "AutoConvertedValue" // parameter to determine which function to call for a given
* parameter are ignored by the reflection scan. // pin type.
* //
*/ ////////////////////////////////////////////////////////////
UCLASS(MinimalAPI) UCLASS(MinimalAPI)
class UlxFormatDataLibrary : public UBlueprintFunctionLibrary class UlxFormatDataLibrary : public UBlueprintFunctionLibrary
{ {
@@ -92,12 +98,12 @@ public:
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility")
static FFormatArgumentData FormatArgumentDataMovementComponentState(const FlxMovementComponentState &AutoConvertedValue, const FString &Name); static FFormatArgumentData FormatArgumentDataMovementComponentState(const FlxMovementComponentState &AutoConvertedValue, const FString &Name);
// A formatting routine for pins that were never connected. // For pins that were never connected.
// //
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility")
static FFormatArgumentData FormatArgumentDataBlank(const FString &Name); static FFormatArgumentData FormatArgumentDataBlank(const FString &Name);
// A specialized formatting routine for pins of enum types. // For pins of enum types.
// //
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility")
static FFormatArgumentData FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject); static FFormatArgumentData FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject);

View File

@@ -1,4 +1,15 @@
// Copyright Epic Games, Inc. All Rights Reserved. ////////////////////////////////////////////////////////////
//
// FormatMessage.h
//
// Two K2Nodes: FormatMessage and FormatLogMessage.
// FormatMessage outputs a formatted string as a pin.
// FormatLogMessage outputs it to the log instead.
//
// FormatLogMessage is a derived class that just sets
// a flag to alter the base class behavior.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
@@ -17,45 +28,49 @@
#include "FormatMessage.generated.h" #include "FormatMessage.generated.h"
/** Format Log Verbosity: controls how a message from the "Format Log Message" ////////////////////////////////////////////////////////////
* K2Node gets written to the log. //
* // ElxFormatLogVerbosity
* 'Fatal' is deliberately placed at the end so that the editor defaults to //
* 'Error' (value 0) when the dropdown is uninitialized. This means the // Controls the ELogVerbosity of the UE_LOG directive inside
* numeric values don't match ELogVerbosity, so a conversion function is needed. // FormatLogMessage. Also controls the throttling of log
* // messages.
* ThrottledDisplay and ThrottledLog behave like Display and Log respectively, //
* but suppress repeated messages with the same format pattern, logging at most // Fatal is deliberately placed at the end so that the
* once per second. // editor defaults to Error (value 0) when the dropdown is
*/ // uninitialized. The numeric values don't match
// ELogVerbosity, so a conversion function is needed.
//
////////////////////////////////////////////////////////////
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxFormatLogVerbosity : uint8 { enum class ElxFormatLogVerbosity : uint8 {
/* Prints an error to the console and log file. The editor collects and reports errors. */ /** Prints an error to the console and log file. The editor collects and reports errors. */
Error, Error,
/* Prints a warning to the console and log file. The editor collects and report warnings. */ /** Prints a warning to the console and log file. The editor collects and reports warnings. */
Warning, Warning,
/* Prints a message to the console and log file. */ /** Prints a message to the console and log file. */
Display, Display,
/* Prints a message to the log file, however, it does not print to the console. */ /** Prints a message to the log file, but not to the console. */
Log, Log,
/* Like Display, but suppresses repeated messages with the same format pattern (at most once per second). */ /** Like Display, but suppresses repeated messages with the same format pattern (at most once per second). */
ThrottledDisplay, ThrottledDisplay,
/* Like Log, but suppresses repeated messages with the same format pattern (at most once per second). */ /** Like Log, but suppresses repeated messages with the same format pattern (at most once per second). */
ThrottledLog, ThrottledLog,
/* Prints a message to a log file only if Verbose logging is enabled for the given category. This is usually used for detailed logging. */ /** Prints a message to the log file only if Verbose logging is enabled for the given category. */
Verbose, Verbose,
/* Prints a message to a log file. If VeryVerbose logging is enabled, then this is used for detailed logging that would otherwise spam output. */ /** Prints a message to the log file only if VeryVerbose logging is enabled. */
VeryVerbose, VeryVerbose,
/* Danger! Prints a fatal error to the console and log file, then crashes (this crashes the editor too). */ /** Prints a fatal error to the console and log file, then crashes (this crashes the editor too). */
Fatal, Fatal,
}; };
@@ -64,19 +79,12 @@ class FString;
class UEdGraph; class UEdGraph;
class UObject; class UObject;
////////////////////////////////////////////////////////////
// //
// FormatMessage and FormatErrorMessage // UK2Node_FormatMessage
//
// This file defines two K2Nodes: FormatMessage, and FormatErrorMessage. The
// only difference between them is that the former outputs the message as an
// output pin. The latter outputs the message to the log instead.
//
// To implement code reuse, we put all the code into FormatMessage, and made
// FormatErrorMessage a derived class of FormatMessage. The derived class
// doesn't override anything - all it does is set a flag, the flag changes
// the behavior of FormatMessage.
//
// //
////////////////////////////////////////////////////////////
UCLASS(MinimalAPI) UCLASS(MinimalAPI)
class UK2Node_FormatMessage : public UK2Node class UK2Node_FormatMessage : public UK2Node
{ {
@@ -110,17 +118,24 @@ class UK2Node_FormatMessage : public UK2Node
//~ End UK2Node Interface. //~ End UK2Node Interface.
protected: protected:
/** Create all necessary pins */ // Create all necessary pins.
//
void CreateCorrectPins(); void CreateCorrectPins();
/** Synchronize the type of the given argument pin with the type its connected to, or reset it to a wildcard pin if there's no connection */ // Synchronize the type of the given argument pin
// with the type its connected to, or reset it to
// a wildcard pin if there's no connection.
//
void SynchronizeArgumentPinType(UEdGraphPin* Pin); void SynchronizeArgumentPinType(UEdGraphPin* Pin);
/** Our derived class will set this to true, altering the behavior of this K2Node. **/ // Derived class sets this to true, altering
// the behavior of this K2Node.
//
virtual bool IsFormatErrorMessage() const { return false; } virtual bool IsFormatErrorMessage() const { return false; }
// When IsFormatErrorMessage is true, the K2Node macroexpands to call this // When IsFormatErrorMessage is true, the K2Node
// function, which formats the message and outputs it to the log. // macroexpands to call this function, which
// formats the message and outputs it to the log.
// //
UFUNCTION(BlueprintCallable, meta=(WorldContext = "Context", BlueprintInternalUseOnly = "true")) UFUNCTION(BlueprintCallable, meta=(WorldContext = "Context", BlueprintInternalUseOnly = "true"))
static void FormatLogMessageInternal(UObject *Context, ElxFormatLogVerbosity Verbosity, const FString &InPattern, TArray<FFormatArgumentData> InArgs); static void FormatLogMessageInternal(UObject *Context, ElxFormatLogVerbosity Verbosity, const FString &InPattern, TArray<FFormatArgumentData> InArgs);
@@ -129,26 +144,31 @@ private:
static ELogVerbosity::Type ConvertElxFormatLogVerbosity(ElxFormatLogVerbosity Verbosity); static ELogVerbosity::Type ConvertElxFormatLogVerbosity(ElxFormatLogVerbosity Verbosity);
protected: protected:
/** When adding arguments to the node, their names are placed here and are generated as pins during construction */ // Argument names added to the node, generated as pins
// during construction.
//
UPROPERTY() UPROPERTY()
TArray<FString> PinNames; TArray<FString> PinNames;
/** Tooltip text for this node. */ // Tooltip text for this node.
//
FText NodeTooltip; FText NodeTooltip;
}; };
////////////////////////////////////////////////////////////
//
// UK2Node_FormatLogMessage
//
// Derives from FormatMessage. Sets a flag to make
// the base class output to the log instead of to
// a pin.
//
////////////////////////////////////////////////////////////
//
// This derives from FormatMessage.
//
UCLASS(MinimalAPI) UCLASS(MinimalAPI)
class UK2Node_FormatLogMessage : public UK2Node_FormatMessage class UK2Node_FormatLogMessage : public UK2Node_FormatMessage
{ {
GENERATED_UCLASS_BODY() GENERATED_UCLASS_BODY()
// Setting this flag alters the behavior of FormatMessage, making it
// output to the log instead of to a pin.
//
virtual bool IsFormatErrorMessage() const override { return true; } virtual bool IsFormatErrorMessage() const override { return true; }
}; };

View File

@@ -1,25 +1,34 @@
////////////////////////////////////////////////////////////
//
// LockedWrapper.h
//
// Mutex-guarded access to the EngineWrapper.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "lpx-enginewrapper.hpp" #include "lpx-enginewrapper.hpp"
#include "Common.h" #include "Common.h"
////////////////////////////////////////////////////////////
// Class FlxLockableWrapper //
// FlxLockableWrapper
// //
// Contains the EngineWrapper and a Mutex to lock it. // Contains the EngineWrapper and a Mutex to lock it.
// This class has no methods. To access the EngineWrapper, // This class has no methods. To access the
// construct a FlxLockedWrapper, and then dereference it // EngineWrapper, construct a FlxLockedWrapper.
// using operator right arrow.
// //
////////////////////////////////////////////////////////////
class FlxLockableWrapper { class FlxLockableWrapper {
private: private:
FCriticalSection Mutex; FCriticalSection Mutex;
EngineWrapper Wrapper; EngineWrapper Wrapper;
// Temporary buffers. These are only used // Temporary buffers used only inside wrapper
// inside wrapper methods. There's nothing // methods. Nothing persistent in these.
// persistent in these.
// //
TArray<uint32> AQLenBuffer; TArray<uint32> AQLenBuffer;
TArray<const char*> AQStrBuffer; TArray<const char*> AQStrBuffer;
@@ -28,50 +37,63 @@ public:
friend class FlxLockedWrapper; friend class FlxLockedWrapper;
}; };
////////////////////////////////////////////////////////////
//
// FlxLockedWrapper
//
// RAII lock guard. The constructor claims the mutex,
// the destructor releases it. Use operator-> to
// access the EngineWrapper.
//
////////////////////////////////////////////////////////////
class FlxLockedWrapper { class FlxLockedWrapper {
private: private:
FlxLockableWrapper& Lockable; FlxLockableWrapper& Lockable;
// This function is called by luprex to output debugging // Called by luprex to output debugging messages.
// messages. It is a thin wrapper around UE_LOG. // A thin wrapper around UE_LOG.
// //
static void DPrintHook(const char *Msg, size_t Size); static void DPrintHook(const char *Msg, size_t Size);
public: public:
// Import these types into our Namespace. // Import these types into our namespace.
//
using IdArray = LpxCommonTypes::IdArray; using IdArray = LpxCommonTypes::IdArray;
using IdView = LpxCommonTypes::IdView; using IdView = LpxCommonTypes::IdView;
using StringViewVec = LpxCommonTypes::StringViewVec; using StringViewVec = LpxCommonTypes::StringViewVec;
public: public:
// The constructor of the FlxLockedWrapper claims the mutex. // The constructor claims the mutex.
//
FlxLockedWrapper(FlxLockableWrapper& w) : Lockable(w) { FlxLockedWrapper(FlxLockableWrapper& w) : Lockable(w) {
Lockable.Mutex.Lock(); Lockable.Mutex.Lock();
} }
// The destructor of the FlxLockedWrapper releases the mutex. // The destructor releases the mutex.
//
~FlxLockedWrapper() { ~FlxLockedWrapper() {
Lockable.Mutex.Unlock(); Lockable.Mutex.Unlock();
} }
// Operator right arrow accesses the EngineWrapper. // Operator-> accesses the EngineWrapper.
//
EngineWrapper* operator ->() { EngineWrapper* operator ->() {
return &Lockable.Wrapper; return &Lockable.Wrapper;
} }
// Get a pointer to the enginewrapper. This is not // Get a pointer to the EngineWrapper. Not very
// very safe because you could keep the pointer after // safe because you could keep the pointer after
// the LockedWrapper is destroyed. Don't do that. // the LockedWrapper is destroyed. Don't do that.
//
EngineWrapper* Get() { EngineWrapper* Get() {
return &Lockable.Wrapper; return &Lockable.Wrapper;
} }
// Initialize the engine wrapper if it's not already. // Initialize the engine wrapper if it's not
// // already. All this does is open the DLL and
// All this does is open the DLL and hook up all // hook up all the function pointers in the
// the function pointers in the wrapper to point into // wrapper to point into the DLL.
// the DLL.
// //
void InitWrapper(); void InitWrapper();
@@ -85,9 +107,9 @@ public:
// Get the list of tangibles near the actor. // Get the list of tangibles near the actor.
// //
// This function is fast but not free. You should fetch this // This function is fast but not free. You should
// once per frame and then store the IdView somewhere (like // fetch this once per frame and then store the
// in the TangibleManager, for example). // IdView somewhere (like in the TangibleManager).
// //
IdView GetNear(int64 id, double rx, double ry, double rz); IdView GetNear(int64 id, double rx, double ry, double rz);

View File

@@ -1,3 +1,17 @@
////////////////////////////////////////////////////////////
//
// LuaCall.h
//
// Low-level functions for calling Lua from blueprints.
// The "Call Lua" K2Node macroexpands into sequences
// of these functions.
//
// Also contains UlxLuaValues, which stores return
// values from Lua calls, and FlxParsedProto, which
// parses Lua function prototype strings.
//
////////////////////////////////////////////////////////////
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
@@ -9,14 +23,20 @@
class UlxLuaValues; class UlxLuaValues;
// Classify lua code syntactically: ////////////////////////////////////////////////////////////
// //
// SlashCommand: starts with a slash, therefore, not lua // ElxLuaSyntaxCheck
// WhitespaceOnly: the input only contains whitespace
// ValidSyntax: the input is valid lua code
// TruncatedCode: the input is truncated
// InvalidSyntax: invalid lua
// //
// Classifies console commands syntactically:
//
// SlashCommand: starts with a slash, not lua
// Whitespace: the input only contains whitespace
// ValidLua: the input is valid lua code
// TruncatedLua: the input is truncated
// InvalidLua: invalid lua
//
////////////////////////////////////////////////////////////
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxLuaSyntaxCheck : uint8 { enum class ElxLuaSyntaxCheck : uint8 {
SlashCommand, SlashCommand,
@@ -26,29 +46,20 @@ enum class ElxLuaSyntaxCheck : uint8 {
InvalidLua, InvalidLua,
}; };
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// These are the types that can actually be packed into // FlxParsedProto
// a serialized buffer.
// //
///////////////////////////////////////////////////////////////// // The first argument to LuaCallNode is a function
// prototype of the form:
/////////////////////////////////////////////////////////////////
// //
// This is a little parser that parses Lua function 'prototypes'. // class.name(int arg1, int arg2) : int ret1
// The prototypes look like this:
// //
// class.name(int arg1, int arg2) : int ret1, int ret2 // Return values can be omitted. The last return
// value can be an ellipsis. The class name can be
// asterisk.
// //
// The return values can be omitted if the function has no return ////////////////////////////////////////////////////////////
// values. Optionally, there can be one last return value which
// is just an ellipsis. The class name can be asterisk.
//
// For more information about the meaning of all this, see the docs
// for the 'Call Lua' blueprint node.
//
/////////////////////////////////////////////////////////////////
class FlxParsedProto class FlxParsedProto
{ {
@@ -60,21 +71,33 @@ public:
Pin(const FString &T, const FString &N) : Type(T), Name(N) {} Pin(const FString &T, const FString &N) : Type(T), Name(N) {}
}; };
// If parsing generated an error, the error
// message is stored here.
//
FString ErrorMessage; FString ErrorMessage;
TArray<FString> Tokens;
int NextToken; // The results of parsing the prototype.
//
FString ClassName; FString ClassName;
FString FunctionName; FString FunctionName;
TArray<Pin> Arguments; TArray<Pin> Arguments;
TArray<Pin> ReturnValues; TArray<Pin> ReturnValues;
bool ExtraReturnValues; bool ExtraReturnValues;
// Used internally to help generate the error
// message.
//
TArray<FString> Tokens;
int NextToken;
private: private:
// Check the next token to see if it's exactly equal to text. // Check the next token to see if it's exactly
// equal to text.
// //
bool IsLiteral(const TCHAR *text); bool IsLiteral(const TCHAR *text);
// Check the next token to see if it's an identifier. // Check the next token to see if it's an
// identifier.
// //
bool IsIdent(); bool IsIdent();
@@ -96,26 +119,24 @@ public:
FlxParsedProto(const FString &str) { Parse(str); } FlxParsedProto(const FString &str) { Parse(str); }
}; };
///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// To make a Lua Call from inside of a blueprint, use the convenient "Call Lua" // UlxLuaCallLibrary
// blueprint node. This node macroexpands into a sequence of low-level
// function calls. This library contains the low-level functions that
// "Call Lua" macroexpands into.
// //
// The procedure for making a lua call using the low-level functions is as follows: // Low-level functions that LuaCallNode macroexpands
// into. Every LuaCallNode expands into the following
// sequence of functions:
// //
// * Use LuaCallBegin to put the class name and function name into the argument buffer. // * LuaCallBegin to set class/function name.
// * Use LuaCallArgumentXXX to put arguments into the argument buffer. // * LuaCallArgument_XXX to pack arguments.
// * Use LuaCallInvoke or LuaCallProbe to actually make the call. // * LuaCallInvoke or LuaCallProbe to call.
// * Use LuaCallReturnValueXXX to fetch return values from the return buffer. // * LuaCallReturnValue_XXX to fetch results.
// //
// The two buffers are basically global variables, they are part of the // The buffers used by these functions are global
// LuprexGameModeBase. This is okay because blueprint is single-threaded. // variables in LuprexGameModeBase. It is ok to use
// globals, because blueprint is single-threaded.
// //
// The following three libraries contain all the low-level functions. ////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////
UCLASS() UCLASS()
class INTEGRATION_API UlxLuaCallLibrary : public UObject class INTEGRATION_API UlxLuaCallLibrary : public UObject
@@ -123,25 +144,36 @@ class INTEGRATION_API UlxLuaCallLibrary : public UObject
GENERATED_BODY() GENERATED_BODY()
public: public:
// Get an argument packing function or a return value unpacking function. // Get an argument packing function or a return
// value unpacking function.
// //
static UFunction *GetArgumentPacker(const FString &Type); static UFunction *GetArgumentPacker(const FString &Type);
static UFunction *GetReturnValueUnpacker(const FString &Type); static UFunction *GetReturnValueUnpacker(const FString &Type);
// Get the types supported for arguments and return values, as a documentation string. // Get the types supported for arguments and
// return values, as a documentation string.
// //
static FString AllFunctionsWithPrefix(const TCHAR *Prefix); static FString AllFunctionsWithPrefix(const TCHAR *Prefix);
static FString AllKnownArgumentTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallArgument_")); } static FString AllKnownArgumentTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallArgument_")); }
static FString AllKnownReturnValueTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallReturnValue_")); } static FString AllKnownReturnValueTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallReturnValue_")); }
public: public:
// Syntactically validate lua code. Parses the code and // Syntactically validate lua code. Parses the
// returns an error message. If the code is error-free, the // code and returns an error message. If the code
// error message is the empty string. // is error-free, the error message is empty.
//
// TODO: This doesn't belong here. This library
// is for LuaCallNode's internal implementation.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code); static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code);
////////////////////////////////////////////////////////
//
// Functions that initiate and complete the lua call.
//
////////////////////////////////////////////////////////
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void InvokeLuaExpr(UObject *context, const FString &Code); static void InvokeLuaExpr(UObject *context, const FString &Code);
@@ -154,9 +186,11 @@ public:
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", ExpandBoolAsExecs="ReturnValue", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", ExpandBoolAsExecs="ReturnValue", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
static bool LuaCallProbe(UObject *context, AActor *Place, UlxLuaValues *&ReturnArray); static bool LuaCallProbe(UObject *context, AActor *Place, UlxLuaValues *&ReturnArray);
////////////////////////////////////////////////////////
// //
// Functions that pack arguments into the call buffer. // Functions that pack arguments into the call buffer.
// //
////////////////////////////////////////////////////////
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
static void LuaCallArgument_string(UObject *context, const FString &Value); static void LuaCallArgument_string(UObject *context, const FString &Value);
@@ -180,14 +214,15 @@ public:
static void LuaCallArgument_boolean(UObject *context, bool Value); static void LuaCallArgument_boolean(UObject *context, bool Value);
}; };
////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// //
// This class stores an array of values that were returned by Lua. // UlxLuaValues
// //
///////////////////////////////////////////////////////////////// // Stores an array of values returned by Lua.
// Provides a cursor-based API for reading values
// one at a time with type checking.
//
////////////////////////////////////////////////////////////
UCLASS(BlueprintType) UCLASS(BlueprintType)
class INTEGRATION_API UlxLuaValues : public UObject class INTEGRATION_API UlxLuaValues : public UObject
@@ -203,7 +238,8 @@ private:
// //
TArray<ElxLuaValueType> Types; TArray<ElxLuaValueType> Types;
// For each chunk, a pointer to the serialized data. // For each chunk, a pointer to the serialized
// data.
// //
TArray<std::string_view> Data; TArray<std::string_view> Data;
@@ -216,15 +252,17 @@ private:
// //
void Empty(); void Empty();
// Compare two types. If they aren't equal, possibly log an error, and return a status code. // Compare two types. If they aren't equal,
// possibly log an error, and return a status
// code.
// //
static ElxSuccessOrWrongType CheckType(bool LogErrorOnWrongType, ElxLuaValueType Type, ElxLuaValueType Desired); static ElxSuccessOrWrongType CheckType(bool LogErrorOnWrongType, ElxLuaValueType Type, ElxLuaValueType Desired);
public: public:
UlxLuaValues() { Cursor = 0; } UlxLuaValues() { Cursor = 0; }
// Copies the data, and then preprocesses it to make sure // Copies the data, then preprocesses it to make
// it's all valid. If it's not valid, returns false. // sure it's all valid. Returns false if invalid.
// //
bool Initialize(std::string_view data); bool Initialize(std::string_view data);

View File

@@ -1,4 +1,3 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once #pragma once