Added modding tool command exportScriptEvents and updated modding docs

This commit is contained in:
Robert Beckebans 2020-04-14 10:31:03 +02:00
parent bc7d66a740
commit 97a49323e5
4 changed files with 305 additions and 7 deletions

View file

@ -377,15 +377,22 @@ r_useFilmicPostProcessEffects | Apply several post process effects to m
## Modding Support
Name | Description
:--------------------------------------| :------------------------------------------------
exportDeclsToJSON | Command: exports all entity and model defs to exported/entities.json for usage in Blender
postLoadExportModels | Export models after loading to OBJ model format
exportMapToOBJ | Convert .map file to .obj/.mtl
exportScriptEvents | Command: Generates a new script/doom_events.script that reflects all registered class events in the idClass C++ system. The gamecode still needs to be extended to add the original comments of the events
exportDeclsToJSON | Command: Exports all entity and model defs to exported/entities.json for usage in Blender
postLoadExportModels | Cvar: Export models after loading to OBJ model format. Set it to 1 before loading a map.
exportMapToOBJ | Command: Convert .map file to .obj/.mtl
swf_exportAtlas | Cvar: Set to 1 at startup to dump the Flash images to exported/swf/
swf_exportSWF | Cvar: Set to 1 at startup to dump the Flash .bswf files as .swf (WIP)
swf_exportJSON | Cvar: Set to 1 at startup to dump the Flash .bswf files as .json. Can be reimported into the engine and imported into Blender for inspection
swf_show | Cvar: Draws the bounding box of instanced Flash sprites in red and their names
dmap <mapfile> | Command: Compiles a .map to its corresponding BSP .proc, Collision .cm files and Area Awareness System (AI navigation) .aas files. Just type dmap to list all options
dmap -glview <mapfile> | DMap option that exports the BSP areas and portals to .obj for debugging purposes
convertMapToJSON <mapfile> | Command: Convert .map file to new .json map format with polygons instead of brushes. This was easy because the original .map format is only an array of entities and each entity has a simple dictionary for its values. This JSON format contains all level data and can be imported and exported to Blender without loosing any data. The new DMap can also compile map files with the .json suffix like regular maps.
convertMapToJSON <mapfile> | Command: Convert .map file to new .json map format with polygons instead of brushes. This was easy because the original .map format is only an array of entities and each entity has a simple dictionary for its values. This JSON format contains all level data and can be imported and exported to Blender without loosing any data. The new DMap can also compile map files with the .json suffix like regular maps.
<img src="https://i.imgur.com/2k9IvJC.png" width="384"> <img src="https://i.imgur.com/MnUVKcl.png" width="384">
<img src="https://i.imgur.com/2k9IvJC.png" width="384">
<img src="https://i.imgur.com/MnUVKcl.png" width="384">
____
# Known Issues <a name="issues"></a>

View file

@ -106,7 +106,9 @@ const idEventDef EV_Player_ExitTeleporter( "exitTeleporter" );
const idEventDef EV_Player_StopAudioLog( "stopAudioLog" );
const idEventDef EV_Player_HideTip( "hideTip" );
const idEventDef EV_Player_LevelTrigger( "levelTrigger" );
const idEventDef EV_SpectatorTouch( "spectatorTouch", "et" );
// RB: changed to internal event as it was not exposed to Doom Script by default and broke the automatic export
const idEventDef EV_SpectatorTouch( "<spectatorTouch>", "et" );
// RB end
const idEventDef EV_Player_GiveInventoryItem( "giveInventoryItem", "s" );
const idEventDef EV_Player_RemoveInventoryItem( "removeInventoryItem", "s" );
const idEventDef EV_Player_GetIdealWeapon( "getIdealWeapon", NULL, 's' );

View file

@ -1143,3 +1143,288 @@ void idClass::Event_SafeRemove()
// Forces the remove to be done at a safe time
PostEventMS( &EV_Remove, 0 );
}
// RB: development tool
void idClass::ExportScriptEvents_f( const idCmdArgs& args )
{
// allocate temporary memory for flags so that the subclass's event callbacks
// override the superclass's event callback
int numEventDefs = idEventDef::NumEventCommands();
bool* set = new bool[ numEventDefs ];
enum
{
EXPORTLANG_DOOMSCRIPT,
EXPORTLANG_DOOMSHARP,
NUM_EXPORTLANGS,
};
// go through the inheritence order
#if 1 //defined(USE_DOOMSHARP)
for( int exportLang = 0; exportLang < NUM_EXPORTLANGS; exportLang++ )
#else
int exportLang = 0;
#endif
{
bool threadClassFound = false;
bool firstEntityClassFound = false;
memset( set, 0, sizeof( bool ) * numEventDefs );
#if 1 //defined(USE_DOOMSHARP)
idFile* file = NULL;
if( exportLang == EXPORTLANG_DOOMSHARP )
{
file = fileSystem->OpenFileWrite( "script/doom_events.cs", "fs_basepath" );
}
else
{
file = fileSystem->OpenFileWrite( "script/doom_events.script", "fs_basepath" );
}
#else
idFile* file = fileSystem->OpenFileWrite( "script/doom_events.script", "fs_basepath" );
#endif
file->Printf( "// generated by RBDOOM-3-BFG\n//\n\n" );
if( exportLang == EXPORTLANG_DOOMSHARP )
{
//file->Printf( "#if CSHARP\n\n" );
file->Printf( "using vector;\n\n" );
}
for( const idTypeInfo* c = classHierarchy.GetNext(); c != NULL; c = c->node.GetNext() )
{
idEventFunc<idClass>* def = c->eventCallbacks;
if( !def || !def[ 0 ].event )
{
// no new events or overrides
continue;
}
if( exportLang == EXPORTLANG_DOOMSHARP )
{
//if( c->IsType( idEntity::Type ) && threadClassFound )
//{
// file->Printf( "\n}\n\n\n" );
//}
file->Printf( "\n/// <summary>\n" );
file->Printf( "/// %-24s ---> %-24s\n", c->classname, c->superclass );
file->Printf( "/// </summary>\n" );
if( !c->IsType( idThread::Type ) && !c->IsType( idEntity::Type ) )
{
continue;
}
else if( c->IsType( idThread::Type ) )
{
file->Printf( "class sys\n{\n" );
threadClassFound = true;
}
else if( c->IsType( idEntity::Type ) && !firstEntityClassFound )
{
file->Printf( "\n}\n\n\n" );
file->Printf( "class entity\n{\n" );
file->Printf( "\tpublic void remove() { }\n\n" );
firstEntityClassFound = true;
}
}
else
{
file->Printf( "/*\n\n" );
file->Printf( "%-24s ---> %-24s\n\n", c->classname, c->superclass );
file->Printf( "*/\n\n" );
}
// go through each entry until we hit the NULL terminator
for( int j = 0; def[ j ].event != NULL; j++ )
{
const idEventDef* ev = def[ j ].event;
int evNum = ev->GetEventNum();
if( set[ evNum ] )
{
//continue;
}
if( ev->GetName()[0] == '_' || ev->GetName()[0] == '<' )
{
// internal event
continue;
}
if( set[ evNum ] )
{
file->Printf( "// override " );
}
set[ evNum ] = true;
if( exportLang == EXPORTLANG_DOOMSHARP )
{
if( c->IsType( idThread::Type ) )
{
file->Printf( "\tpublic static " );
}
else
{
file->Printf( "\tpublic " );
}
}
else
{
file->Printf( "scriptEvent " );
}
switch( ev->GetReturnType() )
{
case D_EVENT_FLOAT :
file->Printf( "float " );
break;
case D_EVENT_INTEGER :
file->Printf( "float " );
break;
case D_EVENT_VECTOR :
file->Printf( "vector " );
break;
case D_EVENT_STRING :
file->Printf( "string " );
break;
case D_EVENT_ENTITY :
case D_EVENT_ENTITY_NULL :
file->Printf( "entity " );
break;
case 0:
file->Printf( "void " );
break;
default:
case D_EVENT_TRACE :
file->Printf( "<unsupported> " );
break;
}
file->Printf( "%s(", ev->GetName() );
if( ev->GetNumArgs() )
{
file->Printf( " " );
}
const char* formatspec = ev->GetArgFormat();
for( int arg = 0; arg < ev->GetNumArgs(); arg++ )
{
if( arg != 0 )
{
file->Printf( ", " );
}
switch( formatspec[ arg ] )
{
case D_EVENT_FLOAT :
file->Printf( "float parm%d", arg );
break;
case D_EVENT_INTEGER :
file->Printf( "float parm%d", arg );
break;
case D_EVENT_VECTOR :
file->Printf( "vector parm%d", arg );
break;
case D_EVENT_STRING :
file->Printf( "string parm%d", arg );
break;
case D_EVENT_ENTITY :
case D_EVENT_ENTITY_NULL :
file->Printf( "entity parm%d", arg );
break;
case 0:
// void
break;
default:
case D_EVENT_TRACE :
file->Printf( "<unsupported> parm%d", arg );
break;
}
}
if( ev->GetNumArgs() )
{
file->Printf( " " );
}
if( exportLang == EXPORTLANG_DOOMSHARP )
{
file->Printf( ") " );
switch( ev->GetReturnType() )
{
case D_EVENT_FLOAT :
file->Printf( "{ return 0; }\n\n" );
break;
case D_EVENT_INTEGER :
file->Printf( "{ return 0; }\n\n" );
break;
case D_EVENT_VECTOR :
file->Printf( "{ return new vector( 0, 0, 0 ); }\n\n" );
break;
case D_EVENT_STRING :
file->Printf( "{ return \"\"; }\n\n" );
break;
case D_EVENT_ENTITY :
case D_EVENT_ENTITY_NULL :
file->Printf( "{ return null; }\n\n" );
break;
case 0:
file->Printf( "{ }\n\n" );
break;
default:
case D_EVENT_TRACE :
file->Printf( "<unsupported> " );
break;
}
}
else
{
file->Printf( ");\n\n" );
}
}
}
if( exportLang == EXPORTLANG_DOOMSHARP )
{
file->Printf( "\n}\n\n" );
//file->Printf( "#endif // CSHARP\n\n" );
}
fileSystem->CloseFile( file );
}
delete[] set;
}
// RB end

View file

@ -2737,6 +2737,10 @@ void idGameLocal::InitConsoleCommands()
cmdSystem->AddCommand( "showViewNotes", Cmd_ShowViewNotes_f, CMD_FL_GAME | CMD_FL_CHEAT, "show any view notes for the current map, successive calls will cycle to the next note" );
cmdSystem->AddCommand( "closeViewNotes", Cmd_CloseViewNotes_f, CMD_FL_GAME | CMD_FL_CHEAT, "close the view showing any notes for this map" );
// RB begin
cmdSystem->AddCommand( "exportScriptEvents", idClass::ExportScriptEvents_f, CMD_FL_GAME | CMD_FL_CHEAT, "update script/doom_events.script" );
// RB end
// multiplayer client commands ( replaces old impulses stuff )
//cmdSystem->AddCommand( "clientDropWeapon", idMultiplayerGame::DropWeapon_f, CMD_FL_GAME, "drop current weapon" );
cmdSystem->AddCommand( "clientMessageMode", idMultiplayerGame::MessageMode_f, CMD_FL_GAME, "ingame gui message mode" );