Refactoring and bugfixing

This commit is contained in:
barsdeveloper
2021-10-24 00:17:16 +02:00
parent a34be2351e
commit f80c9f8dc1
16 changed files with 274 additions and 1396 deletions

1387
dist/ueblueprint.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,30 +0,0 @@
export default class Guid {
static generateGuid(random) {
let values = new Uint32Array(4);
if (random === true) {
crypto.getRandomValues(values)
}
let result = ""
values.forEach(n => {
result += ('00000000' + n.toString(16).toUpperCase()).slice(-8)
})
return result
}
constructor(guid) {
switch (guid?.constructor) {
case String:
this.value = guid
break
case Guid:
this.value = guid.value
break
default:
this.value = Guid.generateGuid(guid === true)
}
}
toString() {
return this.value
}
}

View File

@@ -33,6 +33,12 @@ export default class Entity {
continue
}
let defaultValue = properties[property]
if (defaultValue instanceof TypeInitialization) {
if (!defaultValue.showDefault) {
continue
}
defaultValue = defaultValue.value
}
if (defaultValue instanceof Array) {
propertySetter(target, property, [])
defineAllAttributes(
@@ -42,12 +48,6 @@ export default class Entity {
(t, _, v) => t.push(v))
continue
}
if (defaultValue instanceof TypeInitialization) {
if (!defaultValue.showDefault) {
continue
}
defaultValue = defaultValue.value
}
if (defaultValue instanceof Function) {
defaultValue = Utility.sanitize(new defaultValue())
}

37
js/entity/GuidEntity.js Normal file
View File

@@ -0,0 +1,37 @@
import Entity from "./Entity";
export default class GuidEntity extends Entity {
static attributes = {
value: String
}
static generateGuid(random) {
let values = new Uint32Array(4);
if (random === true) {
crypto.getRandomValues(values)
}
let result = ""
values.forEach(n => {
result += ('00000000' + n.toString(16).toUpperCase()).slice(-8)
})
return result
}
constructor(guid) {
if (guid?.constructor === String) {
guid = {
value: guid
}
} else if (guid?.constructor === Boolean) {
guid = {
value: GuidEntity.generateGuid(guid == true)
}
}
super(guid)
}
getAttributes() {
return GuidEntity.attributes
}
}

View File

@@ -1,6 +1,6 @@
import Entity from "./Entity"
import FunctionReferenceEntity from "./FunctionReferenceEntity"
import Guid from "../Guid"
import GuidEntity from "./GuidEntity"
import Integer from "./Integer"
import ObjectReferenceEntity from "./ObjectReferenceEntity"
import PinEntity from "./PinEntity"
@@ -18,7 +18,7 @@ export default class ObjectEntity extends Entity {
TargetType: new TypeInitialization(new ObjectReferenceEntity(), false),
NodePosX: Integer,
NodePosY: Integer,
NodeGuid: Guid,
NodeGuid: GuidEntity,
CustomProperties: [PinEntity]
}

View File

@@ -1,12 +1,14 @@
import Entity from "./Entity";
import Guid from "../Guid";
import ObjectReferenceEntity from "./ObjectReferenceEntity";
import TypeInitialization from "./TypeInitialization";
import LocalizedTextEntity from "./LocalizedTextEntity";
import Entity from "./Entity"
import GuidEntity from "./GuidEntity"
import LocalizedTextEntity from "./LocalizedTextEntity"
import ObjectReferenceEntity from "./ObjectReferenceEntity"
import TypeInitialization from "./TypeInitialization"
import PinReferenceEntity from "./PinReferenceEntity"
export default class PinEntity extends Entity {
static attributes = {
PinId: Guid,
PinId: GuidEntity,
PinName: "",
PinFriendlyName: new TypeInitialization(new LocalizedTextEntity(), false),
PinToolTip: "",
@@ -23,10 +25,10 @@ export default class PinEntity extends Entity {
bIsWeakPointer: false,
bIsUObjectWrapper: false
},
LinkedTo: Guid,
LinkedTo: [new TypeInitialization(null, false, PinReferenceEntity)],
DefaultValue: "",
AutogeneratedDefaultValue: "",
PersistentGuid: Guid,
PersistentGuid: GuidEntity,
bHidden: false,
bNotConnectable: false,
bDefaultValueIsReadOnly: false,
@@ -38,4 +40,10 @@ export default class PinEntity extends Entity {
getAttributes() {
return PinEntity.attributes
}
}
isOutput() {
if (this.Direction === "EGPD_Output") {
return true
}
}
}

View File

@@ -0,0 +1,14 @@
import Entity from "./Entity"
import GuidEntity from "./GuidEntity"
export default class PinReferenceEntity extends Entity {
static attributes = {
objectName: String,
pinGuid: GuidEntity
}
getAttributes() {
return PinReferenceEntity.attributes
}
}

View File

@@ -2,9 +2,6 @@ import Utility from "../Utility"
export default class TypeInitialization {
constructor(value, showDefault = true, type = Utility.getType(value)) {
if (type.prototype.constructor.name != value.constructor.name) {
throw new Error("Default value expected to be of the same type.")
}
this.value = value
this.showDefault = showDefault
this.type = type

View File

@@ -1,11 +1,11 @@
import Guid from "../Guid"
import GuidEntity from "./GuidEntity"
import Entity from "./Entity"
import ObjectReferenceEntity from "./ObjectReferenceEntity"
export default class VariableReferenceEntity extends Entity {
static attributes = {
MemberName: "",
MemberGuid: Guid,
MemberName: String,
MemberGuid: GuidEntity,
bSelfContext: true
}

View File

@@ -1,9 +1,3 @@
import Blueprint from "./Blueprint"
import GraphNode from "./graph/GraphNode"
import PinSerializer from "./serialization/PinSerializer"
import PinEntity from "./entity/PinEntity"
import Grammar from "./serialization/Grammar"
import ObjectReferenceEntity from "./entity/ObjectReferenceEntity"
import ObjectSerializer from "./serialization/ObjectSerialize"
export { Blueprint as UEBlueprint, GraphNode as GraphNode, PinSerializer as PinSerializer, PinEntity as PinEntity, Grammar as Grammar, ObjectReferenceEntity as ObjectReferenceEntity, ObjectSerializer as ObjectSerializer }
export { PinSerializer as PinSerializer }

View File

@@ -1,6 +1,3 @@
/**
* A Graph Entity is an element that can stay directly (as a first child) on the blueprint grid. Those entities are either nodes or links
*/
export default class GraphEntity extends HTMLElement {
/**
*

View File

@@ -1,5 +1,5 @@
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity"
import Guid from "../Guid"
import GuidEntity from "../entity/GuidEntity"
import Integer from "../entity/Integer"
import ObjectReferenceEntity from "../entity/ObjectReferenceEntity"
import Parsimmon from "parsimmon"
@@ -7,6 +7,7 @@ import PinEntity from "../entity/PinEntity"
import Utility from "../Utility"
import ObjectEntity from "../entity/ObjectEntity"
import LocalizedTextEntity from "../entity/LocalizedTextEntity"
import PinReferenceEntity from "../entity/PinReferenceEntity"
let P = Parsimmon
@@ -22,8 +23,9 @@ export default class Grammar {
Integer = _ => P.regex(/[0-9]+/).map(v => new Integer(v)).desc("an integer")
String = _ => P.regex(/(?:[^"\\]|\\")*/).wrap(P.string('"'), P.string('"')).desc('string (with possibility to escape the quote using \")')
Word = _ => P.regex(/[a-zA-Z]+/).desc("a word")
Guid = _ => P.regex(/[0-9a-zA-Z]{32}/).desc("32 digit hexadecimal (accepts all the letters for safety) value")
ReferencePath = _ => P.seq(P.string("/"), P.regex(/[0-9a-zA-Z_]+/).sepBy1(P.string(".")).tieWith("."))
Guid = _ => P.regex(/[0-9a-zA-Z]{32}/).map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal (accepts all the letters for safety) value")
PathSymbol = _ => P.regex(/[0-9a-zA-Z_]+/)
ReferencePath = _ => P.seq(P.string("/"), r.PathSymbol.sepBy1(P.string(".")).tieWith("."))
.tie()
.atLeast(2)
.tie()
@@ -49,11 +51,11 @@ export default class Grammar {
AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference, r.LocalizedText)
LocalizedText = r => P.seqMap(
P.string("NSLOCTEXT").skip(P.optWhitespace).skip(P.string("(")),
r.String.trim(P.optWhitespace),
r.String.trim(P.optWhitespace), // namespace
P.string(","),
r.String.trim(P.optWhitespace),
r.String.trim(P.optWhitespace), // key
P.string(","),
r.String.trim(P.optWhitespace),
r.String.trim(P.optWhitespace), // value
P.string(")"),
(_, namespace, __, key, ___, value, ____) => new LocalizedTextEntity({
namespace: namespace,
@@ -61,8 +63,17 @@ export default class Grammar {
value: value
})
)
static getGrammarForType(r, type, defaultGrammar) {
switch (type) {
PinReference = r => P.seqMap(
r.PathSymbol,
P.whitespace,
r.Guid,
(objectName, _, pinGuid) => new PinReferenceEntity({
objectName: objectName,
pinGuid: pinGuid
})
)
static getGrammarForType(r, attributeType, defaultGrammar) {
switch (Utility.getType(attributeType)) {
case Boolean:
return r.Boolean
case Number:
@@ -71,16 +82,34 @@ export default class Grammar {
return r.Integer
case String:
return r.String
case Guid:
case GuidEntity:
return r.Guid
case ObjectReferenceEntity:
return r.Reference
case LocalizedTextEntity:
return r.LocalizedText
case PinReferenceEntity:
return r.PinReference
case FunctionReferenceEntity:
return r.FunctionReference
case PinEntity:
return r.Pin
case Array:
return P.seqMap(
P.string("("),
attributeType
.map(v => Grammar.getGrammarForType(r, Utility.getType(v)))
.reduce((accum, cur) =>
!cur || accum === r.AttributeAnyValue
? r.AttributeAnyValue
: accum.or(cur)
)
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?\s*/)),
P.string(")"),
(_, grammar, __) => grammar
)
default:
return defaultGrammar
}
@@ -91,26 +120,10 @@ export default class Grammar {
.chain(attributeName => {
const attributeKey = attributeName.split(".")
const attribute = attributeSupplier(attributeKey)
const type = Utility.getType(attribute)
let attributeValueGrammar = type === Array
? attribute
.map(v => Grammar.getGrammarForType(r, Utility.getType(v)))
.reduce((accum, cur) =>
!cur || accum === r.AttributeAnyValue
? r.AttributeAnyValue
: accum.or(cur)
)
: Grammar.getGrammarForType(r, type, r.AttributeAnyValue)
// After the attribute name (already parsed at this point, we continue with an equal sign (possibly surrounded by whitespace) then the expected attribute value)
return attributeValueGrammar.map(attributeValue => type === Array
? entity => {
/** @type {Array} */
let array = Utility.objectGet(entity, attributeKey, [])
array.push(attributeValue)
return Utility.objectSet(entity, attributeKey, array, true)
}
: entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
) // returns attributeSetter
let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
) // returns attributeSetter: a function called with an object as argument that will set the correct attribute value
})
// Meta grammar
static CreateMultiAttributeGrammar = (r, keyGrammar, entityType, attributeSupplier) =>
@@ -156,4 +169,5 @@ export default class Grammar {
return result
}
)
MultipleObject = r => r.Object.sepBy1(P.whitespace).trim(P.optWhitespace)
}

View File

@@ -1,9 +1,9 @@
import Parsimmon from "parsimmon"
import Grammar from "./Grammar"
import Utility from "../Utility"
import TypeInitialization from "../entity/TypeInitialization"
import GuidEntity from "../entity/GuidEntity"
import ObjectReferenceEntity from "../entity/ObjectReferenceEntity"
import Guid from "../Guid"
import Parsimmon from "parsimmon"
import TypeInitialization from "../entity/TypeInitialization"
import Utility from "../Utility"
export default class Serializer {
@@ -20,7 +20,7 @@ export default class Serializer {
case Boolean:
return Utility.FirstCapital(value.toString())
case ObjectReferenceEntity:
case Guid:
case GuidEntity:
return value.toString()
case String:
return `"${value}"`

View File

@@ -1,18 +1,19 @@
import { PinEntity } from "../../dist/ueblueprint"
import Template from "./Template"
export default class NodeTemplate extends Template {
/**
* Computes the html content of the target element.
* @param {HTMLElement} element Target element
* @param {HTMLElement} entity Entity representing the element
* @returns The computed html
*/
header(element) {
header(entity) {
return `
<div class="ueb-node-header">
<span class="ueb-node-name">
<span class="ueb-node-symbol"></span>
<span class="ueb-node-text">${element.graphNodeName}</span>
<span class="ueb-node-text">${entity.graphNodeName}</span>
</span>
</div>
`
@@ -20,27 +21,30 @@ export default class NodeTemplate extends Template {
/**
* Computes the html content of the target element.
* @param {HTMLElement} element Target element
* @param {import("../entity/ObjectEntity").default} entity Entity representing the element
* @returns The computed html
*/
body(element) {
body(entity) {
let inputs = entity.CustomProperties.filter(v => v instanceof PinEntity)
let outputs = inputs.filter(v => v.isOutput())
inputs = inputs.filter(v => !v.isOutput())
return `
<div class="ueb-node-body">
<div class="ueb-node-inputs">
${element.inputs.forEach((input, index) => `
${inputs.map((input, index) => `
<div class="ueb-node-input ueb-node-value-${input.type}">
<span class="ueb-node-value-icon ${element.inputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
<span class="ueb-node-value-icon ${inputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
${input.name}
</div>
`) ?? ''}
`).join("") ?? ""}
</div>
<div class="ueb-node-outputs">
${element.outputs.forEach((output, index) => `
${outputs.map((output, index) => `
<div class="ueb-node-output ueb-node-value-${output.type}">
${output.name}
<span class="ueb-node-value-icon ${element.outputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
<span class="ueb-node-value-icon ${entity.outputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
</div>
`) ?? ''}
`).join("") ?? ''}
</div>
</div>
`
@@ -48,15 +52,15 @@ export default class NodeTemplate extends Template {
/**
* Computes the html content of the target element.
* @param {HTMLElement} element Target element
* @param {HTMLElement} entity Entity representing the element
* @returns The computed html
*/
render(element) {
render(entity) {
return `
<div class="ueb-node-border">
<div class="ueb-node-content">
${this.header(element)}
${this.body(element)}
${this.header(entity)}
${this.body(entity)}
</div>
</div>
`

View File

@@ -5,19 +5,19 @@ export default class Template {
/**
* Computes the html content of the target element.
* @param {GraphNode} element Target element
* @param {Entity} entity Entity representing the element
* @returns The computed html
*/
render(element) {
render(entity) {
return ``
}
/**
* Returns the html elements rendered by this template.
* @param {GraphNode} element Target element
* @param {GraphNode} entity Entity representing the element
* @returns The rendered elements
*/
getElements(element) {
getElements(entity) {
let aDiv = document.createElement('div')
aDiv.innerHTML = this.render(element)
return aDiv.childNodes

View File

@@ -14,17 +14,13 @@
<body>
<div>Hello</div>
<script type="module">
import { UEBlueprint, GraphNode, PinSerializer, PinEntity, Grammar, ObjectReferenceEntity, ObjectSerializer } from "./dist/ueblueprint.js"
let pinEparsed = PinSerializer.grammar.Object.parse(`Begin Object Class=/Script/BlueprintGraph.K2Node_DynamicCast Name="K2Node_DynamicCast_0"
NodePosX=2176
NodePosY=1696
NodeGuid=D3C8BC0942D76371537C2F9627104734
End Object`)
let blueprint = new UEBlueprint()
import { PinSerializer } from "./dist/ueblueprint.js"
let pinEparsed = PinSerializer.grammar.Pin.parse(`Pin (PinId=DB96A96142631A1B113BC69C8B77B9BD,PinName="ReturnValue",PinToolTip="Return Value\nString\n\nReturns the string name of the current platform, to perform different behavior based on platform.\n(Platform names include Windows, Mac, IOS, Android, PS4, XboxOne, Linux)",Direction="EGPD_Output",PinType.PinCategory="string",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CommutativeAssociativeBinaryOperator_1 22257AFF4730E84DE3EF0DBA7A92E1EE,K2Node_CommutativeAssociativeBinaryOperator_1 81E183294B6CBC122C5E88A8C37F13A3,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)`)
//let blueprint = new UEBlueprint()
let node0 = new GraphNode(); node0.setLocation([985, 393]); let node1 = new GraphNode(); node1.setLocation([999, 114]); let node2 = new GraphNode(); node2.setLocation([811, 253]); let node3 = new GraphNode(); node3.setLocation([802, 146]); let node4 = new GraphNode(); node4.setLocation([597, 105]); let node5 = new GraphNode(); node5.setLocation([789, 233]); let node6 = new GraphNode(); node6.setLocation([549, 289]); let node7 = new GraphNode(); node7.setLocation([678, 193]); let node8 = new GraphNode(); node8.setLocation([1078, 244]); let node9 = new GraphNode(); node9.setLocation([751, 151]); let node10 = new GraphNode(); node10.setLocation([1046, -14]); let node11 = new GraphNode(); node11.setLocation([714, 267]); let node12 = new GraphNode(); node12.setLocation([767, 36]); let node13 = new GraphNode(); node13.setLocation([807, 219]); let node14 = new GraphNode(); node14.setLocation([1031, 70]); let node15 = new GraphNode(); node15.setLocation([906, 389]); let node16 = new GraphNode(); node16.setLocation([936, 131]); let node17 = new GraphNode(); node17.setLocation([689, 249]); let node18 = new GraphNode(); node18.setLocation([1153, 343]); let node19 = new GraphNode(); node19.setLocation([626, 209]); blueprint.addNode(node0, node1, node2, node3, node4, node5, node6, node7, node8, node9, node10, node11, node12, node13, node14, node15, node16, node17, node18, node19);
//let node0 = new GraphNode(); node0.setLocation([985, 393]); let node1 = new GraphNode(); node1.setLocation([999, 114]); let node2 = new GraphNode(); node2.setLocation([811, 253]); let node3 = new GraphNode(); node3.setLocation([802, 146]); let node4 = new GraphNode(); node4.setLocation([597, 105]); let node5 = new GraphNode(); node5.setLocation([789, 233]); let node6 = new GraphNode(); node6.setLocation([549, 289]); let node7 = new GraphNode(); node7.setLocation([678, 193]); let node8 = new GraphNode(); node8.setLocation([1078, 244]); let node9 = new GraphNode(); node9.setLocation([751, 151]); let node10 = new GraphNode(); node10.setLocation([1046, -14]); let node11 = new GraphNode(); node11.setLocation([714, 267]); let node12 = new GraphNode(); node12.setLocation([767, 36]); let node13 = new GraphNode(); node13.setLocation([807, 219]); let node14 = new GraphNode(); node14.setLocation([1031, 70]); let node15 = new GraphNode(); node15.setLocation([906, 389]); let node16 = new GraphNode(); node16.setLocation([936, 131]); let node17 = new GraphNode(); node17.setLocation([689, 249]); let node18 = new GraphNode(); node18.setLocation([1153, 343]); let node19 = new GraphNode(); node19.setLocation([626, 209]); blueprint.addNode(node0, node1, node2, node3, node4, node5, node6, node7, node8, node9, node10, node11, node12, node13, node14, node15, node16, node17, node18, node19);
document.querySelector('body').appendChild(blueprint)
//document.querySelector('body').appendChild(blueprint)
</script>
<script type="module">
/*