Files
AncientCivil/Content/JavaScript/PuertsEditor/UEMeta.js
T
2025-02-10 00:44:11 +08:00

1492 lines
67 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const UE = require("ue");
const ts = require("typescript");
/**
* @brief the specifier read from the decorator
*/
class MetaSpecifier {
/**
* the constructor
* @param specifier
* @param values
* @returns
*/
constructor(specifier, values) {
/**
* the identity of the specifier
*/
this.Specifier = "";
this.Specifier = specifier;
this.Values = values;
}
/**
* apply the specifier to the meta data, return if the specifier is consumed
* null indicate the specifier is invalid in call context
* this function should be called when parse the meta data defined via umeta
* @param metaData
*/
ApplyInMeta(metaData) {
// for specifier used in meta, only meta key and meta key value is valid
if (this.Specifier == '' || (this.Values != null && this.Values.length != 1)) {
return null;
}
// the meta data set via umeta, we only treat it as key value pair
metaData.set(this.Specifier, this.Values == null ? '' : this.Values[0]);
return true;
}
/**
* apply the specifier to the meta data, return if the specifier is consumed
* this function should be called when parse the meta data defined via prefix e.g uclass/ufunction
* @param metaData
*/
ApplyInIdentity(metaData) {
if (this.Specifier == '') {
return null;
}
if (!MetaSpecifier.CommonMetaData.has(this.Specifier)) { // unknown specifier, need context to parse, don't do here
return false;
}
if (!MetaSpecifier.CommonMetaData.get(this.Specifier).call(null, this, metaData)) { // we know the specifier is invalid for specific key
return null;
}
return true;
}
/**
* check if the specifier is meta key
*/
IsMetaKey() {
return this.Values == null;
}
/**
* check if the specifier is meta key value
* @returns
*/
IsMetaKeyValue() {
return this.Values != null && this.Values.length == 1;
}
/**
* check if the specifier is meta key values
* @returns
*/
IsMetaKeyValues() {
return this.Values != null;
}
}
/**
* the common meta data, the behavior is sync with unreal engine 5.0 early preview
*/
MetaSpecifier.CommonMetaData = new Map([
["DisplayName", (specifier, metaData) => {
if (specifier.IsMetaKeyValue()) {
metaData.set("DisplayName", specifier.Values[0]);
return true;
}
return false;
}],
["FriendlyName", (specifier, metaData) => {
if (specifier.IsMetaKeyValue()) {
metaData.set("FriendlyName", specifier.Values[0]);
return true;
}
return false;
}],
["BlueprintInternalUseOnly", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("BlueprintInternalUseOnly", 'true');
metaData.set("BlueprintType", 'true');
return true;
}
return false;
}],
["BlueprintType", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("BlueprintType", 'true');
return true;
}
return false;
}],
["NotBlueprintType", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("NotBlueprintType", 'true');
metaData.delete('BlueprintType');
return true;
}
return false;
}],
["Blueprintable", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("IsBlueprintBase", 'true');
metaData.set("BlueprintType", 'true');
return true;
}
return false;
}],
["CallInEditor", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("CallInEditor", 'true');
return true;
}
return false;
}],
["NotBlueprintable", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("IsBlueprintBase", 'false');
metaData.delete("BlueprintType");
return true;
}
return false;
}],
["Category", (specifier, metaData) => {
if (specifier.IsMetaKeyValue()) {
metaData.set("Category", specifier.Values[0]);
return true;
}
return false;
}],
["Experimental", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("DevelopmentStatus", "Experimental");
return true;
}
return false;
}],
["EarlyAccessPreview", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("DevelopmentStatus", "EarlyAccessPreview");
return true;
}
return false;
}],
["DocumentationPolicy", (specifier, metaData) => {
if (specifier.IsMetaKey()) {
metaData.set("DocumentationPolicy", 'Strict');
return true;
}
return false;
}],
["SparseClassDataType", (specifier, metaData) => {
if (specifier.IsMetaKeyValue()) {
metaData.set("SparseClassDataType", specifier.Values[0]);
return true;
}
return false;
}]
]);
;
/**
* a helper function used to extract the meta key from an expression
* @param expression
* @param prefix
* @param regExp
* @returns
*/
function extractMetaSpecifierFromExpression(expression, prefix, regExp) {
const execRegExp = regExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : regExp;
const execResult = execRegExp.exec(expression.getText().trim());
if (execResult == null) { // should capture the result
return null;
}
return new MetaSpecifier(execResult[1]);
}
/**
* a helper function used to extract the meta key value from an expression
* @param expression
* @param prefix
* @param regExp
* @returns
*/
function extractMetaSpecifierFromBinaryExpression(expression, prefix, regExp) {
const execRegExp = regExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : regExp;
const execResult = execRegExp.exec(expression.left.getText().trim());
if (execResult == null) {
return null;
}
let values = new Array();
if (ts.isStringLiteral(expression.right)) { // specifier = value
values.push(expression.right.text);
}
else if (ts.isArrayLiteralExpression(expression.right)) { // specifier = [value1, value2, value3]
let bValid = true;
expression.right.elements.forEach((value) => {
if (!bValid) {
return;
}
if (!ts.isStringLiteral(value)) {
bValid = false;
return;
}
values.push(value.text);
});
if (!bValid) {
return null;
}
}
else { // invalid format
return null;
}
return new MetaSpecifier(execResult[1], values);
}
/**
* collect the meta data from the prefix section, @see ObjectMacros.h namespace uc,
* for meta data defined in umeta section, all kinds of meta data are valid
* @param expressions
* @param prefix
* @param specifiers
* @param metaData
* @param keyRegExp
* @param keyValueRegExp
*/
function collectMetaDataFromIdentifyDecorator(expressions, prefix, specifiers, metaData, keyRegExp, keyValueRegExp) {
const MetaKeyValueRegExp = keyValueRegExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : keyValueRegExp;
const MetaKeyRegExp = keyRegExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : keyRegExp;
expressions.forEach((value) => {
let metaSpecifier;
if (ts.isBinaryExpression(value)) { // should be the meta key value or , ${prefix}.identifier = (value);
metaSpecifier = extractMetaSpecifierFromBinaryExpression(value, prefix, MetaKeyValueRegExp);
}
else { // should be the meta key
metaSpecifier = extractMetaSpecifierFromExpression(value, prefix, MetaKeyRegExp);
}
if (metaSpecifier == null) {
console.warn(`the ${prefix}: ${value.getFullText()} is not valid meta data`);
return;
}
const applyResult = metaSpecifier.ApplyInIdentity(metaData);
if (applyResult == null) {
console.warn(`the ${prefix}: ${value.getFullText()} is not valid meta data`);
}
else if (applyResult == false) { // unknown specifier currently
specifiers.push(metaSpecifier);
}
});
}
/**
* collect the meta data from the umeta section, @see ObjectMacros.h namespace um,
* for meta data defined in umeta section, only key or key value is legal
* @param expressions
* @param prefix
* @param specifiers
* @param metaData
* @param keyRegExp
* @param keyValueRegExp
*/
function collectMetaDataFromMetaDecorator(expressions, prefix, specifiers, metaData, keyRegExp, keyValueRegExp) {
const MetaKeyValueRegExp = keyValueRegExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : keyValueRegExp;
const MetaKeyRegExp = keyRegExp == null ? new RegExp(`^${prefix}\.([A-Za-z]+)$`) : keyRegExp;
expressions.forEach((value) => {
let metaSpecifier;
if (ts.isBinaryExpression(value)) { // should be the meta key value or , ${prefix}.identifier.assign(value);
metaSpecifier = extractMetaSpecifierFromBinaryExpression(value, prefix, MetaKeyValueRegExp);
}
else { // should be the meta key
metaSpecifier = extractMetaSpecifierFromExpression(value, prefix, MetaKeyRegExp);
}
if (metaSpecifier == null) {
console.warn(`the umeta: ${value.getFullText()} is not valid meta data`);
return;
}
const applyResult = metaSpecifier.ApplyInMeta(metaData);
if (applyResult == null) {
console.warn(`the umeta: ${value.getFullText()} is not valid meta data`);
}
else if (applyResult == false) { // unknown specifier currently, this should never happen
console.warn(`logic error: umeta data should never be unrecognized`);
}
});
}
/**
* collect the meta data from a specific decorator, the format of decorator @see getMetaDataFromDecorators
* @param decorator
* @param prefix
* @param specifiers
* @param metaData
*/
function collectMetaDataFromDecorator(decorator, prefix, specifiers, metaData) {
let expression = decorator.expression;
if (!ts.isCallExpression(expression)) {
return;
}
const expressionText = expression.expression.getFullText(); // get the callable signature
// should use cache to hold the reg exp object ?
if (new RegExp(`^${prefix}\.${prefix}$`).test(expressionText)) { // the decorator match @prefix.prefix
collectMetaDataFromIdentifyDecorator(expression.arguments, prefix, specifiers, metaData);
}
else if (new RegExp(`^${prefix}\.umeta$`).test(expressionText)) { // the decorator match @prefix.umeta
collectMetaDataFromMetaDecorator(expression.arguments, prefix, specifiers, metaData);
}
}
/**
* extract meta data from specific decorators, the format of the decorators follows:
* 1. @${prefix}.${prefix}(meta1, ...), e.g, @uclass.uclass(meta1, meta2, meta3...)
* 2. @${prefix}.umeta(meta1, ...), e.g, @uclass.umeta(meta1, meta2, meta3)
* the meta data has there formats, the values used in meta data should be string literals
* 1. ${prefix}.{identifier}, e.g, @uclass.editinlinenew, this is a meta data key, put its name in array result
* 2. ${prefix}.{identifier}.assign({value}) e.g, @uclass.DisplayName.assign("name") this is a meta data key value, put its key and value in map result
* 3. ${prefix}.{Identifier}.assign{{value1}, ... } e.g, @uclass.hideCategories.assign("a", 'b') this is a meta data key values, the values will pack into a string
* @param decorators
* @param prefix
*/
function getMetaDataFromDecorators(decorators, prefix) {
let specifiers = new Array();
let metaData = new Map();
if (decorators == null) {
return [specifiers, metaData];
}
decorators.forEach((value) => {
collectMetaDataFromDecorator(value, prefix, specifiers, metaData);
});
return [specifiers, metaData];
}
/**
* process the specifiers specific to the class
* @param specifiers
* @param metaData
*/
function processClassMetaData(specifiers, metaData) {
let bValidSpecifiers = true;
let InvalidSpecifier;
let bWantsPlacable = false;
let ClassFlags = UE.ClassFlags.CLASS_None;
let WithIn = "";
let ConfigName = "";
let ShowCategories = new Set();
let HideCategories = new Set();
let ShowSubCategories = new Set();
let HideFunctions = new Set();
let ShowFunctions = new Set();
let AutoExpandCategories = new Set();
let AutoCollapseCategories = new Set();
let DontAutoCollapseCategories = new Set();
let ClassGroupNames = new Set();
let SparseClassDataTypes = new Set();
/**
* a helper function used to mark process error information
* @param specifier
*/
function markInvalidSpecifier(specifier) {
bValidSpecifiers = false;
InvalidSpecifier = specifier;
}
/**
* parse single meta specifier
* @param value
*/
function parseClassMetaSpecifier(value) {
if (!bValidSpecifiers) {
return;
}
switch (value.Specifier.toLowerCase()) {
case 'NoExport'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_NoExport;
break;
case 'Intrinsic'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_Intrinsic;
break;
case 'ComponentWrapperClass'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
metaData.set('IgnoreCategoryKeywordsInSubclasses', 'true');
break;
case 'Within'.toLowerCase():
if (!value.IsMetaKeyValue()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
WithIn = value.Values[0];
break;
case 'EditInlineNew'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_EditInlineNew;
break;
case 'NotEditInlineNew'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags & ~UE.ClassFlags.CLASS_EditInlineNew;
break;
case 'Placeable'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
bWantsPlacable = true;
ClassFlags = ClassFlags & ~UE.ClassFlags.CLASS_NotPlaceable;
break;
case 'DefaultToInstanced'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_DefaultToInstanced;
break;
case 'NotPlaceable'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_NotPlaceable;
break;
case 'HideDropdown'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_HideDropDown;
break;
case 'DependsOn'.toLowerCase():
console.log('currently depend on meta data specifier is not supported');
break;
case 'MinimalAPI'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_MinimalAPI;
break;
case 'Const'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_Const;
break;
case 'PerObjectConfig'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_PerObjectConfig;
break;
case 'ConfigDoNotCheckDefaults'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_ConfigDoNotCheckDefaults;
break;
case 'Abstract'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_Abstract;
break;
case 'Deprecated'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_Deprecated;
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_NotPlaceable;
break;
case 'Transient'.toLowerCase():
if (!value.IsMetaKey()) { // should be the meta key
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_Transient;
break;
case 'NonTransient'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags & ~UE.ClassFlags.CLASS_Transient;
break;
case 'CustomConstructor'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_CustomConstructor;
break;
case 'Config'.toLowerCase():
if (!value.IsMetaKeyValue()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ConfigName = value.Values[0];
break;
case 'DefaultConfig'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_DefaultConfig;
break;
case 'GlobalUserConfig'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_GlobalUserConfig;
break;
case 'ProjectUserConfig'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_ProjectUserConfig;
break;
case 'ShowCategories'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => { ShowCategories.add(value); });
break;
case 'HideCategories'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => { HideCategories.add(value); });
break;
case 'ShowFunctions'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => { ShowFunctions.add(value); });
break;
case 'HideFunctions'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => { HideFunctions.add(value); });
break;
case 'SparseClassDataTypes'.toLowerCase():
if (!value.IsMetaKeyValue()) { // currently only one sparse class data type is supported
return markInvalidSpecifier(`${value.Specifier}`);
}
SparseClassDataTypes.add(value.Values[0]);
break;
case 'ClassGroup'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => { ClassGroupNames.add(value); });
break;
case 'AutoExpandCategories'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => {
AutoCollapseCategories.delete(value);
AutoExpandCategories.add(value);
});
break;
case 'AutoCollapseCategories'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => {
AutoExpandCategories.delete(value);
AutoCollapseCategories.add(value);
});
break;
case 'DontAutoCollapseCategories'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
value.Values.forEach((value) => {
AutoCollapseCategories.delete(value);
});
break;
case 'CollapseCategories'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags | UE.ClassFlags.CLASS_CollapseCategories;
break;
case 'DontCollapseCategories'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
ClassFlags = ClassFlags & ~UE.ClassFlags.CLASS_CollapseCategories;
break;
case 'AdvancedClassDisplay'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
metaData.set('AdvancedClassDisplay', 'true');
break;
case 'ConversionRoot'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSpecifier(`${value.Specifier}`);
}
metaData.set('IsConversionRoot', 'true');
break;
default:
markInvalidSpecifier(`${value.Specifier}`);
break;
}
}
/**
* @brief
* function body
*/
specifiers.forEach((value) => {
parseClassMetaSpecifier(value);
});
if (!bValidSpecifiers) {
console.warn(`invalid specifier for uclass: ${InvalidSpecifier}`);
return null;
}
let metaDataResult = new UE.PEClassMetaData();
// fill data to the class meta data structure
metaDataResult.SetClassFlags(ClassFlags, bWantsPlacable);
metaData.forEach((value, key) => { metaDataResult.SetMetaData(key, value); });
metaDataResult.SetClassWithIn(WithIn);
metaDataResult.SetConfig(ConfigName);
HideCategories.forEach((value) => { metaDataResult.AddHideCategory(value); });
ShowCategories.forEach((value) => { metaDataResult.AddShowCategory(value); });
ShowSubCategories.forEach((value) => { metaDataResult.AddShowSubCategory(value); });
HideFunctions.forEach((value) => { metaDataResult.AddHideFunction(value); });
ShowFunctions.forEach((value) => { metaDataResult.AddShowFunction(value); });
AutoExpandCategories.forEach((value) => { metaDataResult.AddAutoExpandCategory(value); });
AutoCollapseCategories.forEach((value) => { metaDataResult.AddAutoCollapseCategory(value); });
DontAutoCollapseCategories.forEach((value) => { metaDataResult.AddDontAutoCollapseCategory(value); });
ClassGroupNames.forEach((value) => { metaDataResult.AddClassGroup(value); });
SparseClassDataTypes.forEach((value) => { metaDataResult.AddSparseDataType(value); });
return metaDataResult;
}
/**
* process the meta data, some validation should do with owner class, for simplicity, we ignore it here
* @param specifiers
* @param metaData
* @returns
*/
function processFunctionMetaData(specifiers, metaData) {
let bValidSpecifiers = true;
let InvalidMessage;
let FunctionFlags = BigInt(UE.FunctionFlags.FUNC_None);
let FunctionExportFlags = 0n; // BigInt(UE.FunctionExportFlags.FUNCEXPORT_Final);
let bSpecifiedUnreliable = false;
let bSawPropertyAccessor = false;
let bSealedEvent = false;
let RPCId = 0;
let RPCResponseId = 0;
let EndpointName = '';
let bForceBlueprintImpure = false;
let CppValidationImplName = '';
let CppImpName = '';
let bAutomaticallyFinal = true;
/**
* a helper function used to mark the meta data is invalid
* @param reason
*/
function markInvalidSince(reason) {
bValidSpecifiers = false;
InvalidMessage = reason;
}
/**
* a helper function used parse the net service identifier
* @param InIdentifiers
*/
function parseNetServiceIdentifiers(InIdentifiers) {
const IdTag = "Id";
const ResponseIdTag = "ResponseId";
const JSBridgePriTag = "Priority";
let bResult = true;
InIdentifiers.forEach((value) => {
if (!bResult) {
return;
}
if (value.indexOf('=') != -1) { // a tag with an argument
let TagAndArgument = value.split('=');
if (TagAndArgument.length != 2) {
return markInvalidSince(`Invalid format for net service identifers: ${value}`);
}
let Argument = parseInt(TagAndArgument[1]);
if (Number.isNaN(Argument) || Argument < 0 || Argument > (1 << 16)) {
return markInvalidSince(`Invalid network identifier ${value} for function`);
}
if (TagAndArgument[0] == IdTag) {
RPCId = Argument;
return;
}
if (TagAndArgument[0] == ResponseIdTag || TagAndArgument[0] == JSBridgePriTag) {
RPCResponseId = Argument;
return;
}
}
else { // an endpoint name
if (EndpointName.length != 0) {
bResult = false;
return markInvalidSince(`Function should not specify multiple endpoints - '${value}' found but already using '${EndpointName}'`);
}
EndpointName = value;
}
});
return bResult;
}
/**
* a helper function used to parse teh meta specifier
* @param value
*/
function parseFunctionMetaSpecifier(value) {
if (!bValidSpecifiers) {
return;
}
switch (value.Specifier.toLowerCase()) {
case 'BlueprintNativeEvent'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince('BlueprintNativeEvent should be meta key');
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Net)) {
return markInvalidSince('BlueprintNativeEvent functions cannot be replicated!');
}
if ((FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) && !(FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Native))) {
return markInvalidSince('A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!');
}
if (bSawPropertyAccessor) {
return markInvalidSince("A function cannot be both BlueprintNativeEvent and a Blueprint Property accessor!");
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Event);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintEvent);
break;
case 'BlueprintImplementableEvent'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Net)) {
return markInvalidSince('BlueprintImplementableEvent functions cannot be replicated!');
}
if ((FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) && (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Native))) {
return markInvalidSince('A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!');
}
if (bSawPropertyAccessor) {
return markInvalidSince('A function cannot be both BlueprintImplementableEvent and a Blueprint Property accessor!');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Event);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintEvent);
FunctionFlags &= ~BigInt(UE.FunctionFlags.FUNC_Native);
break;
case 'Exec'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Net)) {
return markInvalidSince('Exec functions cannot be replicated!');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Exec);
break;
case 'SealedEvent'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
bSealedEvent = true;
break;
case 'Server'.toLowerCase():
if (!value.IsMetaKey() && !value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
return markInvalidSince('BlueprintImplementableEvent or BlueprintNativeEvent functions cannot be declared as Client or Server');
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Exec)) {
return markInvalidSince('Exec functions cannot be replicated!');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Net);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetServer);
if (value.IsMetaKeyValue()) {
CppImpName = value.Values[0];
}
break;
case 'Client'.toLowerCase():
if (!value.IsMetaKey() && !value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
return markInvalidSince('BlueprintImplementableEvent or BlueprintNativeEvent functions cannot be declared as Client or Server');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Net);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetClient);
if (value.IsMetaKeyValue()) {
CppImpName = value.Values[0];
}
break;
case 'NetMulticast'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
return markInvalidSince('BlueprintImplementableEvent or BlueprintNativeEvent functions cannot be declared as Multicast');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Net);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetMulticast);
break;
case 'ServiceRequest'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSince(`${value.Specifier} should be meta values`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
return markInvalidSince('BlueprintImplementableEvent or BlueprintNativeEvent functions cannot be declared as a ServiceRequest');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Net);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetReliable);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetRequest);
FunctionExportFlags |= BigInt(UE.FunctionExportFlags.FUNCEXPORT_CustomThunk);
parseNetServiceIdentifiers(value.Values);
if (bValidSpecifiers && EndpointName.length == 0) {
markInvalidSince('ServiceRequest needs to specify an endpoint name');
}
break;
case 'ServiceResponse'.toLowerCase():
if (!value.IsMetaKeyValues()) {
return markInvalidSince(`${value.Specifier} should be meta values`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
return markInvalidSince('BlueprintImplementableEvent or BlueprintNativeEvent functions cannot be declared as a ServiceResponse');
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Net);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetReliable);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetResponse);
parseNetServiceIdentifiers(value.Values);
if (bValidSpecifiers && EndpointName.length == 0) {
markInvalidSince('ServiceResponse needs to specify an endpoint name');
}
break;
case 'Reliable'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetReliable);
break;
case 'Unreliable'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
bSpecifiedUnreliable = true;
break;
case 'CustomThunk'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
FunctionExportFlags |= BigInt(UE.FunctionExportFlags.FUNCEXPORT_CustomThunk);
break;
case 'BlueprintCallable'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintCallable);
break;
case 'BlueprintGetter'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Event)) {
return markInvalidSince(`Function cannot be a blueprint event and a blueprint getter.`);
}
bSawPropertyAccessor = true;
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintCallable);
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintPure);
metaData.set("BlueprintGetter", "");
break;
case 'BlueprintSetter'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Event)) {
return markInvalidSince(`Function cannot be a blueprint event and a blueprint setter.`);
}
bSawPropertyAccessor = true;
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintCallable);
metaData.set("BlueprintSetter", "");
break;
case 'BlueprintPure'.toLowerCase():
{
if (!value.IsMetaKey() && !value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be meta key or meta value`);
}
let bPure = true;
if (value.IsMetaKeyValue()) {
bPure = value.Values[0].toLowerCase() == 'true';
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintCallable);
if (bPure) {
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintPure);
}
else {
bForceBlueprintImpure = true;
}
break;
}
case 'BlueprintAuthorityOnly'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintAuthorityOnly);
break;
case 'BlueprintCosmetic'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be meta key`);
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_BlueprintCosmetic);
break;
case 'WithValidation'.toLowerCase():
if (!value.IsMetaKey() && !value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be meta key or meta value`);
}
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_NetValidate);
if (value.IsMetaKeyValue()) {
CppValidationImplName = value.Values[0];
}
break;
default:
markInvalidSince(`${value.Specifier} is not a valid specifier`);
break;
}
}
/**
* a helper function used to valid the function flags
*/
function validateFunctionFlags() {
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Net)) {
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Event);
const bIsNetService = !!(FunctionFlags & (BigInt(UE.FunctionFlags.FUNC_NetRequest) | BigInt(UE.FunctionFlags.FUNC_NetResponse)));
const bIsNetReliable = !!(FunctionFlags & BigInt(UE.FunctionFlags.FUNC_NetReliable));
// replated function
// 1. not static
// 2. reliable / unreliable should be specified, but never both
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Static)) {
return markInvalidSince("Static functions can't be replicated");
}
if (!bIsNetReliable && !bSpecifiedUnreliable && !bIsNetService) {
return markInvalidSince("Replicated function: 'reliable' or 'unreliable' is required");
}
if (bIsNetReliable && bSpecifiedUnreliable && !bIsNetService) {
return markInvalidSince("'reliable' and 'unreliable' are mutually exclusive");
}
}
else if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_NetReliable)) // only net function could mark reliable or unreliable
{
return markInvalidSince("'reliable' specified without 'client' or 'server'");
}
else if (bSpecifiedUnreliable) {
return markInvalidSince("'unreliable' specified without 'client' or 'server'");
}
if (bSealedEvent && !(FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Event))) // sealed event could only used on events
{
return markInvalidSince("SealedEvent may only be used on events");
}
// blueprint event could not be sealed
if (bSealedEvent && (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent))) {
return markInvalidSince("SealedEvent cannot be used on Blueprint events");
}
if (bForceBlueprintImpure && (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintPure))) {
return markInvalidSince("BlueprintPure (or BlueprintPure=true) and BlueprintPure=false should not both appear on the same function, they are mutually exclusive");
}
// set custom thunk meta data
if ((FunctionExportFlags & BigInt(UE.FunctionExportFlags.FUNCEXPORT_CustomThunk)) && !metaData.has("CustomThunk")) {
metaData.set("CustomThunk", 'true');
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_Net)) {
bAutomaticallyFinal = false;
}
if (FunctionFlags & BigInt(UE.FunctionFlags.FUNC_BlueprintEvent)) {
bAutomaticallyFinal = false;
}
if (bAutomaticallyFinal || bSealedEvent) {
FunctionFlags |= BigInt(UE.FunctionFlags.FUNC_Final);
FunctionExportFlags != BigInt(UE.FunctionExportFlags.FUNCEXPORT_Final);
}
}
/**
* @brief
* function body
*/
if (metaData.has("CppFromBpEvent")) {
FunctionFlags = FunctionFlags | BigInt(UE.FunctionFlags.FUNC_Event);
}
specifiers.forEach((value) => {
parseFunctionMetaSpecifier(value);
});
if (bValidSpecifiers) {
validateFunctionFlags();
}
if (!bValidSpecifiers) {
console.warn(`invalid meta data for ufunction: ${InvalidMessage}`);
return null;
}
let metaDataResult = new UE.PEFunctionMetaData();
metaDataResult.SetFunctionFlags(Number(FunctionFlags >> 32n), Number(FunctionFlags & 0xffffffffn));
metaDataResult.SetFunctionExportFlags(Number(FunctionExportFlags));
metaData.forEach((value, key) => { metaDataResult.SetMetaData(key, value); });
metaDataResult.SetCppImplName(CppImpName);
metaDataResult.SetCppValidationImplName(CppValidationImplName);
metaDataResult.SetEndpointName(EndpointName);
metaDataResult.SetRPCId(RPCId);
metaDataResult.SetRPCResponseId(RPCResponseId);
metaDataResult.SetIsSealedEvent(bSealedEvent);
metaDataResult.SetForceBlueprintImpure(bForceBlueprintImpure);
return metaDataResult;
}
/**
* process the meta data of function parameters
* @param specifiers
* @param metaData
*/
function processParamMetaData(specifiers, metaData) {
let bValidSpecifiers = true;
let InvalidMessage;
let PropertyFlags = BigInt(UE.PropertyFlags.CPF_None);
/**
* a helper function used to mark the meta data is invalid
* @param reason
*/
function markInvalidSince(reason) {
bValidSpecifiers = false;
InvalidMessage = reason;
}
/**
* a helper function used to parse the meta specifier
* @param value
*/
function parseParamMetaSpecifier(value) {
if (!bValidSpecifiers) {
return;
}
switch (value.Specifier.toLowerCase()) {
case 'Const'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_ConstParm);
break;
case 'Ref'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_OutParm) | BigInt(UE.PropertyFlags.CPF_ReferenceParm));
break;
case 'NotReplicated'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_RepSkip));
break;
default:
markInvalidSince(`${value.Specifier} is not a valid specifier`);
break;
}
}
/**
* @brief
* function body
*/
specifiers.forEach((value) => {
parseParamMetaSpecifier(value);
});
if (!bValidSpecifiers) {
console.warn(`invalid meta data for uparam: ${InvalidMessage}`);
return null;
}
let metaDataResult = new UE.PEParamMetaData();
metaDataResult.SetParamFlags(Number(PropertyFlags << 32n), Number(PropertyFlags & 0xffffffffn));
metaData.forEach((value, key) => { metaDataResult.SetMetaData(key, value); });
return metaDataResult;
}
/**
* process the meta data of the property
* @param specifiers
* @param metaData
* @returns
*/
function processPropertyMetaData(specifiers, metaData) {
let bValidSpecifiers = true;
let InvalidMessage;
let PropertyFlags = BigInt(UE.PropertyFlags.CPF_None);
let ImpliedPropertyFlags = BigInt(UE.PropertyFlags.CPF_None);
let bSeenEditSpecifier = false;
let bSeenBlueprintWriteSpecifier = false;
let bSeenBlueprintReadOnlySpecifier = false;
let bSeenBlueprintGetterSpecifier = false;
let RepCallbackName;
/**
* a helper function used to mark the meta data is invalid
* @param reason
*/
function markInvalidSince(reason) {
bValidSpecifiers = false;
InvalidMessage = reason;
}
/**
* a helper function used to parse the meta specifier
* @param value
*/
function parsePropertyMetaSpecifier(value) {
if (!bValidSpecifiers) {
return;
}
switch (value.Specifier.toLowerCase()) {
case 'EditAnywhere'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_Edit);
bSeenEditSpecifier = true;
break;
case 'EditInstanceOnly'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_DisableEditOnTemplate));
bSeenEditSpecifier = true;
break;
case 'EditDefaultsOnly'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_DisableEditOnInstance));
bSeenEditSpecifier = true;
break;
case 'VisibleAnywhere'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_EditConst));
bSeenEditSpecifier = true;
break;
case `VisibleInstanceOnly`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_EditConst) | BigInt(UE.PropertyFlags.CPF_DisableEditOnTemplate));
bSeenEditSpecifier = true;
break;
case 'VisibleDefaultOnly'.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenEditSpecifier) {
return markInvalidSince(`found more than one edit/visibility specifier ${value.Specifier}, only one is allowed`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_EditConst) | BigInt(UE.PropertyFlags.CPF_DisableEditOnInstance));
bSeenEditSpecifier = true;
break;
case `BlueprintReadWrite`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenBlueprintReadOnlySpecifier) {
return markInvalidSince(`cannot specify a property as being both BlueprintReadOnly and BlueprintReadWrite`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintVisible);
bSeenBlueprintWriteSpecifier = true;
break;
case `BlueprintSetter`.toLowerCase():
if (!value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be a meta key value`);
}
if (bSeenBlueprintReadOnlySpecifier) {
return markInvalidSince(`can not specify a property as being both BlueprintReadOnly and having a BlueprintSetter`);
}
metaData.set('BlueprintSetter', value.Values[0]);
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintVisible);
bSeenBlueprintWriteSpecifier = true;
break;
case `BlueprintReadOnly`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
if (bSeenBlueprintWriteSpecifier) {
return markInvalidSince(`can not specify both BlueprintReadOnly and BlueprintReadWrite or BlueprintSetter for ${value.Specifier}`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_BlueprintVisible) | BigInt(UE.PropertyFlags.CPF_BlueprintReadOnly));
ImpliedPropertyFlags = ImpliedPropertyFlags & (~BigInt(UE.PropertyFlags.CPF_BlueprintReadOnly));
bSeenBlueprintReadOnlySpecifier = true;
break;
case `BlueprintGetter`.toLowerCase():
if (!value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier}, should be a meta key value`);
}
metaData.set("BlueprintGetter", value.Values[0]);
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintVisible);
bSeenBlueprintGetterSpecifier = true;
break;
case `Config`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_Config);
break;
case `GlobalConfig`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_GlobalConfig) | BigInt(UE.PropertyFlags.CPF_Config));
break;
case `Localized`.toLowerCase():
console.warn(`the localized specifier is deprecated`);
break;
case `Transient`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_Transient);
break;
case `DuplicateTransient`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_DuplicateTransient);
break;
case `TextExportTransient`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_TextExportTransient);
break;
case `NonPIETransient`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
console.warn('NonPIETransient is deprecated - NonPIEDuplicateTransient should be used instead');
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_NonPIEDuplicateTransient);
break;
case `NonPIEDuplicateTransient`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_NonPIEDuplicateTransient);
break;
case `Export`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_ExportObject);
break;
case `EditInline`.toLowerCase():
return markInvalidSince(`EditInline is deprecated. Remove it, or use Instanced instead`);
case `NoClear`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_NoClear);
break;
case `EditFixedSize`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_EditFixedSize);
break;
case `Replicated`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_Net);
break;
case `ReplicatedUsing`.toLowerCase():
if (!value.IsMetaKeyValue()) {
return markInvalidSince(`${value.Specifier} should be a meta key value`);
}
RepCallbackName = value.Values[0];
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Net) | BigInt(UE.PropertyFlags.CPF_RepNotify));
break;
case `NotReplicated`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_RepSkip);
break;
case `RepRetry`.toLowerCase():
console.error('RepRetry is deprecated');
break;
case `Interp`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_Edit) | BigInt(UE.PropertyFlags.CPF_BlueprintVisible) | BigInt(UE.PropertyFlags.CPF_Interp));
break;
case `NonTransactional`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_NonTransactional);
break;
case `Instanced`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | (BigInt(UE.PropertyFlags.CPF_PersistentInstance) | BigInt(UE.PropertyFlags.CPF_ExportObject) | BigInt(UE.PropertyFlags.CPF_InstancedReference));
metaData.set(`EditInline`, 'true');
break;
case `BlueprintAssignable`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintAssignable);
break;
case `BlueprintCallable`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintCallable);
break;
case `BlueprintAuthorityOnly`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintAuthorityOnly);
break;
case `AssetRegistrySearchable`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_AssetRegistrySearchable);
break;
case `SimpleDisplay`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_SimpleDisplay);
break;
case `AdvancedDisplay`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_AdvancedDisplay);
break;
case `SaveGame`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_SaveGame);
break;
case `SkipSerialization`.toLowerCase():
if (!value.IsMetaKey()) {
return markInvalidSince(`${value.Specifier} should be a meta key`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_SkipSerialization);
break;
default:
markInvalidSince(`${value.Specifier} is not a valid specifier`);
break;
}
}
/**
* a helper function used to validate the property flags
* @returns
*/
function validatePropertyFlags() {
// If we saw a BlueprintGetter but did not see BlueprintSetter or
// or BlueprintReadWrite then treat as BlueprintReadOnly
if (bSeenBlueprintGetterSpecifier && !bSeenBlueprintWriteSpecifier) {
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_BlueprintReadOnly);
ImpliedPropertyFlags = ImpliedPropertyFlags & (~BigInt(UE.PropertyFlags.CPF_BlueprintReadOnly));
}
if (metaData.has(`ExposeOnSpawn`)) {
if ((PropertyFlags & BigInt(UE.PropertyFlags.CPF_DisableEditOnInstance)) != 0n) {
return markInvalidSince(`property cannot have both DisableEditOnInstance and ExposeOnSpawn flags`);
}
if ((PropertyFlags & BigInt(UE.PropertyFlags.CPF_BlueprintVisible)) == 0n) {
return markInvalidSince(`property cannot have ExposeOnSpawn without BlueprintVisible flags`);
}
PropertyFlags = PropertyFlags | BigInt(UE.PropertyFlags.CPF_ExposeOnSpawn);
}
if (!(PropertyFlags & BigInt(UE.PropertyFlags.CPF_Edit))) {
if (PropertyFlags & BigInt(UE.PropertyFlags.CPF_DisableEditOnInstance)) {
return markInvalidSince(`property cannot have DisableEditOnInstance without being editable`);
}
if (PropertyFlags & BigInt(UE.PropertyFlags.CPF_DisableEditOnTemplate)) {
return markInvalidSince(`property cannot have DisableEditOnTemplate without being editable`);
}
}
const ParamFlags = BigInt(UE.PropertyFlags.CPF_Parm)
| BigInt(UE.PropertyFlags.CPF_OutParm)
| BigInt(UE.PropertyFlags.CPF_ReturnParm)
| BigInt(UE.PropertyFlags.CPF_ReferenceParm)
| BigInt(UE.PropertyFlags.CPF_ConstParm);
if (PropertyFlags & ParamFlags) {
return markInvalidSince(`Illegal type modifiers in member variable declaration`);
}
}
/**
* @brief
* function body
*/
specifiers.forEach((value) => {
parsePropertyMetaSpecifier(value);
});
if (bValidSpecifiers) {
validatePropertyFlags();
}
if (!bValidSpecifiers) {
console.warn(`invalid meta data for uproperty: ${InvalidMessage}`);
return null;
}
let metaDataResult = new UE.PEPropertyMetaData();
const FinalFlags = PropertyFlags | ImpliedPropertyFlags;
metaDataResult.SetPropertyFlags(Number(FinalFlags >> 32n), Number(FinalFlags & 0xffffffffn));
metaData.forEach((value, key) => { metaDataResult.SetMetaData(key, value); });
metaDataResult.SetRepCallbackName(RepCallbackName);
return metaDataResult;
}
/**
* compile the class data
* @param type
*/
function compileClassMetaData(type) {
// fetch the decorator
let decorators = null;
if (type.getSymbol().valueDeclaration != null) {
decorators = type.getSymbol().valueDeclaration.decorators;
}
if (decorators == null) { // no decorators
return null;
}
let [specifiers, metaData] = getMetaDataFromDecorators(decorators, 'uclass');
return processClassMetaData(specifiers, metaData);
}
exports.compileClassMetaData = compileClassMetaData;
/**
* compile the function meta data
* @param func
*/
function compileFunctionMetaData(func) {
// fetch the decorator
const decorators = func.valueDeclaration != null ? func.valueDeclaration.decorators : null;
if (decorators == null) { // no decorators
return null;
}
let [specifiers, metaData] = getMetaDataFromDecorators(decorators, 'ufunction');
return processFunctionMetaData(specifiers, metaData);
}
exports.compileFunctionMetaData = compileFunctionMetaData;
/**
* compile the function parameter meta data
* @param param
* @returns
*/
function compileParamMetaData(param) {
// fetch the decorator
const decorators = param.valueDeclaration != null ? param.valueDeclaration.decorators : null;
if (decorators == null) {
return null;
}
let [specifiers, metaData] = getMetaDataFromDecorators(decorators, 'uparam');
return processParamMetaData(specifiers, metaData);
}
exports.compileParamMetaData = compileParamMetaData;
/**
* compile the property meta data
* @param prop
* @returns
*/
function compilePropertyMetaData(prop) {
// fetch the decorator
const decorators = prop.valueDeclaration != null ? prop.valueDeclaration.decorators : null;
if (decorators == null) {
return null;
}
let [specifiers, metaData] = getMetaDataFromDecorators(decorators, 'uproperty');
return processPropertyMetaData(specifiers, metaData);
}
exports.compilePropertyMetaData = compilePropertyMetaData;
//# sourceMappingURL=UEMeta.js.map