Implementation of Subscenes, SceneGroups and Gamemodes

Standardizes Gamemodes to be an actual class with data and utility functions that can be parsed
Adds inspector field handling for selecting gamemodes
Updated Scene class to work with Gamemodes for the gamemode field
Updates editor suite elements to be able to create SubScenes, SceneGroups and Gamemodes
Adds ability to convert SimGroup to SubScene
Updates BaseUI's chooselevel menu to have gamemode selection and filters shown levels based on selected gamemode
This commit is contained in:
Areloch 2024-09-01 16:39:00 -05:00
parent 0d07823ecd
commit ae8eca48e1
36 changed files with 2963 additions and 173 deletions

View file

@ -325,6 +325,8 @@ function replaceInFile(%fileName, %fromWord, %toWord)
//Go through our scriptfile and replace the old namespace with the new
%editedFileContents = "";
%lineArray = new ArrayObject(){};
%file = new FileObject();
if ( %file.openForRead( %fileName ) )
{
@ -334,6 +336,8 @@ function replaceInFile(%fileName, %fromWord, %toWord)
%line = trim( %line );
%editedFileContents = %editedFileContents @ strreplace(%line, %fromWord, %toWord) @ "\n";
%lineArray.add(strreplace(%line, %fromWord, %toWord));
}
%file.close();
@ -341,12 +345,18 @@ function replaceInFile(%fileName, %fromWord, %toWord)
if(%editedFileContents !$= "")
{
%file.openForWrite(%fileName);
%file.writeline(%editedFileContents);
%file.close();
if( %file.openForWrite(%fileName) )
{
for(%i=0; %i < %lineArray.getCount(); %i++)
{
%file.writeline(%lineArray.getKey(%i));
}
%file.close();
}
}
%lineArray.delete();
}
//------------------------------------------------------------------------------

View file

@ -15,19 +15,6 @@ function ExampleModule::initServer(%this)
//This is called when the server is created for an actual game/map to be played
function ExampleModule::onCreateGameServer(%this)
{
//These are common managed data files. For any datablock-based stuff that gets generated by the editors
//(that doesn't have a specific associated file, like data for a player class) will go into these.
//So we'll register them now if they exist.
if(isFile("./scripts/managedData/managedDatablocks." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedDatablocks");
if(isFile("./scripts/managedData/managedForestItemData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedForestItemData");
if(isFile("./scripts/managedData/managedForestBrushData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
if(isFile("./scripts/managedData/managedParticleData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedParticleData");
if(isFile("./scripts/managedData/managedParticleEmitterData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
}
//This is called when the server is shut down due to the game/map being exited
@ -46,6 +33,8 @@ function ExampleModule::initClient(%this)
%prefPath = getPrefpath();
if(isScriptFile(%prefPath @ "/keybinds"))
exec(%prefPath @ "/keybinds");
%this.queueExec("./scripts/server/ExampleGameMode");
}
//This is called when a client connects to a server

View file

@ -8,4 +8,5 @@
ForestFile="@assetFile=ExampleLevel.forest"
NavmeshFile="@assetFile=ExampleLevel.nav"
staticObjectAssetDependency0="@asset=Prototyping:FloorGray"
gameModesNames="ExampleGameMode;"
VersionId="1"/>

View file

@ -1,11 +1,5 @@
function ExampleGameMode::onCreateGame()
{
// Note: The Game object will be cleaned up by MissionCleanup. Therefore its lifetime is
// limited to that of the mission.
new ScriptObject(ExampleGameMode){};
return ExampleGameMode;
}
if(!isObject(ExampleGameMode))
new GameMode(ExampleGameMode){};
//-----------------------------------------------------------------------------
// The server has started up so do some game start up
@ -159,6 +153,30 @@ function ExampleGameMode::onInitialControlSet(%this)
}
function ExampleGameMode::onSceneLoaded(%this)
{
echo("===================================");
echo("ExampleGameMode - Scene is loaded");
}
function ExampleGameMode::onSceneUnloaded(%this)
{
echo("===================================");
echo("ExampleGameMode - Scene is unloaded");
}
function ExampleGameMode::onSubsceneLoaded(%this)
{
echo("===================================");
echo("ExampleGameMode - Subscene is loaded");
}
function ExampleGameMode::onSubsceneUnloaded(%this)
{
echo("===================================");
echo("ExampleGameMode - Subscene is unloaded");
}
function ExampleGameMode::spawnCamera(%this, %client, %spawnPoint)
{
// Set the control object to the default camera

View file

@ -99,4 +99,9 @@ function UI::onDestroyClientConnection(%this)
function UI::registerGameMenus(%this, %menusArrayObj)
{
%menusArrayObj.add("System", SystemMenu);
}
function listLevelsAndGameModes()
{
}

View file

@ -9,6 +9,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
canSaveDynamicFields = "1";
currentMenuIdx = "0";
launchInEditor = "0";
previewButtonSize = "445 120";
@ -39,31 +40,42 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
new GuiStackControl(ChooseLevelMenuTabList) {
stackingType = "Horizontal";
padding = "10";
position = "485 61";
extent = "310 41";
position = "405 61";
extent = "470 41";
horizSizing = "center";
profile = "GuiDefaultProfile";
visible = "0";
tooltipProfile = "GuiToolTipProfile";
hidden = "1";
new GuiButtonCtrl() {
text = "Level";
text = "Game Mode";
groupNum = "1";
extent = "150 41";
profile = "GuiMenuButtonProfile";
command = "ChooseLevelMenu.openMenu(0);";
tooltipProfile = "GuiToolTipProfile";
internalName = "GameModeBtn";
class = "ChooseLevelMenuButton";
};
new GuiButtonCtrl() {
text = "Server Config";
text = "Level";
groupNum = "1";
position = "160 0";
extent = "150 41";
profile = "GuiMenuButtonProfile";
command = "ChooseLevelMenu.openMenu(1);";
tooltipProfile = "GuiToolTipProfile";
internalName = "LevelBtn";
class = "ChooseLevelMenuButton";
};
new GuiButtonCtrl() {
text = "Server Config";
groupNum = "1";
position = "320 0";
extent = "150 41";
profile = "GuiMenuButtonProfile";
command = "ChooseLevelMenu.openMenu(2);";
tooltipProfile = "GuiToolTipProfile";
internalName = "ConfigBtn";
class = "ChooseLevelMenuButton";
};
};
@ -72,14 +84,12 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
extent = "1281 60";
horizSizing = "width";
profile = "GuiNonModalDefaultProfile";
visible = "0";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
hidden = "1";
new GuiBitmapCtrl(ChooseLevelMenuPrevNavIcon) {
BitmapAsset = "UI:Keyboard_Black_Q_image";
position = "485 24";
position = "405 24";
extent = "40 40";
vertSizing = "top";
profile = "GuiNonModalDefaultProfile";
@ -87,19 +97,72 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
};
new GuiBitmapCtrl(ChooseLevelMenuNextNavIcon) {
BitmapAsset = "UI:Keyboard_Black_E_image";
position = "595 24";
position = "515 24";
extent = "40 40";
vertSizing = "top";
profile = "GuiNonModalDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
};
};
new GuiContainer(GameModeSelectContainer) {
position = "196 119";
extent = "888 566";
horizSizing = "center";
profile = "GuiNonModalDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
new GuiScrollCtrl(GameModePreviewScroll) {
hScrollBar = "alwaysOff";
vScrollBar = "dynamic";
extent = "445 562";
vertSizing = "height";
profile = "GuiMenuScrollProfile";
tooltipProfile = "GuiToolTipProfile";
new GuiStackControl(GameModePreviewArray) {
padding = "5";
position = "0 1";
extent = "445 120";
horizSizing = "width";
vertSizing = "height";
profile = "GuiMenuDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
};
};
new GuiBitmapCtrl(GameModePreviewBitmap) {
BitmapAsset = "UI:no_preview_image";
position = "448 0";
extent = "440 440";
horizSizing = "left";
profile = "GuiNonModalDefaultProfile";
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl(GameModeNameText) {
text = "Example Level";
position = "448 445";
extent = "440 20";
horizSizing = "left";
profile = "MenuSubHeaderText";
tooltipProfile = "GuiToolTipProfile";
internalName = "GameModeNameTxt";
};
new GuiMLTextCtrl(GameModeDescriptionText) {
position = "448 473";
extent = "440 19";
horizSizing = "left";
profile = "GuiMLTextProfile";
tooltipProfile = "GuiToolTipProfile";
internalName = "GameModeDescTxt";
};
};
new GuiContainer(LevelSelectContainer) {
position = "196 119";
extent = "888 566";
horizSizing = "center";
profile = "GuiNonModalDefaultProfile";
visible = "0";
tooltipProfile = "GuiToolTipProfile";
hidden = "1";
new GuiScrollCtrl(LevelPreviewScroll) {
hScrollBar = "alwaysOff";
@ -120,7 +183,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
};
};
new GuiBitmapCtrl(LevelPreviewBitmap) {
BitmapAsset = "";
BitmapAsset = "UI:no_preview_image";
position = "448 0";
extent = "440 440";
horizSizing = "left";
@ -128,7 +191,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl(LevelNameText) {
text = "";
text = "Example Level";
position = "448 445";
extent = "440 20";
horizSizing = "left";
@ -214,7 +277,6 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextEditCtrl(serverNameCTRL) {
text = "";
position = "606 4";
extent = "295 22";
horizSizing = "left";
@ -240,7 +302,6 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextEditCtrl(serverPassCTRL) {
text = "";
position = "606 4";
extent = "295 22";
horizSizing = "left";
@ -314,7 +375,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
tooltipProfile = "GuiToolTipProfile";
new GuiIconButtonCtrl(ChooseLevelStartBtn) {
BitmapAsset = "UI:Keyboard_Black_Return_image";
BitmapAsset = "UI:Keyboard_Black_Space_image";
sizeIconToButton = "1";
makeIconSquare = "1";
textLocation = "Center";

View file

@ -42,6 +42,70 @@ function ChooseLevelMenu::onWake(%this)
%this.fillPrefEntries();
LevelPreviewArray.clear();
refreshGameModesList();
if(!$pref::HostMultiPlayer)
ChooseLevelTitleText.setText("SINGLE PLAYER");
else
ChooseLevelTitleText.setText("CREATE SERVER");
ChooseLevelMenuTabList-->ConfigBtn.visible = $pref::HostMultiPlayer;
ChooseLevelMenuTabList.visible = true;//$pref::HostMultiPlayer;
ChooseLevelMenuNavButtonOverlay.visible = true;//$pref::HostMultiPlayer;
%this.schedule(32, openMenu, 0);
}
function refreshGameModesList()
{
GameModePreviewArray.clear();
$pref::Server::GameMode = "";
ChooseLevelMenuTabList-->LevelBtn.active = false;
//popilate the gamemodes list first
%gamemodeList = getGameModesList();
for(%i=0; %i < getTokenCount(%gamemodeList, ";"); %i++)
{
%gameModeObj = getToken(%gamemodeList, ";", %i);
if(isObject(%gameModeObj))
{
%gameModeName = %gameModeObj.gameModeName;
if(%gameModeName $= "")
%gameModeName = %gameModeObj.getName();
%preview = new GuiButtonCtrl() {
position = "0 0";
extent = ChooseLevelMenu.previewButtonSize;
buttonType = "PushButton";
profile = GuiMenuButtonLeftJustProfile;
horizSizing = "right";
vertSizing = "bottom";
internalName = "button";
class = "GameModePreviewButton";
//command = "ChooseGameModeBegin(" @ %i @ ");";
altCommand = "ChooseGameModeBegin(" @ %i @ ");"; //allow doubleclick to quick action it
text = %gameModeName;
gameModeObj = %gameModeObj;
gameModeDesc = %gameModeObj.description;
previewImage = %gameModeObj.previewImage;
textMargin = 120;
groupNum = 2;
cansave = false;
};
GameModePreviewArray.add(%preview);
}
}
}
function refreshLevelsList()
{
LevelPreviewArray.clear();
//fetch the levelAssets
ChooseLevelAssetQuery.clear();
AssetDatabase.findAssetType(ChooseLevelAssetQuery, "LevelAsset");
@ -57,6 +121,7 @@ function ChooseLevelMenu::onWake(%this)
return;
}
//filter the levelAssets by the gamemode selected
for(%i=0; %i < %count; %i++)
{
%assetId = ChooseLevelAssetQuery.getAsset(%i);
@ -71,6 +136,32 @@ function ChooseLevelMenu::onWake(%this)
if ( !isFile(%file) )
continue;
if( %levelAsset.isSubScene )
continue;
//filter for selected gamemode
%levelGameModes = %levelAsset.gameModesNames;
echo("LevelAsset gamemodes: " @ %levelGameModes);
%foundGameModeMatch = false;
for(%gm = 0; %gm < getTokenCount(%levelGameModes, ";"); %gm++)
{
%gameModeName = getToken(%levelGameModes, ";", %gm);
echo("testing gamemode: " @ %gameModeName);
echo("selected gamemode: " @ $pref::Server::GameMode.getName());
if(%gameModeName $= $pref::Server::GameMode.getName())
{
%foundGameModeMatch = true;
break;
}
}
if(!%foundGameModeMatch)
continue;
%levelPreviewImg = %levelAsset.getPreviewImagePath();
if (!isFile(%levelPreviewImg))
@ -78,7 +169,7 @@ function ChooseLevelMenu::onWake(%this)
%preview = new GuiIconButtonCtrl() {
position = "0 0";
extent = %this.previewButtonSize;
extent = ChooseLevelMenu.previewButtonSize;
buttonType = "PushButton";
profile = GuiMenuButtonLeftJustProfile;
horizSizing = "right";
@ -86,7 +177,7 @@ function ChooseLevelMenu::onWake(%this)
internalName = "button";
class = "LevelPreviewButton";
//command = "$selectedLevelAsset = " @ %assetId @ ";";
altCommand = "ChooseLevelBegin(1);"; //allow doubleclick to quick action it
altCommand = "ChooseLevelBegin(" @ %i @ ");"; //allow doubleclick to quick action it
text = %levelAsset.levelName;
bitmapAsset = %levelPreviewImg;
levelAsset = %levelAsset;
@ -107,20 +198,10 @@ function ChooseLevelMenu::onWake(%this)
// Also add the new level mission as defined in the world editor settings
// if we are choosing a level to launch in the editor.
if ( %this.launchInEditor )
if ( ChooseLevelMenu.launchInEditor )
{
%this.addMissionFile( "tools/levels/DefaultEditorLevel.mis" );
ChooseLevelMenu.addMissionFile( "tools/levels/DefaultEditorLevel.mis" );
}
if(!$pref::HostMultiPlayer)
ChooseLevelTitleText.setText("SINGLE PLAYER");
else
ChooseLevelTitleText.setText("CREATE SERVER");
ChooseLevelMenuTabList.visible = $pref::HostMultiPlayer;
ChooseLevelMenuNavButtonOverlay.visible = $pref::HostMultiPlayer;
%this.schedule(32, openMenu, 0);
}
if(!isObject( ChooseLevelActionMap ) )
@ -133,8 +214,8 @@ if(!isObject( ChooseLevelActionMap ) )
ChooseLevelActionMap.bind( keyboard, e, ChooseLevelMenuNextMenu);
ChooseLevelActionMap.bind( gamepad, btn_r, ChooseLevelMenuNextMenu);
ChooseLevelActionMap.bind( keyboard, Space, ChooseLevelBegin );
ChooseLevelActionMap.bind( gamepad, btn_a, ChooseLevelBegin );
ChooseLevelActionMap.bind( keyboard, Space, ChooseLevelMenuOption );
ChooseLevelActionMap.bind( gamepad, btn_a, ChooseLevelMenuOption );
}
function ChooseLevelMenu::syncGUI(%this)
@ -169,14 +250,26 @@ function LevelPreviewArray::syncGUI(%this)
$selectedLevelAsset = %btn.levelAssetId;
}
function GameModePreviewArray::syncGUI(%this)
{
%btn = %this.getObject(%this.listPosition);
%btn.setHighlighted(true);
$pref::Server::GameMode = %btn.gameModeObject;
}
function ChooseLevelMenuPrevMenu(%val)
{
if(%val && $pref::HostMultiPlayer)
if(%val)
{
%currentIdx = ChooseLevelMenu.currentMenuIdx;
ChooseLevelMenu.currentMenuIdx -= 1;
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, 1);
%endIndex = 1;
if($pref::HostMultiPlayer)
%endIndex = 2;
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, %endIndex);
if(%currentIdx == ChooseLevelMenu.currentMenuIdx)
return;
@ -187,12 +280,16 @@ function ChooseLevelMenuPrevMenu(%val)
function ChooseLevelMenuNextMenu(%val)
{
if(%val && $pref::HostMultiPlayer)
if(%val)
{
%currentIdx = ChooseLevelMenu.currentMenuIdx;
ChooseLevelMenu.currentMenuIdx += 1;
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, 1);
%endIndex = 1;
if($pref::HostMultiPlayer)
%endIndex = 2;
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, %endIndex);
if(%currentIdx == ChooseLevelMenu.currentMenuIdx)
return;
@ -201,15 +298,17 @@ function ChooseLevelMenuNextMenu(%val)
}
}
function ChooseLevelMenu::openMenu(%this, %menuIdx)
{
LevelSelectContainer.setVisible(%menuIdx == 0);
ServerConfigContainer.setVisible(%menuIdx == 1);
GameModeSelectContainer.setVisible(%menuIdx == 0);
LevelSelectContainer.setVisible(%menuIdx == 1);
ServerConfigContainer.setVisible(%menuIdx == 2);
if(%menuIdx == 0)
$MenuList = LevelPreviewArray;
$MenuList = GameModePreviewArray;
else if(%menuIdx == 1)
$MenuList = LevelPreviewArray;
else if(%menuIdx == 2)
$MenuList = ServerConfigList;
%this.currentMenuIdx = %menuIdx;
@ -220,37 +319,63 @@ function ChooseLevelMenu::openMenu(%this, %menuIdx)
%this.syncGui();
}
function ChooseLevelBegin(%val)
function ChooseLevelMenuOption(%val)
{
if(%val)
{
// So we can't fire the button when loading is in progress.
if ( isObject( ServerGroup ) )
return;
Canvas.popDialog();
%entry = LevelPreviewArray.getObject(LevelPreviewArray.listPosition);
if(!AssetDatabase.isDeclaredAsset(%entry.levelAssetId))
{
MessageBoxOK("Error", "Selected level preview does not have a valid level asset!");
return;
}
$selectedLevelAsset = %entry.levelAssetId;
if(ChooseLevelMenu.currentMenuIdx == 0)
ChooseGameModeBegin(ChooseLevelMenu.listPosition);
else if(ChooseLevelMenu.currentMenuIdx == 1)
ChooseLevelBegin(ChooseLevelMenu.listPosition);
}
}
// Launch the chosen level with the editor open?
if ( ChooseLevelMenu.launchInEditor )
{
activatePackage( "BootEditor" );
ChooseLevelMenu.launchInEditor = false;
StartGame(%entry.levelAssetId, "SinglePlayer");
}
else
{
StartGame(%entry.levelAssetId);
}
function ChooseGameModeBegin(%index)
{
%entry = GameModePreviewArray.getObject(%index);
if(!isObject(%entry) || !isObject(%entry.gameModeObj))
{
MessageBoxOK("Error", "Selected game mode does not have a valid mode");
return;
}
$pref::Server::GameMode = %entry.gameModeObj;
ChooseLevelMenuTabList-->LevelBtn.active = true;
refreshLevelsList();
ChooseLevelMenu.openMenu(1);
}
function ChooseLevelBegin(%index)
{
// So we can't fire the button when loading is in progress.
if ( isObject( ServerGroup ) )
return;
Canvas.popDialog();
%entry = LevelPreviewArray.getObject(%index);
if(!AssetDatabase.isDeclaredAsset(%entry.levelAssetId))
{
MessageBoxOK("Error", "Selected level preview does not have a valid level asset!");
return;
}
$selectedLevelAsset = %entry.levelAssetId;
// Launch the chosen level with the editor open?
if ( ChooseLevelMenu.launchInEditor )
{
activatePackage( "BootEditor" );
ChooseLevelMenu.launchInEditor = false;
StartGame(%entry.levelAssetId, "SinglePlayer");
}
else
{
StartGame(%entry.levelAssetId);
}
}
@ -270,6 +395,23 @@ function ChooseLevelMenu::onSleep( %this )
}
}
function GameModePreviewButton::onHighlighted(%this, %highlighted)
{
if(%highlighted)
{
$MenuList.listPosition = $MenuList.getObjectIndex(%this);
GameModePreviewBitmap.bitmapAsset = %this.previewImage;
GameModePreviewBitmap.visible = (%this.previewImage !$= "");
GameModeNameText.text = %this.text;
GameModeDescriptionText.setText(%this.gameModeDesc);
GameModePreviewScroll.scrollToObject(%this);
}
}
function LevelPreviewButton::onHighlighted(%this, %highlighted)
{
if(%highlighted)

View file

@ -87,6 +87,7 @@ function initializeAssetBrowser()
exec("./scripts/looseFileAudit." @ $TorqueScriptFileExtension);
exec("./scripts/creator." @ $TorqueScriptFileExtension);
exec("./scripts/setAssetTarget." @ $TorqueScriptFileExtension);
exec("./scripts/utils." @ $TorqueScriptFileExtension);
//Processing for the different asset types
exec("./scripts/assetTypes/component." @ $TorqueScriptFileExtension);
@ -110,6 +111,7 @@ function initializeAssetBrowser()
exec("./scripts/assetTypes/looseFiles." @ $TorqueScriptFileExtension);
exec("./scripts/assetTypes/prefab." @ $TorqueScriptFileExtension);
exec("./scripts/assetTypes/creatorObj." @ $TorqueScriptFileExtension);
exec("./scripts/assetTypes/gameMode." @ $TorqueScriptFileExtension);
new ScriptObject( AssetBrowserPlugin )
{

View file

@ -79,7 +79,6 @@ function AssetBrowser_addModuleWindow::CreateNewModule(%this)
%line = strreplace( %line, "@@", %newModuleName );
%file.writeline(%line);
echo(%line);
}
%file.close();

View file

@ -0,0 +1,96 @@
function AssetBrowser::createGameMode(%this)
{
%moduleName = AssetBrowser.newAssetSettings.moduleName;
%moduleDef = ModuleDatabase.findModule(%moduleName, 1);
%assetName = AssetBrowser.newAssetSettings.assetName;
%assetPath = NewAssetTargetAddress.getText() @ "/";
%scriptPath = %assetPath @ %assetName @ "." @ $TorqueScriptFileExtension;
%fullScriptPath = makeFullPath(%scriptPath);
%file = new FileObject();
%templateFile = new FileObject();
%postFXTemplateCodeFilePath = %this.templateFilesPath @ "gameMode." @ $TorqueScriptFileExtension @ ".template";
if(%file.openForWrite(%fullScriptPath) && %templateFile.openForRead(%postFXTemplateCodeFilePath))
{
while( !%templateFile.isEOF() )
{
%line = %templateFile.readline();
%line = strreplace( %line, "@@", %assetName );
%file.writeline(%line);
}
%file.close();
%templateFile.close();
}
else
{
%file.close();
%templateFile.close();
warnf("createGameMode - Something went wrong and we couldn't write the gameMode script file!");
}
%localScriptPath = strReplace(%scriptPath, "data/" @ %moduleName @ "/", "./");
%execLine = " %this.queueExec(\"" @ %localScriptPath @ "\");";
%moduleScriptPath = makeFullPath(%moduleDef.ModuleScriptFilePath @ "." @ $TorqueScriptFileExtension);
echo("Attempting exec insert for file: " @ %moduleScriptPath);
%lineIdx = Tools::findInFile(%moduleScriptPath, "*function*" @ %moduleName @ "::initClient*");
if(%lineIdx != -1)
{
echo("INIT CLIENT FUNCTION LINE FOUND ON: " @ %lineIdx);
%insertLineIdx = Tools::findInFunction(%moduleScriptPath, %moduleName, "initClient", "*//--FILE EXEC END--*");
echo("FILE EXEC END LINE FOUND ON: " @ %insertLineIdx);
if(%insertLineIdx == -1)
{
//If there are not 'blocking' comments, then just slap the exec on the end of the function def
//as it doesn't really matter now
Tools::appendLineToFunction(%moduleScriptPath, %moduleName, "initClient", %execLine);
}
else
{
Tools::insertInFile(%moduleScriptPath, %insertLineIdx, %execLine, true);
}
}
%lineIdx = Tools::findInFile(%moduleScriptPath, "*function*" @ %moduleName @ "::initServer*");
if(%lineIdx != -1)
{
echo("INIT SERVER FUNCTION LINE FOUND ON: " @ %lineIdx);
%insertLineIdx = Tools::findInFunction(%moduleScriptPath, %moduleName, "initServer", "*//--FILE EXEC END--*");
echo("FILE EXEC END LINE FOUND ON: " @ %insertLineIdx);
if(%insertLineIdx == -1)
{
//If there are not 'blocking' comments, then just slap the exec on the end of the function def
//as it doesn't really matter now
Tools::appendLineToFunction(%moduleScriptPath, %moduleName, "initServer", %execLine);
}
else
{
Tools::insertInFile(%moduleScriptPath, %insertLineIdx, %execLine, true);
}
}
//and we'll go ahead and force execute the script file so the gamemode is 'available' for use immediately
exec(%scriptPath);
if(isObject(%assetName))
{
//it's possible it got moved to an instant group upon execution, so we'll just
//shove it back to the RootGroup by force to be 100% sure
RootGroup.add(%assetName);
}
return %scriptPath;
}

View file

@ -3,6 +3,8 @@ function AssetBrowser::setupCreateNewLevelAsset(%this)
NewAssetPropertiesInspector.startGroup("Level");
NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String", "Human-readable name of new level", "", "", %this.newAssetSettings);
NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image", "Preview Image for the level", "", "", %this.newAssetSettings);
NewAssetPropertiesInspector.addField("isSubScene", "Is SubScene", "bool", "Is this levelAsset intended as a subScene", "", "", %this.newAssetSettings);
NewAssetPropertiesInspector.endGroup();
}
@ -20,14 +22,16 @@ function AssetBrowser::createLevelAsset(%this)
%assetPath = NewAssetTargetAddress.getText() @ "/";
%misExtension = AssetBrowser.newAssetSettings.isSubScene ? ".subMis" : ".mis";
%tamlpath = %assetPath @ %assetName @ ".asset.taml";
%levelPath = %assetPath @ %assetName @ ".mis";
%levelPath = %assetPath @ %assetName @ %misExtension;
%asset = new LevelAsset()
{
AssetName = %assetName;
versionId = 1;
LevelFile = %assetName @ ".mis";
LevelFile = %assetName @ %misExtension;
DecalsFile = %assetName @ ".mis.decals";
PostFXPresetFile = %assetName @ ".postfxpreset." @ $TorqueScriptFileExtension;
ForestFile = %assetName @ ".forest";
@ -35,6 +39,7 @@ function AssetBrowser::createLevelAsset(%this)
LevelName = AssetBrowser.newAssetSettings.levelName;
AssetDescription = AssetBrowser.newAssetSettings.description;
PreviewImage = AssetBrowser.newAssetSettings.levelPreviewImage;
isSubScene = AssetBrowser.newAssetSettings.isSubScene;
};
TamlWrite(%asset, %tamlpath);
@ -58,15 +63,32 @@ function AssetBrowser::createLevelAsset(%this)
%moduleDef = ModuleDatabase.findModule(%moduleName, 1);
%addSuccess = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath);
if(!%addSuccess)
{
error("AssetBrowser::createLevelAsset() - failed to add declared asset: " @ %tamlpath @ " for module: " @ %moduleDef);
}
AssetBrowser.refresh();
return %tamlpath;
}
//==============================================================================
//SubScene derivative
//==============================================================================
function AssetBrowser::setupCreateNewSubScene(%this)
{
%this.newAssetSettings.isSubScene = true;
%this.newAssetSettings.assetType = "LevelAsset";
}
//==============================================================================
function AssetBrowser::editLevelAsset(%this, %assetDef)
{
schedule( 1, 0, "EditorOpenMission", %assetDef);
if(!%assetDef.isSubScene)
schedule( 1, 0, "EditorOpenMission", %assetDef);
}
//Renames the asset
@ -150,4 +172,100 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
"Asset Type: Level Asset\n" @
"Asset Definition ID: " @ %assetDef @ "\n" @
"Level File path: " @ %assetDef.getLevelPath();
}
function createAndAssignLevelAsset(%moduleName, %assetName)
{
$createAndAssignField.apply(%moduleName @ ":" @ %assetName);
}
function EWorldEditor::createSelectedAsSubScene( %this, %object )
{
//create new level asset here
AssetBrowser.setupCreateNewAsset("SubScene", AssetBrowser.selectedModule, "finishCreateSelectedAsSubScene");
%this.contextActionObject = %object;
}
function finishCreateSelectedAsSubScene(%assetId)
{
echo("finishCreateSelectedAsSubScene");
%subScene = new SubScene() {
levelAsset = %assetId;
};
%levelAssetDef = AssetDatabase.acquireAsset(%assetId);
%levelFilePath = %levelAssetDef.getLevelPath();
//write out to file
EWorldEditor.contextActionObject.save(%levelFilePath);
AssetDatabase.releaseAsset(%assetId);
getRootScene().add(%subScene);
EWorldEditor.contextActionObject.delete();
%subScene.load();
%subScene.recalculateBounds();
%scalar = $SubScene::createScalar;
if(%scalar $= "")
%scalar = 1.5;
//pad for loading boundary
%subScene.scale = VectorScale(%subScene.scale, %scalar);
}
function GuiInspectorTypeLevelAssetPtr::onControlDropped( %this, %payload, %position )
{
Canvas.popDialog(EditorDragAndDropLayer);
// Make sure this is a color swatch drag operation.
if( !%payload.parentGroup.isInNamespaceHierarchy( "AssetPreviewControlType_AssetDrop" ) )
return;
%assetType = %payload.assetType;
%module = %payload.moduleName;
%assetName = %payload.assetName;
if(%assetType $= "LevelAsset")
{
%cmd = %this @ ".apply(\""@ %module @ ":" @ %assetName @ "\");";
eval(%cmd);
}
EWorldEditor.isDirty = true;
}
function AssetBrowser::onLevelAssetEditorDropped(%this, %assetDef, %position)
{
%assetId = %assetDef.getAssetId();
if(!%assetDef.isSubScene)
{
errorf("Cannot drag-and-drop LevelAsset into WorldEditor");
return;
}
%newSubScene = new SubScene()
{
position = %position;
levelAsset = %assetId;
};
getScene(0).add(%newSubScene);
%newSubScene.load();
%newSubScene.recalculateBounds();
EWorldEditor.clearSelection();
EWorldEditor.selectObject(%newSubScene);
EWorldEditor.dropSelection();
EWorldEditor.isDirty = true;
MECreateUndoAction::submit(%newSubScene );
}

View file

@ -176,6 +176,31 @@ function AssetBrowser::performRenameAsset(%this, %originalAssetName, %newName)
%buildCommand = %this @ ".rename" @ EditAssetPopup.assetType @ "(" @ %assetDef @ "," @ %newName @ ");";
eval(%buildCommand);
}
else
{
//do generic action here
%oldAssetId = %moduleName @ ":" @ %originalAssetName;
%assetDef = AssetDatabase.acquireAsset(%oldAssetId);
%assetFileName = fileName(%assetDef.getFileName());
%assetFilePath = filePath(%assetDef.getFileName());
%pattern = %assetFilePath @ "/" @ %assetFileName @ ".*";
echo("Searching for matches of asset files following pattern: " @ %pattern);
//get list of files that match the name in the same dir
//do a rename on them
for (%file = findFirstFileMultiExpr(%pattern); %file !$= ""; %file = findNextFileMultiExpr(%pattern))
{
if(%file !$= %assetFileName)
renameAssetLooseFile(%file, %newName);
}
//update the assetDef
replaceInFile(%assetDef.getFileName(), %originalAssetName, %newName);
renameAssetFile(%assetDef, %newName);
}
}
else
{

View file

@ -117,7 +117,8 @@ function AssetBrowser::buildPopupMenus(%this)
//item[ 0 ] = "Create Component" TAB AddNewComponentAssetPopup;
item[ 0 ] = "Create Script" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"ScriptAsset\", AssetBrowser.selectedModule);";
item[ 1 ] = "Create State Machine" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"StateMachineAsset\", AssetBrowser.selectedModule);";
//item[ 3 ] = "-";
item[ 2 ] = "-";
item[ 3 ] = "Create Game Mode" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"GameMode\", AssetBrowser.selectedModule);";
//item[ 3 ] = "Create Game Object" TAB "" TAB "AssetBrowser.createNewGameObjectAsset(\"NewGameObject\", AssetBrowser.selectedModule);";
};
//%this.AddNewScriptAssetPopup.insertSubMenu(0, "Create Component", AddNewComponentAssetPopup);

View file

@ -0,0 +1,176 @@
//This file implements game mode logic for an Example gamemode. The primary functions:
//@@::onMissionStart
//@@::onMissionReset
//@@::onMissionEnd
//Are the primary hooks for the server to start, restart and end any active gamemodes
//onMissionStart, for example is called from core/clientServer/scripts/server/levelLoad.cs
//It's called once the server has successfully loaded the level, and has parsed
//through any active scenes to get GameModeNames defined by them. It then iterates
//over them and calls these callbacks to envoke gamemode behaviors. This allows multiple
//gamemodes to be in effect at one time. Modules can implement as many gamemodes as you want.
//
//For levels that can be reused for multiple gammodes, the general setup would be a primary level file
//with the Scene in it having the main geometry, weapons, terrain, etc. You would then have subScenes that
//each contain what's necessary for the given gamemode, such as a subScene that just adds the flags and capture
//triggers for a CTF mode. The subscene would then have it's GameModeName defined to run the CTF gamemode logic
//and the levelLoad code will execute it.
if(!isObject(@@))
{
new GameMode(@@){};
}
//This function is called when the level finishes loading. It sets up the initial configuration, variables and
//spawning and dynamic objects, timers or rules needed for the gamemode to run
function @@::onMissionStart(%this)
{
//set up the game and game variables
%this.initGameVars();
if (%this.isActive())
{
error("@@::onMissionStart: End the game first!");
return;
}
%this.setActive(true);
}
//This function is called when the level ends. It can be envoked due to the gamemode ending
//but is also kicked off when the game server is shut down as a form of cleanup for anything the gamemode
//created or is managing like the above mentioned dynamic objects or timers
function @@::onMissionEnded(%this)
{
if (!%this.isActive())
{
error("@@::onMissionEnded: No game running!");
return;
}
%this.setActive(false);
}
//This function is called in the event the server resets and is used to re-initialize the gamemode
function @@::onMissionReset(%this)
{
// Called by resetMission(), after all the temporary mission objects
// have been deleted.
%this.initGameVars();
}
//This sets up our gamemode's duration time
function @@::initGameVars(%this)
{
// Set the gameplay parameters
%this.duration = 30 * 60;
}
//This is called when the timer runs out, allowing the gamemode to end
function @@::onGameDurationEnd(%this)
{
//we don't end if we're currently editing the level
if (%this.duration && !(EditorIsActive() && GuiEditorIsActive()))
%this.onMissionEnded();
}
//This is called to actually spawn a control object for the player to utilize
//A player character, spectator camera, etc.
function @@::spawnControlObject(%this, %client)
{
//In this example, we just spawn a camera
/*if (!isObject(%client.camera))
{
if(!isObject(Observer))
{
datablock CameraData(Observer)
{
mode = "Observer";
};
}
%client.camera = spawnObject("Camera", Observer);
}
// If we have a camera then set up some properties
if (isObject(%client.camera))
{
MissionCleanup.add( %this.camera );
%client.camera.scopeToClient(%client);
%client.setControlObject(%client.camera);
%client.camera.setTransform("0 0 1 0 0 0 0");
}*/
}
//This is called when the client has finished loading the mission, but aren't "in" it yet
//allowing for some last-second prepwork
function @@::onClientMissionLoaded(%this)
{
$clientLoaded++;
if ($clientLoaded == $clientConneted)
$gameReady = true;
}
//This is called when the client has initially established a connection to the game server
//It's used for setting up anything ahead of time for the client, such as loading in client-passed
//config stuffs, saved data or the like that should be handled BEFORE the client has actually entered
//the game itself
function @@::onClientConnect(%this, %client)
{
$clientConneted++;
getPlayer(%client);
}
//This is called when a client enters the game server. It's used to spawn a player object
//set up any client-specific properties such as saved configs, values, their name, etc
//These callbacks are activated in core/clientServer/scripts/server/levelDownload.cs
function @@::onClientEnterGame(%this, %client)
{
$Game::DefaultPlayerClass = "Player";
$Game::DefaultPlayerDataBlock = "DefaultPlayerData";
$Game::DefaultPlayerSpawnGroups = "spawn_player CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
$Game::DefaultCameraClass = "Camera";
$Game::DefaultCameraDataBlock = "Observer";
$Game::DefaultCameraSpawnGroups = "spawn_player CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
//Spawn NPCs for the map and stuff here?
// This function currently relies on some helper functions defined in
// core/scripts/spawn.cs. For custom spawn behaviors one can either
// override the properties on the SpawnSphere's or directly override the
// functions themselves.
}
function @@::onSceneLoaded(%this)
{
}
function @@::onSceneUnloaded(%this)
{
}
function @@::onSubsceneLoaded(%this)
{
}
function @@::onSubsceneUnloaded(%this)
{
}
//This is called when the player leaves the game server. It's used to clean up anything that
//was spawned or setup for the client when it connected, in onClientEnterGame
//These callbacks are activated in core/clientServer/scripts/server/levelDownload.cs
function @@::onClientLeaveGame(%this, %client)
{
// Cleanup the camera
if (isObject(%this.camera))
%this.camera.delete();
// Cleanup the player
if (isObject(%this.player))
%this.player.delete();
}

View file

@ -9,6 +9,8 @@ function @@::onDestroy(%this)
//This is called when the server is initially set up by the game application
function @@::initServer(%this)
{
//--FILE EXEC BEGIN--
//--FILE EXEC END--
}
//This is called when the server is created for an actual game/map to be played
@ -17,16 +19,14 @@ function @@::onCreateGameServer(%this)
//These are common managed data files. For any datablock-based stuff that gets generated by the editors
//(that doesn't have a specific associated file, like data for a player class) will go into these.
//So we'll register them now if they exist.
if(isFile("./scripts/managedData/managedDatablocks." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedDatablocks");
if(isFile("./scripts/managedData/managedForestItemData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedForestItemData");
if(isFile("./scripts/managedData/managedForestBrushData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
if(isFile("./scripts/managedData/managedParticleEmitterData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
if(isFile("./scripts/managedData/managedParticleData." @ $TorqueScriptFileExtension))
%this.registerDatablock("./scripts/managedData/managedParticleData");
%this.registerDatablock("./scripts/managedData/managedDatablocks");
%this.registerDatablock("./scripts/managedData/managedForestItemData");
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
%this.registerDatablock("./scripts/managedData/managedParticleData");
//--DATABLOCK EXEC BEGIN--
//--DATABLOCK EXEC END--
}
//This is called when the server is shut down due to the game/map being exited
@ -37,6 +37,8 @@ function @@::onDestroyGameServer(%this)
//This is called when the client is initially set up by the game application
function @@::initClient(%this)
{
//--FILE EXEC BEGIN--
//--FILE EXEC END--
}
//This is called when a client connects to a server

View file

@ -0,0 +1,253 @@
function testRpl()
{
ToolUtilityScripts::appendLineToFunction("data/prototyping/prototyping.tscript", "Prototyping", "onDestroyGameServer", "//AAAAAAAAAAAAAAAAAAAAA");
}
function Tools::appendLineToFunction(%file, %nameSpace, %functionName, %appendLine)
{
%fileOutput = new ArrayObject(){};
%fileObj = new FileObject(){};
%insideFunction = false;
%scopeDepth = 0;
if ( %fileObj.openForRead( %file ) )
{
while ( !%fileObj.isEOF() )
{
%line = %fileObj.readLine();
if(strIsMatchExpr("*function *(*)*", %line))
{
%fileOutput.add(%line);
%start = strpos(%line, "function ");
%end = strpos(%line, "(", %start);
%scannedFunctionName = "";
if(%start != -1 && %end != -1)
{
%scannedFunctionName = getSubStr(%line, %start + 9, %end-%start-9);
}
%matchesFunctionSig = false;
if(%nameSpace !$= "")
{
if(%scannedFunctionName $= (%nameSpace @ "::" @ %functionName))
%matchesFunctionSig = true;
}
else
{
if(%scannedFunctionName $= %functionName)
%matchesFunctionSig = true;
}
if(!%matchesFunctionSig)
continue;
%insideFunction = true;
if(strIsMatchExpr("*{*", %line))
{
%scopeDepth++;
}
if(strIsMatchExpr("*}*", %line))
{
%scopeDepth--;
}
}
else
{
if(%insideFunction && strIsMatchExpr("*{*", %line))
{
%scopeDepth++;
}
if(%insideFunction && strIsMatchExpr("*}*", %line))
{
%scopeDepth--;
if(%scopeDepth == 0) //we've fully backed out of the function scope, so resolve back to the parent
{
%insideFunction = false;
%fileOutput.add(%appendLine);
}
}
%fileOutput.add(%line);
}
}
%fileObj.close();
}
if ( %fileObj.openForWrite( %file ) )
{
for(%i=0; %i < %fileOutput.count(); %i++)
{
%line = %fileOutput.getKey(%i);
%fileObj.writeLine(%line);
}
%fileObj.close();
}
}
function Tools::findInFile(%file, %findText, %startingLineId)
{
if(%startingLineId $= "")
%startingLineId = 0;
%fileObj = new FileObject(){};
if ( %fileObj.openForRead( %file ) )
{
%lineId = 0;
while ( !%fileObj.isEOF() )
{
if(%lineId >= %startingLineId)
{
%line = %fileObj.readLine();
if(strIsMatchExpr(%findText, %line))
{
return %lineId;
}
}
%lineId++;
}
%fileObj.close();
}
return -1;
}
function Tools::findInFunction(%file, %nameSpace, %functionName, %findText)
{
%fileObj = new FileObject(){};
%insideFunction = false;
%scopeDepth = 0;
if ( %fileObj.openForRead( %file ) )
{
%lineId = -1;
while ( !%fileObj.isEOF() )
{
%line = %fileObj.readLine();
%lineId++;
if(strIsMatchExpr("*function *(*)*", %line))
{
%start = strpos(%line, "function ");
%end = strpos(%line, "(", %start);
%scannedFunctionName = "";
if(%start != -1 && %end != -1)
{
%scannedFunctionName = getSubStr(%line, %start + 9, %end-%start-9);
}
%matchesFunctionSig = false;
if(%nameSpace !$= "")
{
if(%scannedFunctionName $= (%nameSpace @ "::" @ %functionName))
%matchesFunctionSig = true;
}
else
{
if(%scannedFunctionName $= %functionName)
%matchesFunctionSig = true;
}
if(!%matchesFunctionSig)
continue;
%insideFunction = true;
if(strIsMatchExpr("*{*", %line))
{
%scopeDepth++;
}
if(strIsMatchExpr("*}*", %line))
{
%scopeDepth--;
}
}
else
{
if(%insideFunction && strIsMatchExpr("*{*", %line))
{
%scopeDepth++;
}
if(%insideFunction && strIsMatchExpr("*}*", %line))
{
%scopeDepth--;
if(%scopeDepth == 0) //we've fully backed out of the function scope, so resolve back to the parent
{
%insideFunction = false;
break;
}
}
if(%insideFunction && strIsMatchExpr(%findText, %line))
{
break;
}
}
}
%fileObj.close();
}
return %lineId;
}
function Tools::insertInFile(%file, %insertLineId, %insertText, %insertBefore)
{
%fileOutput = new ArrayObject(){};
%fileObj = new FileObject(){};
if ( %fileObj.openForRead( %file ) )
{
%lineId = 0;
while ( !%fileObj.isEOF() )
{
%line = %fileObj.readLine();
if(%insertLineId == %lineId)
{
if(!%insertBefore || %insertBefore $= "")
{
%fileOutput.add(%line);
%fileOutput.add(%insertText);
}
else
{
%fileOutput.add(%insertText);
%fileOutput.add(%line);
}
}
else
{
%fileOutput.add(%line);
}
%lineId++;
}
%fileObj.close();
}
if ( %fileObj.openForWrite( %file ) )
{
for(%i=0; %i < %fileOutput.count(); %i++)
{
%line = %fileOutput.getKey(%i);
%fileObj.writeLine(%line);
}
%fileObj.close();
}
}

View file

@ -301,6 +301,10 @@ function ESettingsWindow::getGeneralSettings(%this)
SettingsInspector.addSettingsField("WorldEditor/AutosaveInterval", "Autosave Interval(in minutes)", "int", "");
SettingsInspector.endGroup();
SettingsInspector.startGroup("SubScenes");
SettingsInspector.addSettingsField("WorldEditor/subSceneCreateScalar", "SubScene Creation Scalar", "float", "Amount to scale SubScene's bounds by when creating from scene objects.", "1.5");
SettingsInspector.endGroup();
SettingsInspector.startGroup("Paths");
//SettingsInspector.addSettingsField("WorldEditor/torsionPath", "Torsion Path", "filename", "");
SettingsInspector.endGroup();

View file

@ -375,6 +375,8 @@
name="orthoShowGrid">1</Setting>
<Setting
name="startupMode">Blank Level</Setting>
<Setting
name="subSceneCreateScalar">2</Setting>
<Setting
name="torsionPath">AssetWork_Debug.exe</Setting>
<Setting

View file

@ -472,7 +472,7 @@ $guiContent = new GuiControl() {
Profile = "ToolsGuiButtonProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "290 22";
Position = "269 22";
Extent = "16 16";
MinExtent = "8 2";
canSave = "1";
@ -496,7 +496,7 @@ $guiContent = new GuiControl() {
Profile = "ToolsGuiButtonProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "311 22";
Position = "290 22";
Extent = "16 16";
MinExtent = "8 2";
canSave = "1";
@ -512,6 +512,30 @@ $guiContent = new GuiControl() {
useModifiers = "1";
};
new GuiBitmapButtonCtrl(EWAddSceneGroupButton) {
canSaveDynamicFields = "0";
internalName = "AddSceneGroup";
Enabled = "1";
isContainer = "0";
Profile = "ToolsGuiButtonProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "311 22";
Extent = "16 16";
MinExtent = "8 2";
canSave = "1";
Visible = "1";
tooltipprofile = "ToolsGuiToolTipProfile";
ToolTip = "Add Scene Group";
hovertime = "1000";
bitmapAsset = "ToolsModule:add_simgroup_btn_n_image";
buttonType = "PushButton";
groupNum = "-1";
text = "";
useMouseEvents = "0";
useModifiers = "1";
};
new GuiBitmapButtonCtrl() {
canSaveDynamicFields = "0";
internalName = "DeleteSelection";

View file

@ -2007,7 +2007,7 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
%popup.item[ 0 ] = "Delete" TAB "" TAB "EditorMenuEditDelete();";
%popup.item[ 1 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );";
%popup.item[ 2 ] = "-";
%popup.item[ 3 ] = "Make select a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";
%popup.item[ 3 ] = "Make selected a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";
}
else
{
@ -2103,6 +2103,14 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
%popup.enableItem(15, true);
}
}
else if(%obj.getClassName() $= "SimGroup" ||
%obj.getClassName() $= "SceneGroup")
{
//if it's ACTUALLY a SimGroup or SceneGroup, have the ability to
//upconvert to SubScene
%popup.item[ 12 ] = "-";
%popup.item[ 13 ] = "Convert to SubScene" TAB "" TAB "EWorldEditor.createSelectedAsSubScene( " @ %popup.object @ " );";
}
}
}
}
@ -2142,7 +2150,7 @@ function EditorTree::isValidDragTarget( %this, %id, %obj )
if( %obj.name $= "CameraBookmarks" )
return EWorldEditor.areAllSelectedObjectsOfType( "CameraBookmark" );
else
return ( %obj.getClassName() $= "SimGroup" || %obj.isMemberOfClass("Scene"));
return ( %obj.getClassName() $= "SimGroup" || %obj.isMemberOfClass("Scene") || %obj.isMemberOfClass("SceneGroup"));
}
function EditorTree::onBeginReparenting( %this )
@ -2582,6 +2590,77 @@ function EWorldEditor::addSimGroup( %this, %groupCurrentSelection )
%this.syncGui();
}
function EWorldEditor::addSceneGroup( %this, %groupCurrentSelection )
{
%activeSelection = %this.getActiveSelection();
if ( %groupCurrentSelection && %activeSelection.getObjectIndex( getScene(0) ) != -1 )
{
toolsMessageBoxOK( "Error", "Cannot add Scene to a new SceneGroup" );
return;
}
// Find our parent.
%parent = getScene(0);
if( !%groupCurrentSelection && isObject( %activeSelection ) && %activeSelection.getCount() > 0 )
{
%firstSelectedObject = %activeSelection.getObject( 0 );
if( %firstSelectedObject.isMemberOfClass( "SimGroup" ) )
%parent = %firstSelectedObject;
else if( %firstSelectedObject.getId() != getScene(0).getId() )
%parent = %firstSelectedObject.parentGroup;
}
// If we are about to do a group-selected as well,
// starting recording an undo compound.
if( %groupCurrentSelection )
Editor.getUndoManager().pushCompound( "Group Selected" );
// Create the SimGroup.
%object = new SceneGroup()
{
parentGroup = %parent;
};
MECreateUndoAction::submit( %object );
// Put selected objects into the group, if requested.
if( %groupCurrentSelection && isObject( %activeSelection ) )
{
%undo = UndoActionReparentObjects::create( EditorTree );
%numObjects = %activeSelection.getCount();
for( %i = 0; %i < %numObjects; %i ++ )
{
%sel = %activeSelection.getObject( %i );
%undo.add( %sel, %sel.parentGroup, %object );
%object.add( %sel );
}
%undo.addToManager( Editor.getUndoManager() );
}
// Stop recording for group-selected.
if( %groupCurrentSelection )
Editor.getUndoManager().popCompound();
// When not grouping selection, make the newly created SimGroup the
// current selection.
if( !%groupCurrentSelection )
{
EWorldEditor.clearSelection();
EWorldEditor.selectObject( %object );
}
// Refresh the Gui.
%this.syncGui();
}
function EWorldEditor::toggleLockChildren( %this, %simGroup )
{
foreach( %child in %simGroup )
@ -2847,6 +2926,16 @@ function EWAddSimGroupButton::onCtrlClick( %this )
EWorldEditor.addSimGroup( true );
}
function EWAddSceneGroupButton::onDefaultClick( %this )
{
EWorldEditor.addSceneGroup();
}
function EWAddSceneGroupButton::onCtrlClick( %this )
{
EWorldEditor.addSceneGroup( true );
}
//------------------------------------------------------------------------------
function EWToolsToolbar::reset( %this )

View file

@ -34,6 +34,7 @@ EditorSettings.setDefaultValue( "orthoFOV", "50" );
EditorSettings.setDefaultValue( "orthoShowGrid", "1" );
EditorSettings.setDefaultValue( "AutosaveInterval", "5" );
EditorSettings.setDefaultValue( "forceSidebarToSide", "1" );
EditorSettings.setDefaultValue( "subSceneCreateScalar", $SubScene::createScalar );
if( isFile( "C:/Program Files/Torsion/Torsion.exe" ) )
EditorSettings.setDefaultValue( "torsionPath", "C:/Program Files/Torsion/Torsion.exe" );

View file

@ -329,9 +329,6 @@ function EditorSaveMission()
if(EWorldEditor.isDirty || ETerrainEditor.isMissionDirty)
{
//Inform objects a save is happening, in case there is any special pre-save behavior a class needs to do
getScene(0).callOnChildren("onSaving", $Server::MissionFile);
getScene(0).save($Server::MissionFile);
}
@ -604,18 +601,20 @@ function EditorOpenSceneAppend(%levelAsset)
function MakeSelectionASublevel()
{
/*%size = EWorldEditor.getSelectionSize();
%size = EWorldEditor.getSelectionSize();
if ( %size == 0 )
return;
//Make a new Scene object
//Make a group for the objects to go into to be processed as into a
//subscene
%group = new SimGroup();
for(%i=0; %i < %size; %i++)
{
%group.add(EWorldEditor.getSelectedObject(%i));
}
%a = EWorldEditor.getSelectedObject(0);
%b = EWorldEditor.getSelectedObject(1);*/
//Now that we have a group, process it into a subscene
EWorldEditor.createSelectedAsSubScene(%group);
}
function updateEditorRecentLevelsList(%levelAssetId)