mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-03 23:55:04 +08:00
782 lines
34 KiB
JavaScript
Executable File
782 lines
34 KiB
JavaScript
Executable File
import P from "parsernostrum"
|
|
import Configuration from "../Configuration.js"
|
|
import nodeColor from "../decoding/nodeColor.js"
|
|
import nodeIcon from "../decoding/nodeIcon.js"
|
|
import nodeVariadic from "../decoding/nodeVariadic.js"
|
|
import Grammar from "../serialization/Grammar.js"
|
|
import Utility from "../Utility.js"
|
|
import AlternativesEntity from "./AlternativesEntity.js"
|
|
import ArrayEntity from "./ArrayEntity.js"
|
|
import BooleanEntity from "./BooleanEntity.js"
|
|
import FunctionReferenceEntity from "./FunctionReferenceEntity.js"
|
|
import GuidEntity from "./GuidEntity.js"
|
|
import IEntity from "./IEntity.js"
|
|
import IntegerEntity from "./IntegerEntity.js"
|
|
import LinearColorEntity from "./LinearColorEntity.js"
|
|
import MacroGraphReferenceEntity from "./MacroGraphReferenceEntity.js"
|
|
import MirroredEntity from "./MirroredEntity.js"
|
|
import NaturalNumberEntity from "./NaturalNumberEntity.js"
|
|
import NullEntity from "./NullEntity.js"
|
|
import NumberEntity from "./NumberEntity.js"
|
|
import ObjectReferenceEntity from "./ObjectReferenceEntity.js"
|
|
import PinEntity from "./PinEntity.js"
|
|
import ScriptVariableEntity from "./ScriptVariableEntity.js"
|
|
import StringEntity from "./StringEntity.js"
|
|
import SymbolEntity from "./SymbolEntity.js"
|
|
import UnknownPinEntity from "./UnknownPinEntity.js"
|
|
import VariableReferenceEntity from "./VariableReferenceEntity.js"
|
|
|
|
export default class ObjectEntity extends IEntity {
|
|
|
|
#exported = false
|
|
get exported() {
|
|
return this.#exported
|
|
}
|
|
set exported(value) {
|
|
this.#exported = value
|
|
}
|
|
|
|
static #nameRegex = /^(\w+?)(?:_(\d+))?$/
|
|
/** @type {(k: String) => String} */
|
|
static printKey = k => !k.startsWith(Configuration.subObjectAttributeNamePrefix) ? k : ""
|
|
static attributeSeparator = "\n"
|
|
static wrap = this.notWrapped
|
|
static trailing = true
|
|
static attributes = {
|
|
...super.attributes,
|
|
Class: ObjectReferenceEntity,
|
|
Name: StringEntity,
|
|
Archetype: ObjectReferenceEntity,
|
|
ExportPath: MirroredEntity.of(ObjectReferenceEntity),
|
|
ObjectRef: ObjectReferenceEntity,
|
|
BlueprintElementType: ObjectReferenceEntity,
|
|
BlueprintElementInstance: ObjectReferenceEntity,
|
|
ConstA: MirroredEntity.of(NumberEntity),
|
|
ConstB: MirroredEntity.of(NumberEntity),
|
|
PinTags: ArrayEntity.of(NullEntity).flagInlined(),
|
|
PinNames: ArrayEntity.of(StringEntity).flagInlined(),
|
|
AxisKey: SymbolEntity,
|
|
InputAxisKey: SymbolEntity,
|
|
InputName: StringEntity,
|
|
InputType: SymbolEntity,
|
|
NumAdditionalInputs: NaturalNumberEntity,
|
|
bIsPureFunc: BooleanEntity,
|
|
bIsConstFunc: BooleanEntity,
|
|
bIsCaseSensitive: BooleanEntity,
|
|
bDefaultsToPureFunc: BooleanEntity,
|
|
VariableReference: VariableReferenceEntity,
|
|
SelfContextInfo: SymbolEntity,
|
|
DelegatePropertyName: StringEntity,
|
|
DelegateOwnerClass: ObjectReferenceEntity,
|
|
ComponentPropertyName: StringEntity,
|
|
EventReference: FunctionReferenceEntity,
|
|
FunctionReference: FunctionReferenceEntity,
|
|
FunctionScript: ObjectReferenceEntity,
|
|
CustomFunctionName: StringEntity,
|
|
TargetType: ObjectReferenceEntity,
|
|
MacroGraphReference: MacroGraphReferenceEntity,
|
|
Enum: ObjectReferenceEntity,
|
|
EnumEntries: ArrayEntity.of(StringEntity).flagInlined(),
|
|
InputKey: SymbolEntity,
|
|
OpName: StringEntity,
|
|
CachedChangeId: GuidEntity,
|
|
FunctionDisplayName: StringEntity,
|
|
AddedPins: ArrayEntity.of(UnknownPinEntity).withDefault().flagInlined().flagSilent(),
|
|
ChangeId: GuidEntity,
|
|
MaterialFunction: ObjectReferenceEntity,
|
|
bOverrideFunction: BooleanEntity,
|
|
bInternalEvent: BooleanEntity,
|
|
bConsumeInput: BooleanEntity,
|
|
bExecuteWhenPaused: BooleanEntity,
|
|
bOverrideParentBinding: BooleanEntity,
|
|
bControl: BooleanEntity,
|
|
bAlt: BooleanEntity,
|
|
bShift: BooleanEntity,
|
|
bCommand: BooleanEntity,
|
|
CommentColor: LinearColorEntity,
|
|
bCommentBubbleVisible_InDetailsPanel: BooleanEntity,
|
|
bColorCommentBubble: BooleanEntity,
|
|
ProxyFactoryFunctionName: StringEntity,
|
|
ProxyFactoryClass: ObjectReferenceEntity,
|
|
ProxyClass: ObjectReferenceEntity,
|
|
StructType: ObjectReferenceEntity,
|
|
MaterialExpression: ObjectReferenceEntity,
|
|
MaterialExpressionComment: ObjectReferenceEntity,
|
|
MoveMode: SymbolEntity,
|
|
TimelineName: StringEntity,
|
|
TimelineGuid: GuidEntity,
|
|
SizeX: MirroredEntity.of(IntegerEntity),
|
|
SizeY: MirroredEntity.of(IntegerEntity),
|
|
Text: MirroredEntity.of(StringEntity),
|
|
ParameterName: StringEntity,
|
|
ExpressionGUID: GuidEntity,
|
|
MaterialExpressionEditorX: MirroredEntity.of(IntegerEntity),
|
|
MaterialExpressionEditorY: MirroredEntity.of(IntegerEntity),
|
|
MaterialExpressionGuid: GuidEntity,
|
|
NodeTitle: StringEntity,
|
|
NodeTitleColor: LinearColorEntity,
|
|
PositionX: MirroredEntity.of(IntegerEntity),
|
|
PositionY: MirroredEntity.of(IntegerEntity),
|
|
SettingsInterface: ObjectReferenceEntity,
|
|
PCGNode: ObjectReferenceEntity,
|
|
SoundNode: ObjectReferenceEntity,
|
|
SoundWaveAssetPtr: ObjectReferenceEntity,
|
|
HiGenGridSize: SymbolEntity,
|
|
Operation: SymbolEntity,
|
|
NodePosX: IntegerEntity,
|
|
NodePosY: IntegerEntity,
|
|
NodeHeight: IntegerEntity,
|
|
NodeWidth: IntegerEntity,
|
|
Graph: ObjectReferenceEntity,
|
|
SubgraphInstance: StringEntity,
|
|
InputPins: ArrayEntity.of(ObjectReferenceEntity).flagInlined(),
|
|
OutputPins: ArrayEntity.of(ObjectReferenceEntity).flagInlined(),
|
|
bExposeToLibrary: BooleanEntity,
|
|
bCanRenameNode: BooleanEntity,
|
|
bCommentBubblePinned: BooleanEntity,
|
|
bCommentBubbleVisible: BooleanEntity,
|
|
NodeComment: StringEntity,
|
|
AdvancedPinDisplay: SymbolEntity,
|
|
DelegateReference: VariableReferenceEntity,
|
|
EnabledState: SymbolEntity,
|
|
NodeGuid: GuidEntity,
|
|
ErrorType: IntegerEntity,
|
|
ErrorMsg: StringEntity,
|
|
ScriptVariables: ArrayEntity.flagInlined().of(ScriptVariableEntity),
|
|
Node: MirroredEntity.of(ObjectReferenceEntity),
|
|
ExportedNodes: StringEntity,
|
|
CustomProperties: ArrayEntity
|
|
.of(AlternativesEntity.accepting(PinEntity, UnknownPinEntity))
|
|
.withDefault()
|
|
.flagSilent(),
|
|
}
|
|
static customPropertyGrammar = P.seq(
|
|
P.reg(/CustomProperties\s+/),
|
|
this.attributes.CustomProperties.type.grammar,
|
|
).map(([_0, pin]) => values => {
|
|
/** @type {InstanceType<typeof this.attributes.CustomProperties>} */(
|
|
values.CustomProperties ??= new (this.attributes.CustomProperties)()
|
|
).values.push(pin)
|
|
})
|
|
static inlinedArrayEntryGrammar = P.seq(
|
|
P.alt(
|
|
Grammar.symbolQuoted.map(v => [v, true]),
|
|
Grammar.symbol.map(v => [v, false]),
|
|
),
|
|
P.reg(new RegExp(String.raw`\s*\(\s*(\d+)\s*\)\s*\=\s*`), 1).map(Number) // Number in parentheses then equal
|
|
).chain(
|
|
/** @param {[[keyof ObjectEntity.attributes, Boolean], Number]} param */
|
|
([[symbol, quoted], index]) =>
|
|
(this.attributes[symbol]?.grammar ?? IEntity.unknownEntityGrammar).map(currentValue =>
|
|
values => {
|
|
if (values[symbol] === undefined) {
|
|
let arrayEntity = ArrayEntity
|
|
if (quoted != arrayEntity.quoted) {
|
|
arrayEntity = arrayEntity.flagQuoted(quoted)
|
|
}
|
|
if (!arrayEntity.inlined) {
|
|
arrayEntity = arrayEntity.flagInlined()
|
|
}
|
|
values[symbol] = new arrayEntity()
|
|
}
|
|
/** @type {ArrayEntity} */
|
|
const target = values[symbol]
|
|
target.values[index] = currentValue
|
|
}
|
|
)
|
|
)
|
|
static grammar = this.createGrammar()
|
|
static grammarMultipleObjects = P.seq(
|
|
P.whitespaceOpt,
|
|
this.grammar,
|
|
P.seq(
|
|
P.whitespace,
|
|
this.grammar,
|
|
)
|
|
.map(([_0, object]) => object)
|
|
.many(),
|
|
P.whitespaceOpt
|
|
).map(([_0, first, remaining, _4]) => [first, ...remaining])
|
|
|
|
constructor(values = {}) {
|
|
if (("NodePosX" in values) !== ("NodePosY" in values)) {
|
|
const entries = Object.entries(values)
|
|
const [key, position] = "NodePosX" in values
|
|
? ["NodePosY", Object.keys(values).indexOf("NodePosX") + 1]
|
|
: ["NodePosX", Object.keys(values).indexOf("NodePosY")]
|
|
entries.splice(position, 0, [key, new IntegerEntity(0)])
|
|
values = Object.fromEntries(entries)
|
|
}
|
|
super(values)
|
|
|
|
// Attributes
|
|
/** @type {ArrayEntity<typeof PinEntity | typeof UnknownPinEntity>} */ this.CustomProperties
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.AddedPins>} */ this.AddedPins
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.AdvancedPinDisplay>} */ this.AdvancedPinDisplay
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Archetype>} */ this.Archetype
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.AxisKey>} */ this.AxisKey
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.bIsPureFunc>} */ this.bIsPureFunc
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.bDefaultsToPureFunc>} */ this.bDefaultsToPureFunc
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.BlueprintElementInstance>} */ this.BlueprintElementInstance
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.BlueprintElementType>} */ this.BlueprintElementType
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Class>} */ this.Class
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.CommentColor>} */ this.CommentColor
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ComponentPropertyName>} */ this.ComponentPropertyName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ConstA>} */ this.ConstA
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ConstB>} */ this.ConstB
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.CustomFunctionName>} */ this.CustomFunctionName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.DelegatePropertyName>} */ this.DelegatePropertyName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.DelegateReference>} */ this.DelegateReference
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.EnabledState>} */ this.EnabledState
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Enum>} */ this.Enum
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.EnumEntries>} */ this.EnumEntries
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.EventReference>} */ this.EventReference
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ExportedNodes>} */ this.ExportedNodes
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ExportPath>} */ this.ExportPath
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.FunctionDisplayName>} */ this.FunctionDisplayName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.FunctionReference>} */ this.FunctionReference
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.FunctionScript>} */ this.FunctionScript
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Graph>} */ this.Graph
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.HiGenGridSize>} */ this.HiGenGridSize
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.InputAxisKey>} */ this.InputAxisKey
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.InputKey>} */ this.InputKey
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.InputName>} */ this.InputName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.InputPins>} */ this.InputPins
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.InputType>} */ this.InputType
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MacroGraphReference>} */ this.MacroGraphReference
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MaterialExpression>} */ this.MaterialExpression
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MaterialExpressionComment>} */ this.MaterialExpressionComment
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MaterialExpressionEditorX>} */ this.MaterialExpressionEditorX
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MaterialExpressionEditorY>} */ this.MaterialExpressionEditorY
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.MaterialFunction>} */ this.MaterialFunction
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Name>} */ this.Name
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Node>} */ this.Node
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodeComment>} */ this.NodeComment
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodeHeight>} */ this.NodeHeight
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodePosX>} */ this.NodePosX
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodePosY>} */ this.NodePosY
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodeTitle>} */ this.NodeTitle
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodeTitleColor>} */ this.NodeTitleColor
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NodeWidth>} */ this.NodeWidth
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.NumAdditionalInputs>} */ this.NumAdditionalInputs
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ObjectRef>} */ this.ObjectRef
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Operation>} */ this.Operation
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.OpName>} */ this.OpName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.OutputPins>} */ this.OutputPins
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ParameterName>} */ this.ParameterName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.PCGNode>} */ this.PCGNode
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SoundNode>} */ this.SoundNode
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SoundWaveAssetPtr>} */ this.SoundWaveAssetPtr
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.PinNames>} */ this.PinNames
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.PinTags>} */ this.PinTags
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.PositionX>} */ this.PositionX
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.PositionY>} */ this.PositionY
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ProxyFactoryFunctionName>} */ this.ProxyFactoryFunctionName
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.ScriptVariables>} */ this.ScriptVariables
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SettingsInterface>} */ this.SettingsInterface
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SizeX>} */ this.SizeX
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SizeY>} */ this.SizeY
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.StructType>} */ this.StructType
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.SubgraphInstance>} */ this.SubgraphInstance
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.TargetType>} */ this.TargetType
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Text>} */ this.Text
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.Text>} */ this.Text
|
|
/** @type {InstanceType<typeof ObjectEntity.attributes.VariableReference>} */ this.VariableReference
|
|
|
|
// Legacy nodes pins
|
|
if (this["Pins"] instanceof ArrayEntity) {
|
|
this["Pins"].valueOf().forEach(
|
|
/** @param {ObjectReferenceEntity} objectReference */
|
|
objectReference => {
|
|
const pinObject = this[Configuration.subObjectAttributeNameFromReference(objectReference, true)]
|
|
if (pinObject) {
|
|
const pinEntity = PinEntity.fromLegacyObject(pinObject)
|
|
pinEntity.LinkedTo = new (PinEntity.attributes.LinkedTo)()
|
|
this.getCustomproperties(true).push(pinEntity)
|
|
this.CustomProperties.ignored = true
|
|
}
|
|
}
|
|
)
|
|
}
|
|
/** @type {ObjectEntity} */
|
|
const materialSubobject = this.getMaterialSubobject()
|
|
if (materialSubobject) {
|
|
const obj = materialSubobject
|
|
obj.SizeX !== undefined && (obj.SizeX.getter = () => this.NodeWidth)
|
|
obj.SizeY && (obj.SizeY.getter = () => this.NodeHeight)
|
|
obj.Text && (obj.Text.getter = () => this.NodeComment)
|
|
obj.MaterialExpressionEditorX && (obj.MaterialExpressionEditorX.getter = () => this.NodePosX)
|
|
obj.MaterialExpressionEditorY && (obj.MaterialExpressionEditorY.getter = () => this.NodePosY)
|
|
if (this.getType() === Configuration.paths.materialExpressionComponentMask) {
|
|
const rgbaPins = Configuration.rgba.map(pinName => {
|
|
const result = this.getPinEntities().find(pin => pin.PinName.toString() === pinName)
|
|
result.recomputesNodeTitleOnChange = true
|
|
return result
|
|
})
|
|
// Reorder keys so that the added ones stay first
|
|
obj.keys = [...Configuration.rgba, ...obj.keys]
|
|
const silentBool = MirroredEntity.of(BooleanEntity).withDefault().flagSilent()
|
|
obj["R"] = new silentBool(() => rgbaPins[0].DefaultValue)
|
|
obj["G"] = new silentBool(() => rgbaPins[1].DefaultValue)
|
|
obj["B"] = new silentBool(() => rgbaPins[2].DefaultValue)
|
|
obj["A"] = new silentBool(() => rgbaPins[3].DefaultValue)
|
|
} else if (this.getType() === Configuration.paths.materialExpressionSubtract) {
|
|
const silentNumber = MirroredEntity
|
|
.of(NumberEntity.withPrecision(6))
|
|
.withDefault(() => new MirroredEntity(() => new NumberEntity(1)))
|
|
.flagSilent()
|
|
const pinA = this.getCustomproperties().find(pin => pin.PinName?.toString() === "A")
|
|
const pinB = this.getCustomproperties().find(pin => pin.PinName?.toString() === "B")
|
|
if (pinA || pinB) {
|
|
// Reorder keys so that the added ones stay first
|
|
obj.keys = ["ConstA", "ConstB", ...obj.keys]
|
|
if (pinA) {
|
|
pinA.recomputesNodeTitleOnChange = true
|
|
obj.ConstA = new silentNumber(() => pinA.DefaultValue)
|
|
}
|
|
if (pinB) {
|
|
pinB.recomputesNodeTitleOnChange = true
|
|
obj.ConstB = new silentNumber(() => pinB.DefaultValue)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/** @type {ObjectEntity} */
|
|
const pcgObject = this.getPcgSubobject()
|
|
if (pcgObject) {
|
|
pcgObject.PositionX && (pcgObject.PositionX.getter = () => this.NodePosX)
|
|
pcgObject.PositionY && (pcgObject.PositionY.getter = () => this.NodePosY)
|
|
pcgObject.getSubobjects().forEach(
|
|
/** @param {ObjectEntity} obj */
|
|
obj => {
|
|
if (obj.Node !== undefined) {
|
|
const nodeRef = obj.Node.getter()
|
|
if (
|
|
nodeRef.type === this.PCGNode.type
|
|
&& nodeRef.path === `${this.Name}.${this.PCGNode.path}`
|
|
) {
|
|
obj.Node.getter = () => new ObjectReferenceEntity(
|
|
this.PCGNode.type,
|
|
`${this.Name}.${this.PCGNode.path}`,
|
|
nodeRef.full,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
}
|
|
let inputIndex = 0
|
|
let outputIndex = 0
|
|
this.getCustomproperties().forEach((pinEntity, i) => {
|
|
pinEntity.objectEntity = this
|
|
pinEntity.pinIndex = pinEntity.isInput()
|
|
? inputIndex++
|
|
: pinEntity.isOutput()
|
|
? outputIndex++
|
|
: i
|
|
})
|
|
this.mirrorNameInExportPaths()
|
|
}
|
|
|
|
/** @returns {P<ObjectEntity>} */
|
|
static createGrammar() {
|
|
return P.seq(
|
|
P.reg(/Begin +Object/),
|
|
P.seq(
|
|
P.whitespace,
|
|
P.alt(
|
|
this.createSubObjectGrammar(),
|
|
this.customPropertyGrammar,
|
|
Grammar.createAttributeGrammar(this, P.reg(Grammar.Regex.MultipleWordsSymbols)),
|
|
Grammar.createAttributeGrammar(
|
|
this,
|
|
Grammar.attributeNameQuoted,
|
|
undefined,
|
|
(values, attributeKey, attributeValue) => {
|
|
Utility.objectSet(values, [...attributeKey, "quoted"], true)
|
|
},
|
|
),
|
|
this.inlinedArrayEntryGrammar,
|
|
)
|
|
)
|
|
.map(([_0, entry]) => entry)
|
|
.many(),
|
|
P.reg(/\s+End +Object/),
|
|
)
|
|
.map(([_0, attributes, _2]) => {
|
|
const values = {}
|
|
attributes.forEach(attributeSetter => attributeSetter(values))
|
|
return new this(values)
|
|
})
|
|
.label("ObjectEntity")
|
|
}
|
|
|
|
static createSubObjectGrammar() {
|
|
return P.lazy(() => this.grammar)
|
|
.map(object =>
|
|
values => {
|
|
object.trailing = false
|
|
values[Configuration.subObjectAttributeNameFromEntity(object)] = object
|
|
}
|
|
)
|
|
}
|
|
|
|
/**
|
|
* @protected
|
|
* Mirror then name part of the objects contained in this one in ExportPath
|
|
*/
|
|
mirrorNameInExportPaths(originalName = this.Name?.toString()) {
|
|
if (!originalName) {
|
|
return
|
|
}
|
|
const values = [this]
|
|
for (let i = 0; i < values.length; ++i) {
|
|
const value = values[i]
|
|
if (value instanceof ObjectEntity) {
|
|
values.push(...Object.values(value))
|
|
if (!value.ExportPath?.valueOf().path.includes(originalName)) {
|
|
continue
|
|
}
|
|
} else {
|
|
continue
|
|
}
|
|
const mirroredEntity = /** @type {typeof ObjectEntity} */(value.constructor).attributes.ExportPath
|
|
let originalExportPath = value.ExportPath
|
|
value.ExportPath = new mirroredEntity(
|
|
() => {
|
|
const exportPath = originalExportPath.valueOf()
|
|
return new (mirroredEntity.type)(
|
|
exportPath.type,
|
|
exportPath.path.replace(originalName, this.Name?.toString() ?? ""),
|
|
exportPath.full
|
|
)
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
/** @type {String} */
|
|
#class
|
|
getClass() {
|
|
if (!this.#class) {
|
|
this.#class = (this.Class?.path ? this.Class.path : this.Class?.type)
|
|
?? this.ExportPath?.valueOf()?.type
|
|
?? ""
|
|
if (this.#class && !this.#class.startsWith("/")) {
|
|
// Old path names did not start with /Script or /Engine, check tests/resources/LegacyNodes.js
|
|
let path = Object.values(Configuration.paths).find(path => path.endsWith("." + this.#class))
|
|
if (path) {
|
|
this.#class = path
|
|
}
|
|
}
|
|
}
|
|
return this.#class
|
|
}
|
|
|
|
getType() {
|
|
const path = this.MacroGraphReference?.MacroGraph?.path
|
|
if (path) {
|
|
return path
|
|
}
|
|
if (this.MaterialExpression) {
|
|
return this.MaterialExpression.type
|
|
}
|
|
let subobject = this.getSounCueSubobject()
|
|
if (subobject) {
|
|
return subobject.getClass()
|
|
}
|
|
return this.getClass()
|
|
}
|
|
|
|
getObjectName(dropCounter = false) {
|
|
if (dropCounter) {
|
|
return this.getNameAndCounter()[0]
|
|
}
|
|
return this.Name.toString()
|
|
}
|
|
|
|
/** @returns {[String, Number]} */
|
|
getNameAndCounter() {
|
|
const result = this.getObjectName().match(ObjectEntity.#nameRegex)
|
|
let name = ""
|
|
let counter = null
|
|
return result
|
|
? [result[1] ?? "", parseInt(result[2] ?? "0")]
|
|
: ["", 0]
|
|
}
|
|
|
|
getCounter() {
|
|
return this.getNameAndCounter()[1]
|
|
}
|
|
|
|
getNodeWidth() {
|
|
return this.NodeWidth
|
|
?? this.isComment() ? Configuration.defaultCommentWidth : undefined
|
|
}
|
|
|
|
/** @param {Number} value */
|
|
setNodeWidth(value) {
|
|
if (!this.NodeWidth) {
|
|
this.NodeWidth = new IntegerEntity()
|
|
}
|
|
this.NodeWidth.value = value
|
|
}
|
|
|
|
getNodeHeight() {
|
|
return this.NodeHeight
|
|
?? this.isComment() ? Configuration.defaultCommentHeight : undefined
|
|
}
|
|
|
|
/** @param {Number} value */
|
|
setNodeHeight(value) {
|
|
if (!this.NodeHeight) {
|
|
this.NodeHeight = new IntegerEntity()
|
|
}
|
|
this.NodeHeight.value = value
|
|
}
|
|
|
|
getNodePosX() {
|
|
return this.NodePosX?.value ?? 0
|
|
}
|
|
|
|
/** @param {Number} value */
|
|
setNodePosX(value) {
|
|
if (!this.NodePosX) {
|
|
this.NodePosX = new IntegerEntity()
|
|
}
|
|
this.NodePosX.value = Math.round(value)
|
|
}
|
|
|
|
getNodePosY() {
|
|
return this.NodePosY?.value ?? 0
|
|
}
|
|
|
|
/** @param {Number} value */
|
|
setNodePosY(value) {
|
|
if (!this.NodePosY) {
|
|
this.NodePosY = new IntegerEntity()
|
|
}
|
|
this.NodePosY.value = Math.round(value)
|
|
}
|
|
|
|
getCustomproperties(canCreate = false) {
|
|
return this.CustomProperties.values
|
|
}
|
|
|
|
/** @returns {PinEntity[]} */
|
|
getPinEntities() {
|
|
return this.getCustomproperties().filter(v => v.constructor === PinEntity)
|
|
}
|
|
|
|
/** @returns {ObjectEntity[]} */
|
|
getSubobjects() {
|
|
return Object.keys(this)
|
|
.filter(k => k.startsWith(Configuration.subObjectAttributeNamePrefix))
|
|
.flatMap(k => [this[k], .../** @type {ObjectEntity} */(this[k]).getSubobjects()])
|
|
}
|
|
|
|
switchTarget() {
|
|
const switchMatch = this.getClass().match(Configuration.switchTargetPattern)
|
|
if (switchMatch) {
|
|
return switchMatch[1]
|
|
}
|
|
}
|
|
|
|
isEvent() {
|
|
switch (this.getClass()) {
|
|
case Configuration.paths.actorBoundEvent:
|
|
case Configuration.paths.componentBoundEvent:
|
|
case Configuration.paths.customEvent:
|
|
case Configuration.paths.event:
|
|
case Configuration.paths.inputAxisKeyEvent:
|
|
case Configuration.paths.inputVectorAxisEvent:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
isComment() {
|
|
switch (this.getClass()) {
|
|
case Configuration.paths.comment:
|
|
case Configuration.paths.materialGraphNodeComment:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
isMaterial() {
|
|
const classValue = this.getClass()
|
|
return classValue.startsWith("/Script/Engine.MaterialExpression")
|
|
|| classValue.startsWith("/Script/InterchangeImport.MaterialExpression")
|
|
|| classValue.startsWith("/Script/UnrealEd.MaterialGraph")
|
|
}
|
|
|
|
/** @return {ObjectEntity} */
|
|
getMaterialSubobject() {
|
|
const expression = this.MaterialExpression ?? this.MaterialExpressionComment
|
|
return expression
|
|
? this[Configuration.subObjectAttributeNameFromReference(expression, true)]
|
|
: null
|
|
}
|
|
|
|
isPcg() {
|
|
return this.getClass() == Configuration.paths.pcgEditorGraphNode || this.getPcgSubobject() != null
|
|
}
|
|
|
|
isNiagara() {
|
|
return this.Class && (this.Class.type ? this.Class.type : this.Class.path)?.startsWith("/Script/NiagaraEditor.")
|
|
}
|
|
|
|
isSoundCue() {
|
|
return this.getClass() == Configuration.paths.soundCueGraphNode
|
|
}
|
|
|
|
getBlueprintType() {
|
|
if (this.isMaterial()) {
|
|
return "MATERIAL"
|
|
}
|
|
if (this.isNiagara()) {
|
|
return "NIAGARA"
|
|
}
|
|
if (this.isPcg()) {
|
|
return "PCG Graph"
|
|
}
|
|
if (this.isSoundCue()) {
|
|
return "SOUND CUE"
|
|
}
|
|
return "BLUEPRINT"
|
|
}
|
|
|
|
/** @return {ObjectEntity} */
|
|
getPcgSubobject() {
|
|
const node = this.PCGNode
|
|
return node
|
|
? this[Configuration.subObjectAttributeNameFromReference(node, true)]
|
|
: null
|
|
}
|
|
|
|
/** @return {ObjectEntity} */
|
|
getSounCueSubobject() {
|
|
const node = this.SoundNode
|
|
return node
|
|
? this[Configuration.subObjectAttributeNameFromReference(node, true)]
|
|
: null
|
|
}
|
|
|
|
/** @return {ObjectEntity} */
|
|
getSettingsObject() {
|
|
const settings = this.SettingsInterface
|
|
return settings
|
|
? this[Configuration.subObjectAttributeNameFromReference(settings, true)]
|
|
: null
|
|
}
|
|
|
|
/** @return {ObjectEntity} */
|
|
getSubgraphObject() {
|
|
const name = this.SubgraphInstance
|
|
return name
|
|
? this[Configuration.subObjectAttributeNameFromName(name)]
|
|
: null
|
|
}
|
|
|
|
isDevelopmentOnly() {
|
|
const nodeClass = this.getClass()
|
|
return this.EnabledState?.toString() === "DevelopmentOnly"
|
|
|| nodeClass.includes("Debug", Math.max(0, nodeClass.lastIndexOf(".")))
|
|
}
|
|
|
|
getHIDAttribute() {
|
|
return this.InputKey ?? this.AxisKey ?? this.InputAxisKey
|
|
}
|
|
|
|
getDelegatePin() {
|
|
return this.getCustomproperties().find(pin => pin.PinType.PinCategory.toString() === "delegate")
|
|
}
|
|
|
|
nodeColor() {
|
|
return nodeColor(this)
|
|
}
|
|
|
|
nodeIcon() {
|
|
return nodeIcon(this)
|
|
}
|
|
|
|
additionalPinInserter() {
|
|
return nodeVariadic(this)
|
|
}
|
|
|
|
/** @param {String} key */
|
|
showProperty(key) {
|
|
switch (key) {
|
|
case "Class":
|
|
case "Name":
|
|
case "Archetype":
|
|
case "ExportPath":
|
|
case "CustomProperties":
|
|
// Serielized separately, check doWrite()
|
|
return false
|
|
}
|
|
return super.showProperty(key)
|
|
}
|
|
|
|
/** @param {typeof ObjectEntity} Self */
|
|
doSerialize(
|
|
insideString = false,
|
|
indentation = "",
|
|
Self = /** @type {typeof ObjectEntity} */(this.constructor),
|
|
printKey = Self.printKey,
|
|
keySeparator = Self.keySeparator,
|
|
attributeSeparator = Self.attributeSeparator,
|
|
wrap = Self.wrap,
|
|
) {
|
|
const isSelfOverriden = Self !== this.constructor
|
|
const deeperIndentation = indentation + Configuration.indentation
|
|
const initial_trailing = this.trailing
|
|
this.trailing = true
|
|
const content = super.doSerialize(insideString, deeperIndentation, Self, printKey, keySeparator, attributeSeparator, wrap)
|
|
this.trailing = initial_trailing
|
|
let result = indentation + "Begin Object"
|
|
+ ((this.Class?.type || this.Class?.path)
|
|
// && Self.attributes.Class.ignored !== true
|
|
// && this.Class.ignored !== true
|
|
? ` Class${keySeparator}${this.Class.serialize(insideString)}`
|
|
: ""
|
|
)
|
|
+ (this.Name
|
|
// && Self.attributes.Name.ignored !== true
|
|
// && this.Name.ignored !== true
|
|
? ` Name${keySeparator}${this.Name.serialize(insideString)}`
|
|
: ""
|
|
)
|
|
+ (this.Archetype
|
|
// && Self.attributes.Archetype.ignored !== true
|
|
// && this.Archetype.ignored !== true
|
|
? ` Archetype${keySeparator}${this.Archetype.serialize(insideString)}`
|
|
: ""
|
|
)
|
|
+ ((this.ExportPath?.valueOf()?.type || this.ExportPath?.valueOf()?.path)
|
|
// && Self.attributes.ExportPath.valueOf().ignored !== true
|
|
// && this.ExportPath.valueOf().ignored !== true
|
|
? ` ExportPath${keySeparator}${this.ExportPath.serialize(insideString)}`
|
|
: ""
|
|
)
|
|
+ attributeSeparator
|
|
+ content
|
|
+ (Self.attributes.CustomProperties.ignored !== true && this.CustomProperties.ignored !== true
|
|
? this.getCustomproperties()
|
|
.map(pin =>
|
|
deeperIndentation
|
|
+ printKey("CustomProperties ")
|
|
+ pin.serialize(insideString)
|
|
+ attributeSeparator
|
|
)
|
|
.join("")
|
|
: ""
|
|
)
|
|
+ indentation + "End Object"
|
|
+ (isSelfOverriden && Self.trailing || this.trailing ? attributeSeparator : "")
|
|
return result
|
|
}
|
|
}
|