CPP Definitions/SequenceAction/Updatable

This commit is contained in:
Josef 2024-05-08 09:18:42 +02:00
parent 953e6d2325
commit dc8ca36829
7 changed files with 521 additions and 3 deletions

3
.gitignore vendored
View File

@ -1,7 +1,8 @@
## NOTHING IN HERE FOR NOW
/build-steps/local-build-steps-windows.txt
/build-steps/local-build-steps/**
/outputs
/godot-rj-nuget-package
/godot/modules/rokojori_action_library

146
cpp-class-member.js Normal file
View File

@ -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
}

252
create-cpp.js Normal file
View File

@ -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();

View File

@ -1,6 +1,11 @@
const { stat } = require("node:fs");
const fs = require( "node:fs/promises" );
async function getFiles( filePath )
{
return await fs.readdir( filePath );
}
async function exists( filePath )
{
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 )
{
let text = await loadUTF8( filePath );
@ -57,9 +143,21 @@ async function loadJSON( filePath )
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 =
{
exists,
loadUTF8,
loadJSON
saveUTF8,
loadJSON,
getFiles,
getMatches,
insertText
}

@ -1 +1 @@
Subproject commit c040dcae242ec1bbd17906b42092b614e483fb09
Subproject commit 26aea1a20d5bc2e35486517e2849b02f3b5d585b

View File

@ -0,0 +1,10 @@
{
"class":"RJSequenceAction:RJAction",
"public":
{
"virtual dispatchStartEvent()":{},
"virtual dispatchCancelEvent()":{},
"virtual dispatchEndEvent()":{}
}
}

View File

@ -0,0 +1,11 @@
{
"class":"RJUpdatable:RJNetworkNode",
"public":
{
"virtual update()":
{
"parameters":[ { "delta":"double" } ]
}
}
}