CPP Definitions/SequenceAction/Updatable
This commit is contained in:
parent
953e6d2325
commit
dc8ca36829
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 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
|
|
@ -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