Large refactoring and new nodes

* Fix node reference when changing elements

* Fix ScriptVariables parsing

* Fix invariant text and niagara types

* Niagara convert nodes

* Move node tests to own files

* More Niagara tests

* Niagara float and smaller fixes

* More Decoding

* More decoding

* WIP

* Float is real

* WIP

* More types and colors

* Test case and small polish

* WIP

* WIP

* Fix niagara script variables merging

* Fix Niagara variables

* Fixing mirrored ExportPath

* Fix Export paths name adjustments

* Simplify arc calculation

* Simplify a bit arc calculation

* source / destionation => origin / target

* Minor refactoring

* Fix switched link position

* Rename some properties for uniformity

* Fix input escape

* Simplify test

* About window

* Dialog backdrop style

* About dialog touches

* Remove dependency and minot improvement

* Light mode

* Fix link location and css small improvement

* Link direction and minor fixes

* Some minor fixes and refactoring

* Refactoring WIP

* Shorting repetitive bits

* More tests

* Simplify linking tests
This commit is contained in:
BarsDev
2025-02-07 00:36:03 +02:00
committed by GitHub
parent 876b8ce47f
commit 6ba2705386
347 changed files with 10108 additions and 6417 deletions

76
js/decoding/nodeColor.js Normal file → Executable file
View File

@@ -1,54 +1,61 @@
import Configuration from "../Configuration.js"
import LinearColorEntity from "../entity/LinearColorEntity.js"
const p = Configuration.paths
/** @param {ObjectEntity} entity */
export default function nodeColor(entity) {
switch (entity.getType()) {
case Configuration.paths.materialExpressionConstant2Vector:
case Configuration.paths.materialExpressionConstant3Vector:
case Configuration.paths.materialExpressionConstant4Vector:
case p.materialExpressionConstant2Vector:
case p.materialExpressionConstant3Vector:
case p.materialExpressionConstant4Vector:
return Configuration.nodeColors.yellow
case Configuration.paths.materialExpressionFunctionInput:
case Configuration.paths.materialExpressionTextureCoordinate:
case Configuration.paths.materialExpressionWorldPosition:
case Configuration.paths.pcgEditorGraphNodeInput:
case Configuration.paths.pcgEditorGraphNodeOutput:
case p.materialExpressionFunctionInput:
case p.materialExpressionTextureCoordinate:
case p.materialExpressionWorldPosition:
case p.pcgEditorGraphNodeInput:
case p.pcgEditorGraphNodeOutput:
return Configuration.nodeColors.red
case Configuration.paths.makeStruct:
case p.makeStruct:
return Configuration.nodeColors.darkBlue
case Configuration.paths.materialExpressionMaterialFunctionCall:
case p.materialExpressionMaterialFunctionCall:
return Configuration.nodeColors.blue
case Configuration.paths.materialExpressionTextureSample:
case p.materialExpressionTextureSample:
return Configuration.nodeColors.darkTurquoise
case p.niagaraNodeInput:
switch (entity["Usage"]?.toString()) {
case "Attribute": return Configuration.nodeColors.intenseGreen
case "Parameter": return Configuration.nodeColors.red
case "RapidIterationParameter": return Configuration.nodeColors.black
case "SystemConstant": return Configuration.nodeColors.gray
case "TranslatorConstant": return Configuration.nodeColors.gray
default: return Configuration.nodeColors.red
}
}
switch (entity.getClass()) {
case Configuration.paths.callFunction:
return entity.bIsPureFunc?.valueOf()
? Configuration.nodeColors.green
: Configuration.nodeColors.blue
case Configuration.paths.niagaraNodeFunctionCall:
case p.niagaraNodeFunctionCall:
return Configuration.nodeColors.darkerBlue
case Configuration.paths.dynamicCast:
case p.dynamicCast:
return Configuration.nodeColors.turquoise
case Configuration.paths.inputDebugKey:
case Configuration.paths.inputKey:
case p.inputDebugKey:
case p.inputKey:
return Configuration.nodeColors.red
case Configuration.paths.createDelegate:
case Configuration.paths.enumLiteral:
case Configuration.paths.makeArray:
case Configuration.paths.makeMap:
case Configuration.paths.materialGraphNode:
case Configuration.paths.select:
case p.createDelegate:
case p.enumLiteral:
case p.makeArray:
case p.makeMap:
case p.materialGraphNode:
case p.select:
return Configuration.nodeColors.green
case Configuration.paths.executionSequence:
case Configuration.paths.ifThenElse:
case Configuration.paths.macro:
case Configuration.paths.multiGate:
case p.executionSequence:
case p.ifThenElse:
case p.macro:
case p.multiGate:
return Configuration.nodeColors.gray
case Configuration.paths.functionEntry:
case Configuration.paths.functionResult:
case p.functionEntry:
case p.functionResult:
return Configuration.nodeColors.violet
case Configuration.paths.timeline:
case p.timeline:
return Configuration.nodeColors.yellow
}
if (entity.switchTarget()) {
@@ -73,8 +80,11 @@ export default function nodeColor(entity) {
return Configuration.nodeColors.intenseGreen
}
}
if (entity.bIsPureFunc?.valueOf()) {
if (entity.bIsPureFunc?.valueOf() || entity.bDefaultsToPureFunc?.valueOf()) {
return Configuration.nodeColors.green
}
if (entity["Input"]?.["Name"]) {
return Configuration.nodeColors.gray
}
return Configuration.nodeColors.blue
}

72
js/decoding/nodeIcon.js Normal file → Executable file
View File

@@ -2,50 +2,52 @@ import Configuration from "../Configuration.js"
import SVGIcon from "../SVGIcon.js"
import nodeTitle from "./nodeTitle.js"
const p = Configuration.paths
/** @param {ObjectEntity} entity */
export default function nodeIcon(entity) {
if (entity.isMaterial() || entity.isPcg() || entity.isNiagara()) {
return null
}
switch (entity.getType()) {
case Configuration.paths.addDelegate:
case Configuration.paths.asyncAction:
case Configuration.paths.callDelegate:
case Configuration.paths.clearDelegate:
case Configuration.paths.createDelegate:
case Configuration.paths.functionEntry:
case Configuration.paths.functionResult:
case Configuration.paths.removeDelegate:
case p.addDelegate:
case p.asyncAction:
case p.callDelegate:
case p.clearDelegate:
case p.createDelegate:
case p.functionEntry:
case p.functionResult:
case p.removeDelegate:
return SVGIcon.node
case Configuration.paths.customEvent: return SVGIcon.event
case Configuration.paths.doN: return SVGIcon.doN
case Configuration.paths.doOnce: return SVGIcon.doOnce
case Configuration.paths.dynamicCast: return SVGIcon.cast
case Configuration.paths.enumLiteral: return SVGIcon.enum
case Configuration.paths.event: return SVGIcon.event
case Configuration.paths.executionSequence:
case Configuration.paths.multiGate:
case p.customEvent: return SVGIcon.event
case p.doN: return SVGIcon.doN
case p.doOnce: return SVGIcon.doOnce
case p.dynamicCast: return SVGIcon.cast
case p.enumLiteral: return SVGIcon.enum
case p.event: return SVGIcon.event
case p.executionSequence:
case p.multiGate:
return SVGIcon.sequence
case Configuration.paths.flipflop:
case p.flipflop:
return SVGIcon.flipflop
case Configuration.paths.forEachElementInEnum:
case Configuration.paths.forLoop:
case Configuration.paths.forLoopWithBreak:
case Configuration.paths.whileLoop:
case p.forEachElementInEnum:
case p.forLoop:
case p.forLoopWithBreak:
case p.whileLoop:
return SVGIcon.loop
case Configuration.paths.forEachLoop:
case Configuration.paths.forEachLoopWithBreak:
case p.forEachLoop:
case p.forEachLoopWithBreak:
return SVGIcon.forEachLoop
case Configuration.paths.ifThenElse: return SVGIcon.branchNode
case Configuration.paths.isValid: return SVGIcon.questionMark
case Configuration.paths.makeArray: return SVGIcon.makeArray
case Configuration.paths.makeMap: return SVGIcon.makeMap
case Configuration.paths.makeSet: return SVGIcon.makeSet
case Configuration.paths.makeStruct: return SVGIcon.makeStruct
case Configuration.paths.metasoundEditorGraphExternalNode: return SVGIcon.metasoundFunction
case Configuration.paths.select: return SVGIcon.select
case Configuration.paths.spawnActorFromClass: return SVGIcon.spawnActor
case Configuration.paths.timeline: return SVGIcon.timer
case p.ifThenElse: return SVGIcon.branchNode
case p.isValid: return SVGIcon.questionMark
case p.makeArray: return SVGIcon.makeArray
case p.makeMap: return SVGIcon.makeMap
case p.makeSet: return SVGIcon.makeSet
case p.makeStruct: return SVGIcon.makeStruct
case p.metasoundEditorGraphExternalNode: return SVGIcon.metasoundFunction
case p.select: return SVGIcon.select
case p.spawnActorFromClass: return SVGIcon.spawnActor
case p.timeline: return SVGIcon.timer
}
if (entity.switchTarget()) {
return SVGIcon.switch
@@ -53,7 +55,7 @@ export default function nodeIcon(entity) {
if (nodeTitle(entity).startsWith("Break")) {
return SVGIcon.breakStruct
}
if (entity.getClass() === Configuration.paths.macro) {
if (entity.getClass() === p.macro) {
return SVGIcon.macro
}
const hidValue = entity.getHIDAttribute()?.toString()
@@ -73,7 +75,7 @@ export default function nodeIcon(entity) {
if (entity.getDelegatePin()) {
return SVGIcon.event
}
if (entity.ObjectRef?.type === Configuration.paths.ambientSound) {
if (entity.ObjectRef?.type === p.ambientSound) {
return SVGIcon.sound
}
return SVGIcon.functionSymbol

11
js/decoding/nodeSubtitle.js Normal file → Executable file
View File

@@ -2,20 +2,23 @@ import Configuration from "../Configuration.js"
import Utility from "../Utility.js"
import pinTitle from "./pinTitle.js"
const p = Configuration.paths
/**
* @param {ObjectEntity} entity
* @returns {String?}
*/
export default function nodeSubtitle(entity) {
switch (entity.getType()) {
case Configuration.paths.addDelegate:
case Configuration.paths.clearDelegate:
case Configuration.paths.removeDelegate:
case p.addDelegate:
case p.clearDelegate:
case p.callDelegate:
case p.removeDelegate:
return null
}
const targetPin = entity
.getPinEntities()
.find(pin => pin.PinName?.toString() === "self" && pinTitle(pin) === "Target")
.find(pin => !pin.isHidden() && pin.PinName?.toString() === "self" && pinTitle(pin) === "Target")
if (targetPin) {
const target = entity.FunctionReference?.MemberParent?.getName()
?? targetPin.PinType?.PinSubCategoryObject?.getName()

116
js/decoding/nodeTemplate.js Normal file → Executable file
View File

@@ -9,22 +9,89 @@ import VariableAccessNodeTemplate from "../template/node/VariableAccessNodeTempl
import VariableConversionNodeTemplate from "../template/node/VariableConversionNodeTemplate.js"
import VariableOperationNodeTemplate from "../template/node/VariableOperationNodeTemplate.js"
const niagaraOperationNodes = [
"Boolean::LogicEq",
"Boolean::LogicNEq",
"Integer::EnumNEq",
"Integer::EnumEq",
...[
"Abs",
"Add",
"ArcCosine(Degrees)",
"ArcCosine(Radians)",
"ArcSine(Degrees)",
"ArcSine(Radians)",
"ArcTangent(Degrees)",
"ArcTangent(Radians)",
"Ceil",
"CmpEQ",
"CmpGE",
"CmpGT",
"CmpLE",
"CmpLT",
"CmpNEQ",
"Cosine(Degrees)",
"Cosine(Radians)",
"DegreesToRadians",
"Div",
"Dot",
"Exp",
"Exp2",
"Floor",
"FMod",
"Frac",
"Length",
"Lerp",
"Log",
"Log2",
"Madd",
"Max",
"Min",
"Mul",
"Negate",
"Normalize",
"OneMinus",
"PI",
"RadiansToDegrees",
"Rcp",
"RcpFast",
"Round",
"RSqrt",
"Sign",
"Sine(Degrees)",
"Sine(Radians)",
"Sqrt",
"Step",
"Subtract",
"Tangent(Degrees)",
"Tangent(Radians)",
"Trunc",
"TWO_PI",
].map(v => "Numeric::" + v),
"Vector3::Cross",
]
const p = Configuration.paths
/**
* @param {ObjectEntity} nodeEntity
* @return {new () => NodeTemplate}
*/
export default function nodeTemplateClass(nodeEntity) {
const className = nodeEntity.getClass()
if (
nodeEntity.getClass() === Configuration.paths.callFunction
|| nodeEntity.getClass() === Configuration.paths.commutativeAssociativeBinaryOperator
|| nodeEntity.getClass() === Configuration.paths.callArrayFunction
className === p.callFunction
|| className === p.commutativeAssociativeBinaryOperator
|| className === p.callArrayFunction
) {
const memberParent = nodeEntity.FunctionReference?.MemberParent?.path ?? ""
const memberName = nodeEntity.FunctionReference?.MemberName?.toString()
if (
memberName && (
memberParent === Configuration.paths.kismetMathLibrary
|| memberParent === Configuration.paths.kismetArrayLibrary
memberParent === p.kismetArrayLibrary
|| memberParent === p.kismetMathLibrary
|| memberParent === p.kismetStringLibrary
|| memberParent === p.typedElementHandleLibrary
)) {
if (memberName.startsWith("Conv_")) {
return VariableConversionNodeTemplate
@@ -51,6 +118,7 @@ export default function nodeTemplateClass(nodeEntity) {
case "BMin":
case "CrossProduct2D":
case "DotProduct2D":
case "Equal":
case "Exp":
case "FMax":
case "FMin":
@@ -77,45 +145,37 @@ export default function nodeTemplateClass(nodeEntity) {
return VariableOperationNodeTemplate
}
}
if (memberParent === Configuration.paths.blueprintSetLibrary) {
if (memberParent === p.blueprintSetLibrary) {
return VariableOperationNodeTemplate
}
if (memberParent === Configuration.paths.blueprintMapLibrary) {
if (memberParent === p.blueprintMapLibrary) {
return VariableOperationNodeTemplate
}
}
switch (nodeEntity.getClass()) {
case Configuration.paths.comment:
case Configuration.paths.materialGraphNodeComment:
switch (className) {
case p.comment:
case p.materialGraphNodeComment:
return CommentNodeTemplate
case Configuration.paths.createDelegate:
case p.createDelegate:
return NodeTemplate
case Configuration.paths.metasoundEditorGraphExternalNode:
case p.metasoundEditorGraphExternalNode:
if (nodeEntity["ClassName"]?.["Name"] == "Add") {
return MetasoundOperationTemplate
}
return MetasoundNodeTemplate
case Configuration.paths.niagaraNodeOp:
if (
[
"Boolean::LogicEq",
"Boolean::LogicNEq",
"Numeric::Abs",
"Numeric::Add",
"Numeric::Mul",
].includes(nodeEntity.OpName?.toString())
) {
case p.niagaraNodeOp:
if (niagaraOperationNodes.includes(nodeEntity.OpName?.toString())) {
return VariableOperationNodeTemplate
}
break
case Configuration.paths.promotableOperator:
case p.promotableOperator:
return VariableOperationNodeTemplate
case Configuration.paths.knot:
case p.knot:
return KnotNodeTemplate
case Configuration.paths.literal:
case Configuration.paths.self:
case Configuration.paths.variableGet:
case Configuration.paths.variableSet:
case p.literal:
case p.self:
case p.variableGet:
case p.variableSet:
return VariableAccessNodeTemplate
}
if (nodeEntity.isEvent()) {

237
js/decoding/nodeTitle.js Normal file → Executable file
View File

@@ -34,6 +34,68 @@ const keyNameValue = {
"Subtract": "Num -",
"Tilde": "`",
}
const niagaraNodeNames = {
"Boolean::LogicAnd": "Logic AND",
"Boolean::LogicEq": "==",
"Boolean::LogicNEq": "!=",
"Boolean::LogicNot": "Logic NOT",
"Boolean::LogicOr": "Logic OR",
"Integer::BitAnd": "Bitwise AND",
"Integer::BitLShift": "Bitwise Left Shift",
"Integer::BitNot": "Bitwise NOT",
"Integer::BitOr": "Bitwise OR",
"Integer::BitRShift": "Bitwise Right Shift",
"Integer::BitXOr": "Bitwise XOR",
"Integer::EnumEq": "==",
"Integer::EnumNEq": "!=",
"Matrix::MatrixMultiply": "Multiply (Matrix * Matrix)",
"Matrix::MatrixVectorMultiply": "Multiply (Matrix * Vector4)",
// Numeric::
...Object.fromEntries(Object.entries({
"Add": "+",
"ArcCosine": "ArcCosine",
"ArcCosine(Degrees)": "ArcCos(D)",
"ArcCosine(Radians)": "ArcCos(R)",
"ArcSine": "ArcSine",
"ArcSine(Degrees)": "ArcSin(D)",
"ArcSine(Radians)": "ArcSin(R)",
"ArcTangent(Degrees)": "ArcTan(D)",
"ArcTangent(Radians)": "ArcTan(R)",
"CmpEQ": "==",
"CmpGE": ">=",
"CmpGT": ">",
"CmpLE": "<=",
"CmpLT": "<",
"CmpNEQ": "!=",
"Cosine(Degrees)": "Cos(D)",
"Cosine(Radians)": "Cos(R)",
"DegreesToRadians": "DegToRad",
"DistancePos": "Distance",
"Div": String.fromCharCode(0x00f7),
"FMod": "%",
"FModFast": "Modulo Fast",
"Length": "Len",
"Madd": `(A${String.fromCharCode(0x2a2f)}B)+C`,
"Mul": String.fromCharCode(0x2a2f),
"Negate": "-A",
"OneMinus": "1-A",
"PI": String.fromCharCode(0x03C0),
"RadiansToDegrees": "RadToDeg",
"Rand Float": "Random Float",
"Rand Integer": "Random Integer",
"Rand": "Random",
"Rcp": "Reciprocal",
"RSqrt": "Rcp Sqrt",
"Sine(Degrees)": "Sin(D)",
"Sine(Radians)": "Sin(R)",
"Subtract": "-",
"Tangent(Degrees)": "Tan(D)",
"Tangent(Radians)": "Tan(R)",
"TWO_PI": `2 ${String.fromCharCode(0x03C0)}`,
}).map(([k, v]) => ["Numeric::" + k, v])),
}
const p = Configuration.paths
const format = Utility.formatStringName
/** @param {String} value */
function numberFromText(value = "") {
@@ -78,58 +140,58 @@ function keyName(value) {
export default function nodeTitle(entity) {
let value
switch (entity.getType()) {
case Configuration.paths.addDelegate:
case p.addDelegate:
value ??= "Bind Event to "
case Configuration.paths.clearDelegate:
case p.clearDelegate:
value ??= "Unbind all Events from "
case Configuration.paths.removeDelegate:
case p.removeDelegate:
value ??= "Unbind Event from "
return value + Utility.formatStringName(
return value + format(
entity.DelegateReference?.MemberName?.toString().replace(/Delegate$/, "") ?? "None"
)
case Configuration.paths.asyncAction:
case p.asyncAction:
if (entity.ProxyFactoryFunctionName) {
return Utility.formatStringName(entity.ProxyFactoryFunctionName?.toString())
return format(entity.ProxyFactoryFunctionName?.toString())
}
case Configuration.paths.actorBoundEvent:
case Configuration.paths.componentBoundEvent:
return `${Utility.formatStringName(entity.DelegatePropertyName?.toString())} (${entity.ComponentPropertyName?.toString() ?? "Unknown"})`
case Configuration.paths.callDelegate:
case p.actorBoundEvent:
case p.componentBoundEvent:
return `${format(entity.DelegatePropertyName?.toString())} (${entity.ComponentPropertyName?.toString() ?? "Unknown"})`
case p.callDelegate:
return `Call ${entity.DelegateReference?.MemberName?.toString() ?? "None"}`
case Configuration.paths.createDelegate:
case p.createDelegate:
return "Create Event"
case Configuration.paths.customEvent:
case p.customEvent:
if (entity.CustomFunctionName) {
return entity.CustomFunctionName?.toString()
}
case Configuration.paths.dynamicCast:
case p.dynamicCast:
if (!entity.TargetType) {
return "Bad cast node" // Target type not found
}
return `Cast To ${entity.TargetType?.getName()}`
case Configuration.paths.enumLiteral:
case p.enumLiteral:
return `Literal enum ${entity.Enum?.getName()}`
case Configuration.paths.event:
case p.event:
return `Event ${(entity.EventReference?.MemberName?.toString() ?? "").replace(/^Receive/, "")}`
case Configuration.paths.executionSequence:
case p.executionSequence:
return "Sequence"
case Configuration.paths.forEachElementInEnum:
case p.forEachElementInEnum:
return `For Each ${entity.Enum?.getName()}`
case Configuration.paths.forEachLoopWithBreak:
case p.forEachLoopWithBreak:
return "For Each Loop with Break"
case Configuration.paths.functionEntry:
case p.functionEntry:
return entity.FunctionReference?.MemberName?.toString() === "UserConstructionScript"
? "Construction Script"
: entity.FunctionReference?.MemberName?.toString()
case Configuration.paths.functionResult:
case p.functionResult:
return "Return Node"
case Configuration.paths.ifThenElse:
case p.ifThenElse:
return "Branch"
case Configuration.paths.makeStruct:
case p.makeStruct:
if (entity.StructType) {
return `Make ${entity.StructType.getName()}`
}
case Configuration.paths.materialExpressionComponentMask: {
case p.materialExpressionComponentMask: {
const materialObject = entity.getMaterialSubobject()
if (materialObject) {
return `Mask ( ${Configuration.rgba
@@ -138,15 +200,15 @@ export default function nodeTitle(entity) {
.join("")})`
}
}
case Configuration.paths.materialExpressionConstant:
case p.materialExpressionConstant:
value ??= [entity.getCustomproperties().find(pinEntity => pinEntity.PinName.toString() == "Value")?.DefaultValue]
case Configuration.paths.materialExpressionConstant2Vector:
case p.materialExpressionConstant2Vector:
value ??= [
entity.getCustomproperties().find(pinEntity => pinEntity.PinName?.toString() == "X")?.DefaultValue,
entity.getCustomproperties().find(pinEntity => pinEntity.PinName?.toString() == "Y")?.DefaultValue,
]
case Configuration.paths.materialExpressionConstant3Vector:
case Configuration.paths.materialExpressionConstant4Vector:
case p.materialExpressionConstant3Vector:
case p.materialExpressionConstant4Vector:
if (!value) {
const vector = entity.getCustomproperties()
.find(pinEntity => pinEntity.PinName?.toString() == "Constant")
@@ -160,32 +222,32 @@ export default function nodeTitle(entity) {
}
value = undefined
break
case Configuration.paths.materialExpressionFunctionInput: {
case p.materialExpressionFunctionInput: {
const materialObject = entity.getMaterialSubobject()
const inputName = materialObject?.InputName ?? "In"
const inputType = materialObject?.InputType?.value.match(/^.+?_(\w+)$/)?.[1] ?? "Vector3"
return `Input ${inputName} (${inputType})`
}
case Configuration.paths.materialExpressionLogarithm:
case p.materialExpressionLogarithm:
return "Ln"
case Configuration.paths.materialExpressionLogarithm10:
case p.materialExpressionLogarithm10:
return "Log10"
case Configuration.paths.materialExpressionLogarithm2:
case p.materialExpressionLogarithm2:
return "Log2"
case Configuration.paths.materialExpressionMaterialFunctionCall:
case p.materialExpressionMaterialFunctionCall:
const materialFunction = entity.getMaterialSubobject()?.MaterialFunction
if (materialFunction) {
return materialFunction.getName()
}
break
case Configuration.paths.materialExpressionSquareRoot:
case p.materialExpressionSquareRoot:
return "Sqrt"
case Configuration.paths.materialExpressionSubtract:
case p.materialExpressionSubtract:
const materialObject = entity.getMaterialSubobject()
if (materialObject) {
return `Subtract(${materialObject.ConstA ?? "1"},${materialObject.ConstB ?? "1"})`
}
case Configuration.paths.metasoundEditorGraphExternalNode: {
case p.metasoundEditorGraphExternalNode: {
const name = entity["ClassName"]?.["Name"]
if (name) {
switch (name) {
@@ -194,11 +256,19 @@ export default function nodeTitle(entity) {
}
}
}
case Configuration.paths.pcgEditorGraphNodeInput:
case p.niagaraNodeConvert:
/** @type {String} */
const targetType = (entity["AutowireMakeType"]?.["ClassStructOrEnum"] ?? "")
.toString()
.match(/(?:Niagara)?(\w+)['"]*$/)
?.[1]
?? ""
return `Make ${targetType}`
case p.pcgEditorGraphNodeInput:
return "Input"
case Configuration.paths.pcgEditorGraphNodeOutput:
case p.pcgEditorGraphNodeOutput:
return "Output"
case Configuration.paths.spawnActorFromClass:
case p.spawnActorFromClass:
let className = entity.getCustomproperties()
.find(pinEntity => pinEntity.PinName.toString() == "ReturnValue")
?.PinType
@@ -207,20 +277,21 @@ export default function nodeTitle(entity) {
if (className === "Actor") {
className = null
}
return `SpawnActor ${Utility.formatStringName(className ?? "NONE")}`
case Configuration.paths.switchEnum:
return `SpawnActor ${format(className ?? "NONE")}`
case p.switchEnum:
return `Switch on ${entity.Enum?.getName() ?? "Enum"}`
case Configuration.paths.switchInteger:
case p.switchInteger:
return `Switch on Int`
case Configuration.paths.variableGet:
case p.variableGet:
return ""
case Configuration.paths.variableSet:
case p.variableSet:
return "SET"
}
const className = entity.getClass()
let switchTarget = entity.switchTarget()
if (switchTarget) {
if (switchTarget[0] !== "E") {
switchTarget = Utility.formatStringName(switchTarget)
switchTarget = format(switchTarget)
}
return `Switch on ${switchTarget}`
}
@@ -230,19 +301,20 @@ export default function nodeTitle(entity) {
const keyNameSymbol = entity.getHIDAttribute()
if (keyNameSymbol) {
const name = keyNameSymbol.toString()
let title = keyName(name) ?? Utility.formatStringName(name)
if (entity.getClass() === Configuration.paths.inputDebugKey) {
let title = keyName(name) ?? format(name)
if (className === p.inputDebugKey) {
title = "Debug Key " + title
} else if (entity.getClass() === Configuration.paths.getInputAxisKeyValue) {
} else if (className === p.getInputAxisKeyValue) {
title = "Get " + title
}
return title
}
if (entity.getClass() === Configuration.paths.macro) {
return Utility.formatStringName(entity.MacroGraphReference?.getMacroName())
if (className === p.macro) {
return format(entity.MacroGraphReference?.getMacroName())
}
if (entity.isMaterial() && entity.getMaterialSubobject()) {
let result = nodeTitle(entity.getMaterialSubobject())
const materialSubobject = entity.getMaterialSubobject()
if (materialSubobject) {
let result = nodeTitle(materialSubobject)
result = result.match(/Material Expression (.+)/)?.[1] ?? result
return result
}
@@ -257,19 +329,19 @@ export default function nodeTitle(entity) {
}
const settingsObject = entity.getSettingsObject()
if (settingsObject) {
if (settingsObject.ExportPath.type === Configuration.paths.pcgHiGenGridSizeSettings) {
if (settingsObject.ExportPath?.valueOf()?.type === p.pcgHiGenGridSizeSettings) {
return `Grid Size: ${(
settingsObject.HiGenGridSize?.toString().match(/\d+/)?.[0]?.concat("00")
?? settingsObject.HiGenGridSize?.toString().match(/^\w+$/)?.[0]
) ?? "256"}`
}
if (settingsObject.BlueprintElementInstance) {
return Utility.formatStringName(settingsObject.BlueprintElementType.getName())
return format(settingsObject.BlueprintElementType.getName())
}
if (settingsObject.Operation) {
const match = settingsObject.Name?.toString().match(/PCGMetadata(\w+)Settings_\d+/)
if (match) {
return Utility.formatStringName(match[1] + ": " + settingsObject.Operation)
return format(match[1] + ": " + settingsObject.Operation)
}
}
const settingsSubgraphObject = settingsObject.getSubgraphObject()
@@ -284,7 +356,7 @@ export default function nodeTitle(entity) {
case "AddKey":
let result = memberParent.match(sequencerScriptingNameRegex)
if (result) {
return `Add Key (${Utility.formatStringName(result[1])})`
return `Add Key (${format(result[1])})`
}
case "Concat_StrStr":
return "Append"
@@ -295,14 +367,16 @@ export default function nodeTitle(entity) {
+ (memberNameTraceLineMatch[1] === "Multi" ? " Multi " : " ")
+ (memberNameTraceLineMatch[2] === ""
? "By Channel"
: Utility.formatStringName(memberNameTraceLineMatch[2])
: format(memberNameTraceLineMatch[2])
)
}
switch (memberParent) {
case Configuration.paths.blueprintGameplayTagLibrary:
case Configuration.paths.kismetMathLibrary:
case Configuration.paths.slateBlueprintLibrary:
case Configuration.paths.timeManagementBlueprintLibrary:
case p.blueprintGameplayTagLibrary:
case p.kismetMathLibrary:
case p.kismetStringLibrary:
case p.slateBlueprintLibrary:
case p.timeManagementBlueprintLibrary:
case p.typedElementHandleLibrary:
const leadingLetter = memberName.match(/[BF]([A-Z]\w+)/)
if (leadingLetter) {
// Some functions start with B or F (Like FCeil, FMax, BMin)
@@ -313,6 +387,7 @@ export default function nodeTitle(entity) {
case "BooleanAND": return "AND"
case "BooleanNAND": return "NAND"
case "BooleanOR": return "OR"
case "Equal": return "=="
case "Exp": return "e"
case "LineTraceSingle": return "Line Trace By Channel"
case "Max": return "MAX"
@@ -386,23 +461,23 @@ export default function nodeTitle(entity) {
return "^"
}
break
case Configuration.paths.blueprintSetLibrary:
case p.blueprintSetLibrary:
{
const setOperationMatch = memberName.match(/Set_(\w+)/)
if (setOperationMatch) {
return Utility.formatStringName(setOperationMatch[1]).toUpperCase()
return format(setOperationMatch[1]).toUpperCase()
}
}
break
case Configuration.paths.blueprintMapLibrary:
case p.blueprintMapLibrary:
{
const setOperationMatch = memberName.match(/Map_(\w+)/)
if (setOperationMatch) {
return Utility.formatStringName(setOperationMatch[1]).toUpperCase()
return format(setOperationMatch[1]).toUpperCase()
}
}
break
case Configuration.paths.kismetArrayLibrary:
case p.kismetArrayLibrary:
{
const arrayOperationMath = memberName.match(/Array_(\w+)/)
if (arrayOperationMath) {
@@ -411,29 +486,27 @@ export default function nodeTitle(entity) {
}
break
}
return Utility.formatStringName(memberName)
return format(memberName)
}
if (entity.OpName) {
switch (entity.OpName.toString()) {
case "Boolean::LogicAnd": return "Logic AND"
case "Boolean::LogicEq": return "=="
case "Boolean::LogicNEq": return "!="
case "Boolean::LogicNot": return "Logic NOT"
case "Boolean::LogicOr": return "Logic OR"
case "Matrix::MatrixMultiply": return "Multiply (Matrix * Matrix)"
case "Matrix::MatrixVectorMultiply": return "Multiply (Matrix * Vector4)"
case "Numeric::Abs": return "Abs"
case "Numeric::Add": return "+"
case "Numeric::DistancePos": return "Distance"
case "Numeric::Mul": return String.fromCharCode(0x2a2f)
}
return Utility.formatStringName(entity.OpName.toString()).replaceAll("::", " ")
return niagaraNodeNames[entity.OpName.toString()]
?? format(entity.OpName.toString().replaceAll(/(?:^\w+(?<!^Matrix))?::/g, " "))
}
if (entity.FunctionDisplayName) {
return Utility.formatStringName(entity.FunctionDisplayName.toString())
return format(entity.FunctionDisplayName.toString())
}
if (entity.ObjectRef) {
return entity.ObjectRef.getName()
}
return Utility.formatStringName(entity.getNameAndCounter()[0])
let prefix
if (
className.startsWith(prefix = "/Script/NiagaraEditor.NiagaraNodeParameter")
|| className.startsWith(prefix = "/Script/NiagaraEditor.NiagaraNode")
) {
return entity["Input"]?.["Name"]?.toString() ?? format(className.substring(prefix.length))
}
if (entity.ParameterName) {
return entity.ParameterName.toString()
}
return format(entity.getNameAndCounter()[0])
}

19
js/decoding/nodeVariadic.js Normal file → Executable file
View File

@@ -8,6 +8,7 @@ import StringEntity from "../entity/StringEntity.js"
/** @param {PinEntity} pinEntity */
const indexFromUpperCaseLetterName = pinEntity =>
pinEntity.PinName?.toString().match(/^\s*([A-Z])\s*$/)?.[1]?.charCodeAt(0) - "A".charCodeAt(0)
const p = Configuration.paths
/** @param {ObjectEntity} entity */
export default function nodeVariadic(entity) {
@@ -21,8 +22,8 @@ export default function nodeVariadic(entity) {
let prefix
let name
switch (type) {
case Configuration.paths.commutativeAssociativeBinaryOperator:
case Configuration.paths.promotableOperator:
case p.commutativeAssociativeBinaryOperator:
case p.promotableOperator:
name = entity.FunctionReference?.MemberName?.toString()
switch (name) {
default:
@@ -60,9 +61,9 @@ export default function nodeVariadic(entity) {
break
}
break
case Configuration.paths.executionSequence:
case p.executionSequence:
prefix ??= "Then"
case Configuration.paths.multiGate:
case p.multiGate:
prefix ??= "Out"
pinEntities ??= () => entity.getPinEntities().filter(pinEntity => pinEntity.isOutput())
pinIndexFromEntity ??= pinEntity => Number(
@@ -71,7 +72,7 @@ export default function nodeVariadic(entity) {
pinNameFromIndex ??= (index, min = -1, max = -1, newPin) =>
`${prefix} ${index >= 0 ? index : min > 0 ? `${prefix} 0` : max + 1}`
break
// case Configuration.paths.niagaraNodeOp:
// case p.niagaraNodeOp:
// pinEntities ??= () => entity.getPinEntities().filter(pinEntity => pinEntity.isInput())
// pinIndexFromEntity ??= indexFromUpperCaseLetterName
// pinNameFromIndex ??= (index, min = -1, max = -1, newPin) => {
@@ -81,12 +82,12 @@ export default function nodeVariadic(entity) {
// return result
// }
// break
case Configuration.paths.switchInteger:
case p.switchInteger:
pinEntities ??= () => entity.getPinEntities().filter(pinEntity => pinEntity.isOutput())
pinIndexFromEntity ??= pinEntity => Number(pinEntity.PinName?.toString().match(/^\s*(\d+)\s*$/)?.[1])
pinNameFromIndex ??= (index, min = -1, max = -1, newPin) => (index < 0 ? max + 1 : index).toString()
break
case Configuration.paths.switchGameplayTag:
case p.switchGameplayTag:
pinNameFromIndex ??= (index, min = -1, max = -1, newPin) => {
const result = `Case_${index >= 0 ? index : min > 0 ? "0" : max + 1}`
entity.PinNames ??= new ArrayEntity()
@@ -95,8 +96,8 @@ export default function nodeVariadic(entity) {
entity.PinTags.valueOf()[entity.PinTags.length] = null
return result
}
case Configuration.paths.switchName:
case Configuration.paths.switchString:
case p.switchName:
case p.switchString:
pinEntities ??= () => entity.getPinEntities().filter(pinEntity => pinEntity.isOutput())
pinIndexFromEntity ??= pinEntity => Number(pinEntity.PinName.toString().match(/^\s*Case[_\s]+(\d+)\s*$/i)?.[1])
pinNameFromIndex ??= (index, min = -1, max = -1, newPin) => {

49
js/decoding/pinColor.js Normal file → Executable file
View File

@@ -1,25 +1,14 @@
import { css } from "lit"
import Configuration from "../Configuration.js"
const p = Configuration.paths
const colors = {
[Configuration.paths.niagaraBool]: css`146, 0, 0`,
[Configuration.paths.niagaraDataInterfaceVolumeTexture]: css`0, 168, 242`,
[Configuration.paths.niagaraFloat]: css`160, 250, 68`,
[Configuration.paths.niagaraMatrix]: css`0, 88, 200`,
[Configuration.paths.niagaraNumeric]: css`0, 88, 200`,
[Configuration.paths.niagaraPosition]: css`251, 146, 251`,
[Configuration.paths.quat4f]: css`0, 88, 200`,
[Configuration.paths.rotator]: css`157, 177, 251`,
[Configuration.paths.transform]: css`227, 103, 0`,
[Configuration.paths.vector]: css`251, 198, 34`,
[Configuration.paths.vector3f]: css`250, 200, 36`,
[Configuration.paths.vector4f]: css`0, 88, 200`,
"Any": css`132, 132, 132`,
"Any[]": css`132, 132, 132`,
"audio": css`252, 148, 252`,
"blue": css`0, 0, 255`,
"bool": css`146, 0, 0`,
"byte": css`0, 109, 99`,
"byte": css`0, 110, 100`,
"class": css`88, 0, 186`,
"default": css`255, 255, 255`,
"delegate": css`255, 56, 56`,
@@ -27,16 +16,16 @@ const colors = {
"exec": css`240, 240, 240`,
"float": css`160, 252, 70`,
"green": css`0, 255, 0`,
"int": css`31, 224, 172`,
"int": css`30, 224, 172`,
"int32": css`30, 224, 172`,
"int64": css`169, 223, 172`,
"int64": css`170, 224, 172`,
"interface": css`238, 252, 168`,
"name": css`201, 128, 251`,
"name": css`200, 128, 252`,
"object": css`0, 168, 242`,
"Param": css`255, 166, 39`,
"Param[]": css`255, 166, 39`,
"Point": css`63, 137, 255`,
"Point[]": css`63, 137, 255`,
"Param": css`255, 166, 40`,
"Param[]": css`255, 166, 40`,
"Point": css`64, 138, 255`,
"Point[]": css`64, 137, 255`,
"real": css`54, 208, 0`,
"red": css`255, 0, 0`,
"string": css`251, 0, 208`,
@@ -48,6 +37,21 @@ const colors = {
"Volume": css`230, 69, 188`,
"Volume[]": css`230, 69, 188`,
"wildcard": css`128, 120, 120`,
[p.linearColor]: css`0, 88, 200`,
[p.niagaraBool]: css`146, 0, 0`,
[p.niagaraDataInterfaceCollisionQuery]: css`0, 168, 242`,
[p.niagaraDataInterfaceCurlNoise]: css`0, 168, 242`,
[p.niagaraDataInterfaceVolumeTexture]: css`0, 168, 242`,
[p.niagaraFloat]: css`160, 250, 68`,
[p.niagaraInt32]: css`30, 224, 172`,
[p.niagaraPosition]: css`251, 146, 251`,
[p.quat4f]: css`0, 88, 200`,
[p.rotator]: css`157, 177, 251`,
[p.transform]: css`227, 103, 0`,
[p.vector]: css`251, 198, 34`,
[p.vector2f]: css`0, 88, 200`,
[p.vector3f]: css`250, 200, 36`,
[p.vector4f]: css`0, 88, 200`,
}
const pinColorMaterial = css`120, 120, 120`
@@ -62,7 +66,8 @@ export default function pinColor(entity) {
} else if (entity.PinType.PinCategory?.toString() === "optional") {
return pinColorMaterial
}
return colors[entity.getType()]
const type = entity.getType()
return colors[type]
?? colors[entity.PinType.PinCategory?.toString().toLowerCase()]
?? colors["default"]
?? (type.startsWith("/Script/Niagara.") ? colors["struct"] : colors["default"])
}

30
js/decoding/pinTemplate.js Normal file → Executable file
View File

@@ -7,6 +7,7 @@ import IntPinTemplate from "../template/pin/IntPinTemplate.js"
import LinearColorPinTemplate from "../template/pin/LinearColorPinTemplate.js"
import NamePinTemplate from "../template/pin/NamePinTemplate.js"
import PinTemplate from "../template/pin/PinTemplate.js"
import ReadonlyNamePinTemplate from "../template/pin/ReadonlyInputPinTemplate.js"
import RealPinTemplate from "../template/pin/RealPinTemplate.js"
import ReferencePinTemplate from "../template/pin/ReferencePinTemplate.js"
import RotatorPinTemplate from "../template/pin/RotatorPinTemplate.js"
@@ -14,11 +15,14 @@ import StringPinTemplate from "../template/pin/StringPinTemplate.js"
import Vector2DPinTemplate from "../template/pin/Vector2DPinTemplate.js"
import Vector4DPinTemplate from "../template/pin/Vector4DPinTemplate.js"
import VectorPinTemplate from "../template/pin/VectorPinTemplate.js"
import pinTitle from "./pinTitle.js"
const p = Configuration.paths
const inputPinTemplates = {
"bool": BoolPinTemplate,
"byte": IntPinTemplate,
"enum": EnumPinTemplate,
"float": RealPinTemplate,
"int": IntPinTemplate,
"int64": Int64PinTemplate,
"MUTABLE_REFERENCE": ReferencePinTemplate,
@@ -26,14 +30,17 @@ const inputPinTemplates = {
"real": RealPinTemplate,
"rg": Vector2DPinTemplate,
"string": StringPinTemplate,
[Configuration.paths.linearColor]: LinearColorPinTemplate,
[Configuration.paths.niagaraBool]: BoolPinTemplate,
[Configuration.paths.niagaraPosition]: VectorPinTemplate,
[Configuration.paths.rotator]: RotatorPinTemplate,
[Configuration.paths.vector]: VectorPinTemplate,
[Configuration.paths.vector2D]: Vector2DPinTemplate,
[Configuration.paths.vector3f]: VectorPinTemplate,
[Configuration.paths.vector4f]: Vector4DPinTemplate,
[p.linearColor]: LinearColorPinTemplate,
[p.niagaraBool]: BoolPinTemplate,
[p.niagaraFloat]: RealPinTemplate,
[p.niagaraInt32]: IntPinTemplate,
[p.niagaraPosition]: VectorPinTemplate,
[p.rotator]: RotatorPinTemplate,
[p.vector]: VectorPinTemplate,
[p.vector2D]: Vector2DPinTemplate,
[p.vector2f]: Vector2DPinTemplate,
[p.vector3f]: VectorPinTemplate,
[p.vector4f]: Vector4DPinTemplate,
}
/** @param {PinEntity<IEntity>} entity */
@@ -44,9 +51,12 @@ export default function pinTemplate(entity) {
if (entity.PinType.bIsReference?.valueOf() && !entity.PinType.bIsConst?.valueOf()) {
return inputPinTemplates["MUTABLE_REFERENCE"]
}
const type = entity.getType()
if (type === "exec") {
if (entity.isExecution()) {
return ExecPinTemplate
}
if (entity.PinName?.toString() === "self" && pinTitle(entity) === "Target") {
return ReadonlyNamePinTemplate
}
const type = entity.getType()
return (entity.isInput() ? inputPinTemplates[type] : PinTemplate) ?? PinTemplate
}

1
js/decoding/pinTitle.js Normal file → Executable file
View File

@@ -11,5 +11,6 @@ export default function pinTitle(entity) {
return match[1] // In case they match, then keep the case of the PinToolTip
}
}
result = result.replace(/^Module\./, "")
return result
}