CPP Definitions/SequenceAction/Updatable
This commit is contained in:
parent
953e6d2325
commit
dc8ca36829
|
@ -1,7 +1,8 @@
|
||||||
## NOTHING IN HERE FOR NOW
|
## NOTHING IN HERE FOR NOW
|
||||||
|
|
||||||
/build-steps/local-build-steps-windows.txt
|
/build-steps/local-build-steps/**
|
||||||
/outputs
|
/outputs
|
||||||
/godot-rj-nuget-package
|
/godot-rj-nuget-package
|
||||||
/godot/modules/rokojori_action_library
|
/godot/modules/rokojori_action_library
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
class CppParameter
|
||||||
|
{
|
||||||
|
name = "";
|
||||||
|
type = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
class CppClassMember
|
||||||
|
{
|
||||||
|
name = "";
|
||||||
|
isMethod = false;
|
||||||
|
isVirtual = false;
|
||||||
|
isStatic = false;
|
||||||
|
type = "void";
|
||||||
|
parameters = [];
|
||||||
|
|
||||||
|
constructor( nameDefinition, body )
|
||||||
|
{
|
||||||
|
if ( nameDefinition.endsWith( "()" ) )
|
||||||
|
{
|
||||||
|
this.isMethod = true;
|
||||||
|
nameDefinition = nameDefinition.replace( /\(\)$/, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
let names = nameDefinition.split( /\s+/ );
|
||||||
|
this.name = names[ names.length -1 ];
|
||||||
|
|
||||||
|
for ( let i = 0; i < names.length - 1; i++ )
|
||||||
|
{
|
||||||
|
if ( "virtual" === names[ i ] )
|
||||||
|
{
|
||||||
|
this.isVirtual = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "static" === names[ i ] )
|
||||||
|
{
|
||||||
|
this.isStatic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.isMethod )
|
||||||
|
{
|
||||||
|
this.parseMethodBody( body );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMethodBody( body )
|
||||||
|
{
|
||||||
|
if ( ! body )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = body.type || "void";
|
||||||
|
|
||||||
|
let parameters = body.parameters;
|
||||||
|
|
||||||
|
if ( ! parameters )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( let i = 0; i < parameters.length; i++ )
|
||||||
|
{
|
||||||
|
let pm = parameters[ i ];
|
||||||
|
|
||||||
|
let cppParameter = new CppParameter();
|
||||||
|
|
||||||
|
for ( let it in pm )
|
||||||
|
{
|
||||||
|
if ( ! pm.hasOwnProperty( it ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cppParameter.name = it;
|
||||||
|
cppParameter.type = pm[ it ];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parameters.push( cppParameter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getMethodBinding( className )
|
||||||
|
{
|
||||||
|
if ( this.isVirtual )
|
||||||
|
{
|
||||||
|
return `GDVIRTUAL_BIND( ${this.name} );`;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return `ClassDB::bind_method( D_METHOD( "${this.name}" ) , &${className}::${this.name} );`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getHeaderDefinition()
|
||||||
|
{
|
||||||
|
if ( this.isMethod )
|
||||||
|
{
|
||||||
|
return this.getMethodHeaderDefinition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.getVariableHeaderDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getParametersDefinition()
|
||||||
|
{
|
||||||
|
return this.parameters.map( p => p.type + " " + p.name ).join( ", " );
|
||||||
|
}
|
||||||
|
|
||||||
|
getMethodHeaderDefinition()
|
||||||
|
{
|
||||||
|
if ( this.isVirtual )
|
||||||
|
{
|
||||||
|
let numParameters = this.parameters.length;
|
||||||
|
let methodReturnType = this.type === "void" ? "" : "R";
|
||||||
|
let returnTypeDefinition = this.type === "void" ? "" : ( this.type + ", " ) ;
|
||||||
|
|
||||||
|
let parametersDefinition = "";
|
||||||
|
|
||||||
|
if ( numParameters > 0 )
|
||||||
|
{
|
||||||
|
parametersDefinition = ", " + this.parameters.map( p => p.type ).join( ", " );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return `GDVIRTUAL${numParameters}${methodReturnType}( ${returnTypeDefinition}${this.name}${parametersDefinition} );`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.type} ${this.name}(${this.parametersDefinition});`
|
||||||
|
}
|
||||||
|
|
||||||
|
getVariableHeaderDefinition()
|
||||||
|
{
|
||||||
|
return `${this.type} ${this.name};`
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports =
|
||||||
|
{
|
||||||
|
CppParameter,
|
||||||
|
CppClassMember
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
const fs = require( "node:fs/promises" );
|
||||||
|
const path = require( "path" );
|
||||||
|
const { loadJSON, getFiles, saveUTF8, getMatches, loadUTF8, insertText } = require( "./library.js" );
|
||||||
|
const { CppClassMember } = require( "./cpp-class-member.js" );
|
||||||
|
|
||||||
|
function createCppHeader( className, extendingClassName, headerDefine, protectedMembers, publicMembers )
|
||||||
|
{
|
||||||
|
|
||||||
|
let cppHeader =
|
||||||
|
|
||||||
|
`
|
||||||
|
/* ${className}.h */
|
||||||
|
|
||||||
|
#ifndef ${headerDefine}
|
||||||
|
#define ${headerDefine}
|
||||||
|
|
||||||
|
#include "./${extendingClassName}.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ${className} : public ${extendingClassName}
|
||||||
|
{
|
||||||
|
GDCLASS(${className}, ${extendingClassName});
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
${protectedMembers}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
${publicMembers}
|
||||||
|
|
||||||
|
${className}();
|
||||||
|
|
||||||
|
~${className}();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ${headerDefine}
|
||||||
|
`
|
||||||
|
|
||||||
|
return cppHeader;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCppImplementation( className, boundMethods )
|
||||||
|
{
|
||||||
|
|
||||||
|
let cppImplementation =
|
||||||
|
`
|
||||||
|
/* ${className}.cpp */
|
||||||
|
|
||||||
|
#include "${className}.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ${className}::_bind_methods()
|
||||||
|
{
|
||||||
|
${boundMethods}
|
||||||
|
}
|
||||||
|
|
||||||
|
${className}::${className}()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
${className}::~${className}()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
return cppImplementation;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let definitionsPath = __dirname + "/rokojori-action-library-definitions";
|
||||||
|
let outputPath = __dirname + "/rokojori-action-library";
|
||||||
|
let registerTypesPath = outputPath + "/register_types.cpp";
|
||||||
|
let classRegistrationRegex = /ClassDB\:\:register_class\<(\w+)\>\(\)\;/;
|
||||||
|
|
||||||
|
function createTypeRegistration( className )
|
||||||
|
{
|
||||||
|
return `ClassDB::register_class<${className}>();`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createIncludes( className )
|
||||||
|
{
|
||||||
|
return `#include "./${className}.h"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main()
|
||||||
|
{
|
||||||
|
let files = await getFiles( definitionsPath );
|
||||||
|
let typesFile = await loadUTF8( registerTypesPath );
|
||||||
|
|
||||||
|
let types = getRegistratedTypes( typesFile );
|
||||||
|
|
||||||
|
let missingTypes = [];
|
||||||
|
|
||||||
|
for ( let file of files )
|
||||||
|
{
|
||||||
|
await createCppFiles( file, types, missingTypes );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( missingTypes.length === 0 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log( "Registrating missing types:", missingTypes );
|
||||||
|
|
||||||
|
let additions = missingTypes.map( mt => createTypeRegistration( mt ) );
|
||||||
|
let additionsBlock = additions.join( "\n " );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let lastType = types[ types.length -1 ];
|
||||||
|
let insertPosition = lastType.index + lastType.match.length;
|
||||||
|
let updatedTypesFile = insertText( typesFile, "\n " + additionsBlock, insertPosition );
|
||||||
|
|
||||||
|
|
||||||
|
let includeMatches = getMatches( updatedTypesFile, /#include "(\w|\.|\/|\\)+.h"/ );
|
||||||
|
let lastInclude = includeMatches[ includeMatches.length - 1 ];
|
||||||
|
let includes = missingTypes.map( mt => createIncludes( mt ) ).join( "\n" );
|
||||||
|
insertPosition = lastInclude.index + lastInclude.match.length;
|
||||||
|
updatedTypesFile = insertText( updatedTypesFile, "\n" + includes, insertPosition );
|
||||||
|
|
||||||
|
saveUTF8( registerTypesPath, updatedTypesFile );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function grabMembers( membersData )
|
||||||
|
{
|
||||||
|
let members = [];
|
||||||
|
|
||||||
|
if ( ! membersData )
|
||||||
|
{
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( let it in membersData )
|
||||||
|
{
|
||||||
|
if ( ! membersData.hasOwnProperty( it ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nameDefinition = it;
|
||||||
|
let memberData = membersData[ it ];
|
||||||
|
|
||||||
|
let classMember = new CppClassMember( nameDefinition, memberData );
|
||||||
|
|
||||||
|
members.push( classMember );
|
||||||
|
}
|
||||||
|
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeaderDefine( className )
|
||||||
|
{
|
||||||
|
className = className.replace( /^RJ/, "" );
|
||||||
|
|
||||||
|
let output = [ className[ 0 ] ];
|
||||||
|
|
||||||
|
for ( let i = 1; i < className.length; i++ )
|
||||||
|
{
|
||||||
|
let character = className[ i ];
|
||||||
|
let upperCaseCharacter = character.toUpperCase();
|
||||||
|
|
||||||
|
if ( character === upperCaseCharacter )
|
||||||
|
{
|
||||||
|
output.push( "_" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push( upperCaseCharacter );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
className = output.join( "" );
|
||||||
|
|
||||||
|
return "ROKOJORI_CORE__" + className + "_H";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRegistratedTypes( text )
|
||||||
|
{
|
||||||
|
let matches = getMatches( text, classRegistrationRegex );
|
||||||
|
|
||||||
|
let types = matches.map(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
return { match: m.match, index: m.index, type: classRegistrationRegex.exec( m.match )[ 1 ] }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return types;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function createCppFiles( definitionPath, types, missingTypes )
|
||||||
|
{
|
||||||
|
console.log( "Creating: ", definitionPath );
|
||||||
|
|
||||||
|
let data = await loadJSON( path.join( definitionsPath, definitionPath ) );
|
||||||
|
|
||||||
|
let classNameResult = /(\w+)(?:\:(\w+))?/.exec( data.class );
|
||||||
|
|
||||||
|
let className = classNameResult[ 1 ];
|
||||||
|
let extendingClass = classNameResult[ 2 ];
|
||||||
|
|
||||||
|
let headerDefine = getHeaderDefine( className );
|
||||||
|
|
||||||
|
let protectedMembers = grabMembers( data.protected );
|
||||||
|
let publicMembers = grabMembers( data.public );
|
||||||
|
|
||||||
|
let protectedHeader = protectedMembers.map( p => p.getHeaderDefinition() ).join( "\n " );
|
||||||
|
let publicHeader = publicMembers.map( p => p.getHeaderDefinition() ).join( "\n " );
|
||||||
|
|
||||||
|
let protectedBindings = protectedMembers.map( p => p.getMethodBinding( className ) );
|
||||||
|
let publicBindings = publicMembers.map( p => p.getMethodBinding( className ) );
|
||||||
|
|
||||||
|
let bindings = protectedBindings.concat( publicBindings ).join( "\n " );
|
||||||
|
|
||||||
|
let header = createCppHeader( className, extendingClass, headerDefine, protectedHeader, publicHeader );
|
||||||
|
let implementation = createCppImplementation( className, bindings );
|
||||||
|
|
||||||
|
//console.log( header );
|
||||||
|
//console.log( implementation );
|
||||||
|
|
||||||
|
let hasType = types.find( t => t.type === className );
|
||||||
|
|
||||||
|
if ( ! hasType )
|
||||||
|
{
|
||||||
|
missingTypes.push( className );
|
||||||
|
}
|
||||||
|
|
||||||
|
let rawFilePath = path.join( outputPath, className );
|
||||||
|
await saveUTF8( rawFilePath + ".h", header );
|
||||||
|
await saveUTF8( rawFilePath + ".cpp", implementation );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
main();
|
100
library.js
100
library.js
|
@ -1,6 +1,11 @@
|
||||||
const { stat } = require("node:fs");
|
const { stat } = require("node:fs");
|
||||||
const fs = require( "node:fs/promises" );
|
const fs = require( "node:fs/promises" );
|
||||||
|
|
||||||
|
async function getFiles( filePath )
|
||||||
|
{
|
||||||
|
return await fs.readdir( filePath );
|
||||||
|
}
|
||||||
|
|
||||||
async function exists( filePath )
|
async function exists( filePath )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -34,6 +39,87 @@ async function loadUTF8( filePath )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveUTF8( filePath, data )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await fs.writeFile( filePath, data );
|
||||||
|
return Promise.resolve( true );
|
||||||
|
}
|
||||||
|
catch ( exception )
|
||||||
|
{
|
||||||
|
console.warn( exception );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve( false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSticky( regexp )
|
||||||
|
{
|
||||||
|
if ( regexp.sticky )
|
||||||
|
{
|
||||||
|
return regexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = regexp.source;
|
||||||
|
var flags = regexp.flags;
|
||||||
|
|
||||||
|
if ( flags.indexOf( "y" ) === -1 )
|
||||||
|
{
|
||||||
|
flags += "y";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegExp( source, flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeGlobal( regexp )
|
||||||
|
{
|
||||||
|
if ( regexp.global )
|
||||||
|
{
|
||||||
|
return regexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = regexp.source;
|
||||||
|
var flags = regexp.flags;
|
||||||
|
|
||||||
|
if ( flags.indexOf( "g" ) === -1 )
|
||||||
|
{
|
||||||
|
flags += "g";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegExp( source, flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMatches( source, regex )
|
||||||
|
{
|
||||||
|
regex = makeGlobal( regex );
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
let matches = [];
|
||||||
|
|
||||||
|
while ( offset < source.length )
|
||||||
|
{
|
||||||
|
regex.lastIndex = offset;
|
||||||
|
let result = regex.exec( source );
|
||||||
|
|
||||||
|
let match = result ? result[ 0 ] : null;
|
||||||
|
|
||||||
|
if ( result && result.index != offset && match.length > 0)
|
||||||
|
{
|
||||||
|
offset = result.index + match.length;
|
||||||
|
matches.push( { match:match, index: result.index } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadJSON( filePath )
|
async function loadJSON( filePath )
|
||||||
{
|
{
|
||||||
let text = await loadUTF8( filePath );
|
let text = await loadUTF8( filePath );
|
||||||
|
@ -57,9 +143,21 @@ async function loadJSON( filePath )
|
||||||
return Promise.resolve( null );
|
return Promise.resolve( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertText( sourceText, insertText, insertPosition )
|
||||||
|
{
|
||||||
|
let before = sourceText.substring( 0, insertPosition );
|
||||||
|
let after = sourceText.substring( insertPosition, sourceText.length );
|
||||||
|
|
||||||
|
return before + insertText + after;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
{
|
{
|
||||||
exists,
|
exists,
|
||||||
loadUTF8,
|
loadUTF8,
|
||||||
loadJSON
|
saveUTF8,
|
||||||
|
loadJSON,
|
||||||
|
getFiles,
|
||||||
|
getMatches,
|
||||||
|
insertText
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit c040dcae242ec1bbd17906b42092b614e483fb09
|
Subproject commit 26aea1a20d5bc2e35486517e2849b02f3b5d585b
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"class":"RJSequenceAction:RJAction",
|
||||||
|
|
||||||
|
"public":
|
||||||
|
{
|
||||||
|
"virtual dispatchStartEvent()":{},
|
||||||
|
"virtual dispatchCancelEvent()":{},
|
||||||
|
"virtual dispatchEndEvent()":{}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"class":"RJUpdatable:RJNetworkNode",
|
||||||
|
|
||||||
|
"public":
|
||||||
|
{
|
||||||
|
"virtual update()":
|
||||||
|
{
|
||||||
|
"parameters":[ { "delta":"double" } ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue