2007-06-14 23:31:57 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* /
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Text ;
using System.Windows.Forms ;
using System.IO ;
using System.Reflection ;
2008-01-02 21:49:43 +00:00
using System.Diagnostics ;
2008-05-29 11:54:45 +00:00
using CodeImp.DoomBuilder.Windows ;
2007-06-14 23:31:57 +00:00
using CodeImp.DoomBuilder.IO ;
using CodeImp.DoomBuilder.Map ;
2007-06-15 18:30:55 +00:00
using CodeImp.DoomBuilder.Editing ;
using CodeImp.DoomBuilder.Rendering ;
2007-10-05 11:17:58 +00:00
using CodeImp.DoomBuilder.Data ;
2008-05-29 11:34:01 +00:00
using CodeImp.DoomBuilder.Actions ;
2007-10-21 18:06:10 +00:00
using CodeImp.DoomBuilder.Config ;
2008-01-02 21:49:43 +00:00
using CodeImp.DoomBuilder.Plugins ;
2008-11-13 23:05:16 +00:00
using CodeImp.DoomBuilder.Compilers ;
2009-01-10 00:26:24 +00:00
using CodeImp.DoomBuilder.VisualModes ;
2007-06-14 23:31:57 +00:00
#endregion
namespace CodeImp.DoomBuilder
{
2008-11-27 10:33:09 +00:00
public sealed class MapManager
2007-06-14 23:31:57 +00:00
{
#region = = = = = = = = = = = = = = = = = = Constants
2007-10-13 14:05:45 +00:00
// Map header name in temporary file
2008-09-17 19:21:45 +00:00
internal const string TEMP_MAP_HEADER = "TEMPMAP" ;
internal const string BUILD_MAP_HEADER = "MAP01" ;
2007-10-14 15:44:55 +00:00
public const string CONFIG_MAP_HEADER = "~MAP" ;
2007-06-24 18:56:43 +00:00
2007-10-13 14:05:45 +00:00
// Save modes
public const int SAVE_NORMAL = 0 ;
public const int SAVE_AS = 1 ;
public const int SAVE_INTO = 2 ;
public const int SAVE_TEST = 3 ;
2007-06-14 23:31:57 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Status
private bool changed ;
2008-11-10 16:11:44 +00:00
private bool scriptschanged ;
2007-06-14 23:31:57 +00:00
// Map information
private string filetitle ;
private string filepathname ;
2007-10-13 14:05:45 +00:00
private string temppath ;
2008-05-23 06:00:37 +00:00
// Main objects
2007-10-05 11:17:58 +00:00
private MapSet map ;
2007-10-13 14:05:45 +00:00
private MapSetIO io ;
2007-06-14 23:31:57 +00:00
private MapOptions options ;
2007-09-27 22:55:03 +00:00
private ConfigurationInfo configinfo ;
2007-10-21 18:06:10 +00:00
private GameConfiguration config ;
2007-10-05 11:17:58 +00:00
private DataManager data ;
2007-10-31 20:34:09 +00:00
private D3DDevice graphics ;
private Renderer2D renderer2d ;
private Renderer3D renderer3d ;
2007-06-24 18:56:43 +00:00
private WAD tempwad ;
2007-11-10 19:24:52 +00:00
private GridSetup grid ;
2007-11-12 22:43:01 +00:00
private UndoManager undoredo ;
2008-09-16 13:43:47 +00:00
private CopyPasteManager copypaste ;
2008-05-23 06:00:37 +00:00
private Launcher launcher ;
2008-05-26 20:06:15 +00:00
private ThingsFilter thingsfilter ;
2008-11-10 16:11:44 +00:00
private ScriptEditorForm scriptwindow ;
2008-11-14 16:19:25 +00:00
private List < CompilerError > errors ;
2009-01-10 00:26:24 +00:00
private VisualCamera visualcamera ;
2007-06-15 18:30:55 +00:00
2007-06-14 23:31:57 +00:00
// Disposing
private bool isdisposed = false ;
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public string FilePathName { get { return filepathname ; } }
public string FileTitle { get { return filetitle ; } }
2007-10-13 14:05:45 +00:00
public string TempPath { get { return temppath ; } }
2008-01-02 21:49:43 +00:00
internal MapOptions Options { get { return options ; } }
2007-10-05 11:17:58 +00:00
public MapSet Map { get { return map ; } }
2007-10-07 22:21:47 +00:00
public DataManager Data { get { return data ; } }
2008-11-10 16:11:44 +00:00
public bool IsChanged { get { return changed | CheckScriptChanged ( ) ; } set { changed | = value ; } }
2007-06-14 23:31:57 +00:00
public bool IsDisposed { get { return isdisposed ; } }
2008-01-02 21:49:43 +00:00
internal D3DDevice Graphics { get { return graphics ; } }
public IRenderer2D Renderer2D { get { return renderer2d ; } }
public IRenderer3D Renderer3D { get { return renderer3d ; } }
2008-10-15 11:46:43 +00:00
internal Renderer2D CRenderer2D { get { return renderer2d ; } }
internal Renderer3D CRenderer3D { get { return renderer3d ; } }
2007-10-24 17:25:03 +00:00
public GameConfiguration Config { get { return config ; } }
2008-05-23 06:00:37 +00:00
internal ConfigurationInfo ConfigSettings { get { return configinfo ; } }
2007-11-10 19:24:52 +00:00
public GridSetup Grid { get { return grid ; } }
2007-11-12 22:43:01 +00:00
public UndoManager UndoRedo { get { return undoredo ; } }
2008-12-31 16:43:23 +00:00
internal CopyPasteManager CopyPaste { get { return copypaste ; } }
2008-05-05 22:22:53 +00:00
public IMapSetIO FormatInterface { get { return io ; } }
2008-05-23 06:00:37 +00:00
internal Launcher Launcher { get { return launcher ; } }
2008-05-26 20:06:15 +00:00
public ThingsFilter ThingsFilter { get { return thingsfilter ; } }
2008-11-14 16:19:25 +00:00
internal List < CompilerError > Errors { get { return errors ; } }
2008-11-17 23:32:13 +00:00
internal ScriptEditorForm ScriptEditor { get { return scriptwindow ; } }
2009-01-10 00:26:24 +00:00
public VisualCamera VisualCamera { get { return visualcamera ; } set { visualcamera = value ; } }
2008-11-10 16:11:44 +00:00
public bool IsScriptsWindowOpen { get { return ( scriptwindow ! = null ) & & ! scriptwindow . IsDisposed ; } }
2007-06-14 23:31:57 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
2007-06-26 08:47:19 +00:00
// Constructor
2008-01-02 21:49:43 +00:00
internal MapManager ( )
2007-06-14 23:31:57 +00:00
{
// We have no destructor
GC . SuppressFinalize ( this ) ;
2008-04-27 12:07:26 +00:00
2008-05-23 06:00:37 +00:00
// Create temporary path
temppath = General . MakeTempDirname ( ) ;
Directory . CreateDirectory ( temppath ) ;
General . WriteLogLine ( "Temporary directory: " + temppath ) ;
2007-10-20 12:34:27 +00:00
// Basic objects
2007-11-10 19:24:52 +00:00
grid = new GridSetup ( ) ;
2007-11-12 22:43:01 +00:00
undoredo = new UndoManager ( ) ;
2008-09-16 13:43:47 +00:00
copypaste = new CopyPasteManager ( ) ;
2008-05-23 06:00:37 +00:00
launcher = new Launcher ( this ) ;
2008-05-26 20:06:15 +00:00
thingsfilter = new NullThingsFilter ( ) ;
2007-06-14 23:31:57 +00:00
}
2008-01-02 21:49:43 +00:00
// Disposer
2008-11-10 16:11:44 +00:00
internal bool Dispose ( )
2007-06-14 23:31:57 +00:00
{
// Not already disposed?
if ( ! isdisposed )
{
2009-02-22 22:57:21 +00:00
// Stop processing
General . MainWindow . StopProcessing ( ) ;
2008-11-10 16:11:44 +00:00
// Close script editor
CloseScriptEditor ( false ) ;
2007-10-20 19:50:03 +00:00
// Change to no mode
2008-11-27 11:59:17 +00:00
General . Editing . ChangeMode ( ( EditMode ) null ) ;
2007-10-20 19:50:03 +00:00
2007-10-14 21:31:45 +00:00
// Unbind any methods
2008-04-27 12:07:26 +00:00
General . Actions . UnbindMethods ( this ) ;
2008-11-10 16:11:44 +00:00
2007-06-14 23:31:57 +00:00
// Dispose
2008-06-10 08:35:14 +00:00
if ( grid ! = null ) grid . Dispose ( ) ;
2008-05-23 06:00:37 +00:00
if ( launcher ! = null ) launcher . Dispose ( ) ;
2008-09-16 13:43:47 +00:00
if ( copypaste ! = null ) copypaste . Dispose ( ) ;
2008-02-04 13:47:36 +00:00
if ( undoredo ! = null ) undoredo . Dispose ( ) ;
2007-10-05 11:17:58 +00:00
General . WriteLogLine ( "Unloading data resources..." ) ;
2007-11-10 01:58:08 +00:00
if ( data ! = null ) data . Dispose ( ) ;
2007-10-05 11:17:58 +00:00
General . WriteLogLine ( "Closing temporary file..." ) ;
2007-11-10 01:58:08 +00:00
if ( tempwad ! = null ) tempwad . Dispose ( ) ;
2007-10-05 11:17:58 +00:00
General . WriteLogLine ( "Unloading map data..." ) ;
2007-11-10 01:58:08 +00:00
if ( map ! = null ) map . Dispose ( ) ;
2007-10-05 11:17:58 +00:00
General . WriteLogLine ( "Stopping graphics device..." ) ;
2007-11-10 01:58:08 +00:00
if ( renderer2d ! = null ) renderer2d . Dispose ( ) ;
if ( renderer3d ! = null ) renderer3d . Dispose ( ) ;
if ( graphics ! = null ) graphics . Dispose ( ) ;
2009-01-10 00:26:24 +00:00
visualcamera = null ;
2008-11-27 10:33:09 +00:00
grid = null ;
launcher = null ;
copypaste = null ;
undoredo = null ;
data = null ;
tempwad = null ;
map = null ;
renderer2d = null ;
renderer3d = null ;
graphics = null ;
// We may spend some time to clean things up here
GC . Collect ( ) ;
2007-10-20 12:34:27 +00:00
2007-06-24 18:56:43 +00:00
// Remove temp file
2007-10-13 14:05:45 +00:00
General . WriteLogLine ( "Removing temporary directory..." ) ;
try { Directory . Delete ( temppath , true ) ; } catch ( Exception e )
{
General . WriteLogLine ( e . GetType ( ) . Name + ": " + e . Message ) ;
General . WriteLogLine ( "Failed to remove temporary directory!" ) ;
}
2007-06-14 23:31:57 +00:00
// Done
isdisposed = true ;
2008-11-10 16:11:44 +00:00
return true ;
}
else
{
// Already closed
return true ;
2007-06-14 23:31:57 +00:00
}
}
#endregion
2007-10-14 15:44:55 +00:00
#region = = = = = = = = = = = = = = = = = = New / Open
2007-06-15 18:30:55 +00:00
// Initializes for a new map
2008-01-02 21:49:43 +00:00
internal bool InitializeNewMap ( MapOptions options )
2007-06-15 18:30:55 +00:00
{
2007-10-05 10:00:15 +00:00
string tempfile ;
2007-06-15 18:30:55 +00:00
// Apply settings
this . filetitle = "unnamed.wad" ;
this . filepathname = "" ;
this . changed = false ;
this . options = options ;
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Creating new map '" + options . CurrentName + "' with configuration '" + options . ConfigFile + "'" ) ;
2007-07-07 09:40:34 +00:00
// Initiate graphics
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Initializing graphics device..." ) ;
2007-10-31 20:34:09 +00:00
graphics = new D3DDevice ( General . MainWindow . Display ) ;
2007-07-07 09:40:34 +00:00
if ( ! graphics . Initialize ( ) ) return false ;
2007-10-31 20:34:09 +00:00
// Create renderers
renderer2d = new Renderer2D ( graphics ) ;
renderer3d = new Renderer3D ( graphics ) ;
2007-07-07 09:40:34 +00:00
// Load game configuration
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Loading game configuration..." ) ;
2007-09-27 22:55:03 +00:00
configinfo = General . GetConfigurationInfo ( options . ConfigFile ) ;
2007-10-21 18:06:10 +00:00
config = new GameConfiguration ( General . LoadGameConfiguration ( options . ConfigFile ) ) ;
2008-11-27 19:25:13 +00:00
configinfo . ApplyDefaults ( config ) ;
2008-11-27 11:59:17 +00:00
General . Editing . UpdateCurrentEditModes ( ) ;
2007-10-21 18:06:10 +00:00
2007-07-07 09:40:34 +00:00
// Create map data
2007-10-05 11:17:58 +00:00
map = new MapSet ( ) ;
2007-07-07 09:40:34 +00:00
2007-06-26 08:47:19 +00:00
// Create temp wadfile
2007-10-13 14:05:45 +00:00
tempfile = General . MakeTempFilename ( temppath ) ;
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Creating temporary file: " + tempfile ) ;
tempwad = new WAD ( tempfile ) ;
2007-10-13 14:05:45 +00:00
// Read the map from temp file
2007-10-21 18:06:10 +00:00
General . WriteLogLine ( "Initializing map format interface " + config . FormatInterface + "..." ) ;
io = MapSetIO . Create ( config . FormatInterface , tempwad , this ) ;
2007-06-26 08:47:19 +00:00
2007-10-14 17:48:15 +00:00
// Create required lumps
General . WriteLogLine ( "Creating map data structures..." ) ;
tempwad . Insert ( TEMP_MAP_HEADER , 0 , 0 ) ;
io . Write ( map , TEMP_MAP_HEADER , 1 ) ;
CreateRequiredLumps ( tempwad , TEMP_MAP_HEADER ) ;
2008-05-26 20:06:15 +00:00
2007-10-05 11:17:58 +00:00
// Load data manager
General . WriteLogLine ( "Loading data resources..." ) ;
data = new DataManager ( ) ;
data . Load ( configinfo . Resources , options . Resources ) ;
2008-10-15 11:46:43 +00:00
// Update structures
2009-02-23 18:23:39 +00:00
options . ApplyGridSettings ( ) ;
2009-01-21 16:18:30 +00:00
map . UpdateConfiguration ( ) ;
2008-10-15 11:46:43 +00:00
map . Update ( ) ;
thingsfilter . Update ( ) ;
2008-11-17 00:41:52 +00:00
2007-10-14 21:31:45 +00:00
// Bind any methods
2008-04-27 12:07:26 +00:00
General . Actions . BindMethods ( this ) ;
2007-10-14 21:31:45 +00:00
2009-01-10 00:26:24 +00:00
// Set defaults
this . visualcamera = new VisualCamera ( ) ;
2008-11-27 11:59:17 +00:00
General . Editing . ChangeMode ( "VerticesMode" ) ;
ClassicMode cmode = ( General . Editing . Mode as ClassicMode ) ;
2009-01-03 09:38:09 +00:00
if ( cmode ! = null ) cmode . SetZoom ( 0.5f ) ;
2008-11-17 00:41:52 +00:00
renderer2d . SetViewMode ( ( ViewMode ) General . Settings . DefaultViewMode ) ;
2009-03-01 19:19:43 +00:00
General . Settings . SetDefaultThingFlags ( config . DefaultThingFlags ) ;
2009-02-26 16:03:43 +00:00
2007-06-15 18:30:55 +00:00
// Success
2009-01-03 22:18:59 +00:00
this . changed = false ;
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Map creation done" ) ;
2007-06-15 18:30:55 +00:00
return true ;
}
2007-06-16 19:53:51 +00:00
// Initializes for an existing map
2008-01-02 21:49:43 +00:00
internal bool InitializeOpenMap ( string filepathname , MapOptions options )
2007-06-16 19:53:51 +00:00
{
2007-06-24 18:56:43 +00:00
WAD mapwad ;
2007-10-05 10:00:15 +00:00
string tempfile ;
2007-10-05 11:17:58 +00:00
DataLocation maplocation ;
2007-06-24 18:56:43 +00:00
2007-06-16 19:53:51 +00:00
// Apply settings
this . filetitle = Path . GetFileName ( filepathname ) ;
this . filepathname = filepathname ;
this . changed = false ;
this . options = options ;
2009-01-10 00:26:24 +00:00
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Opening map '" + options . CurrentName + "' with configuration '" + options . ConfigFile + "'" ) ;
2007-10-13 14:05:45 +00:00
2007-07-07 09:40:34 +00:00
// Initiate graphics
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Initializing graphics device..." ) ;
2007-10-31 20:34:09 +00:00
graphics = new D3DDevice ( General . MainWindow . Display ) ;
2007-07-07 09:40:34 +00:00
if ( ! graphics . Initialize ( ) ) return false ;
2007-10-31 20:34:09 +00:00
// Create renderers
renderer2d = new Renderer2D ( graphics ) ;
renderer3d = new Renderer3D ( graphics ) ;
2008-01-02 21:49:43 +00:00
2007-07-07 09:40:34 +00:00
// Load game configuration
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Loading game configuration..." ) ;
configinfo = General . GetConfigurationInfo ( options . ConfigFile ) ;
2007-10-21 18:06:10 +00:00
config = new GameConfiguration ( General . LoadGameConfiguration ( options . ConfigFile ) ) ;
2008-11-27 19:25:13 +00:00
configinfo . ApplyDefaults ( config ) ;
2008-11-27 11:59:17 +00:00
General . Editing . UpdateCurrentEditModes ( ) ;
2008-01-02 21:49:43 +00:00
2007-07-07 09:40:34 +00:00
// Create map data
2007-10-05 11:17:58 +00:00
map = new MapSet ( ) ;
2007-07-07 09:40:34 +00:00
2007-06-24 18:56:43 +00:00
// Create temp wadfile
2007-10-13 14:05:45 +00:00
tempfile = General . MakeTempFilename ( temppath ) ;
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Creating temporary file: " + tempfile ) ;
tempwad = new WAD ( tempfile ) ;
2007-07-07 09:40:34 +00:00
2007-06-24 18:56:43 +00:00
// Now open the map file
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Opening source file: " + filepathname ) ;
2007-06-24 18:56:43 +00:00
mapwad = new WAD ( filepathname , true ) ;
// Copy the map lumps to the temp file
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Copying map lumps to temporary file..." ) ;
2007-06-24 18:56:43 +00:00
CopyLumpsByType ( mapwad , options . CurrentName , tempwad , TEMP_MAP_HEADER ,
true , true , true , true ) ;
// Close the map file
mapwad . Dispose ( ) ;
// Read the map from temp file
2007-10-21 18:06:10 +00:00
General . WriteLogLine ( "Initializing map format interface " + config . FormatInterface + "..." ) ;
io = MapSetIO . Create ( config . FormatInterface , tempwad , this ) ;
2007-10-13 14:05:45 +00:00
General . WriteLogLine ( "Reading map data structures from file..." ) ;
2007-11-10 01:58:08 +00:00
try { map = io . Read ( map , TEMP_MAP_HEADER ) ; }
2007-12-28 12:50:34 +00:00
catch ( Exception e )
2007-11-10 01:58:08 +00:00
{
2009-02-26 23:27:46 +00:00
General . ErrorLogger . Add ( ErrorType . Error , e . GetType ( ) . Name + ": " + e . Message ) ;
2007-11-10 01:58:08 +00:00
General . ShowErrorMessage ( "Unable to read the map data structures with the specified configuration." , MessageBoxButtons . OK ) ;
return false ;
}
2008-05-26 20:06:15 +00:00
2007-10-05 11:17:58 +00:00
// Load data manager
General . WriteLogLine ( "Loading data resources..." ) ;
data = new DataManager ( ) ;
2009-01-31 09:09:49 +00:00
maplocation = new DataLocation ( DataLocation . RESOURCE_WAD , filepathname , options . StrictPatches , false ) ;
2007-10-05 11:17:58 +00:00
data . Load ( configinfo . Resources , options . Resources , maplocation ) ;
2008-10-15 11:46:43 +00:00
// Update structures
2009-02-23 18:23:39 +00:00
options . ApplyGridSettings ( ) ;
2009-01-21 16:18:30 +00:00
map . UpdateConfiguration ( ) ;
2009-01-03 22:18:59 +00:00
map . SnapAllToAccuracy ( ) ;
2008-10-15 11:46:43 +00:00
map . Update ( ) ;
thingsfilter . Update ( ) ;
2008-09-28 21:20:56 +00:00
2007-10-14 21:31:45 +00:00
// Bind any methods
2008-04-27 12:07:26 +00:00
General . Actions . BindMethods ( this ) ;
2007-10-14 21:31:45 +00:00
2009-01-10 00:26:24 +00:00
// Set defaults
this . visualcamera = new VisualCamera ( ) ;
2008-11-27 11:59:17 +00:00
General . Editing . ChangeMode ( "VerticesMode" ) ;
2008-11-17 00:41:52 +00:00
renderer2d . SetViewMode ( ( ViewMode ) General . Settings . DefaultViewMode ) ;
2009-03-01 19:19:43 +00:00
General . Settings . SetDefaultThingFlags ( config . DefaultThingFlags ) ;
2007-06-16 19:53:51 +00:00
2007-10-20 01:04:47 +00:00
// Center map in screen
2008-11-27 11:59:17 +00:00
if ( General . Editing . Mode is ClassicMode ) ( General . Editing . Mode as ClassicMode ) . CenterInScreen ( ) ;
2007-10-20 01:04:47 +00:00
2007-06-16 19:53:51 +00:00
// Success
2009-01-03 22:18:59 +00:00
this . changed = false ;
2007-10-05 10:00:15 +00:00
General . WriteLogLine ( "Map loading done" ) ;
2007-06-16 19:53:51 +00:00
return true ;
}
2007-06-15 18:30:55 +00:00
#endregion
2007-10-13 14:05:45 +00:00
#region = = = = = = = = = = = = = = = = = = Save
// Initializes for an existing map
2008-01-02 21:49:43 +00:00
internal bool SaveMap ( string newfilepathname , int savemode )
2007-10-13 14:05:45 +00:00
{
MapSet outputset ;
2009-02-26 14:16:18 +00:00
string nodebuildername , settingsfile ;
StatusInfo oldstatus ;
2007-10-14 15:44:55 +00:00
WAD targetwad ;
int index ;
2008-11-15 13:12:09 +00:00
bool includenodes = false ;
2007-10-14 21:35:49 +00:00
string origmapname ;
2007-10-14 17:48:15 +00:00
General . WriteLogLine ( "Saving map to file: " + newfilepathname ) ;
2007-10-13 14:05:45 +00:00
2008-11-10 16:11:44 +00:00
// If the scripts window is open, save the scripts first
if ( IsScriptsWindowOpen ) scriptwindow . Editor . ImplicitSave ( ) ;
2008-11-15 13:12:09 +00:00
// Only recompile scripts when the scripts have changed
// (not when only the map changed)
if ( CheckScriptChanged ( ) )
{
if ( ! CompileScriptLumps ( ) )
{
// Compiler failure
if ( errors . Count > 0 )
General . ShowErrorMessage ( "Error while compiling scripts: " + errors [ 0 ] . description , MessageBoxButtons . OK ) ;
else
General . ShowErrorMessage ( "Unknown compiler error while compiling scripts!" , MessageBoxButtons . OK ) ;
}
else
{
if ( errors ! = null )
{
if ( scriptwindow ! = null ) scriptwindow . Editor . ShowErrors ( errors ) ;
if ( errors . Count > 0 ) General . ShowWarningMessage ( "The compiler was unable to compile all scripts in your map, due to script errors." , MessageBoxButtons . OK ) ;
}
}
}
2007-10-13 14:05:45 +00:00
2009-01-04 11:35:05 +00:00
// Only write the map and rebuild nodes when the actual map has changed
2008-11-15 13:12:09 +00:00
// (not when only scripts have changed)
if ( changed )
{
2009-01-04 11:35:05 +00:00
// Make a copy of the map data
outputset = map . Clone ( ) ;
// Remove all flags from all 3D Start things
foreach ( Thing t in outputset . Things )
{
if ( t . Type = = config . Start3DModeThingType )
{
List < string > flagkeys = new List < string > ( t . Flags . Keys ) ;
foreach ( string k in flagkeys ) t . Flags [ k ] = false ;
}
}
// Do we need sidedefs compression?
if ( map . Sidedefs . Count > io . MaxSidedefs )
{
// Compress sidedefs
outputset . CompressSidedefs ( ) ;
// Check if it still doesnt fit
if ( map . Sidedefs . Count > io . MaxSidedefs )
{
// Problem! Can't save the map like this!
General . ShowErrorMessage ( "Unable to save the map: There are too many unique sidedefs!" , MessageBoxButtons . OK ) ;
return false ;
}
}
// TODO: Check for more limitations
// Write to temporary file
General . WriteLogLine ( "Writing map data structures to file..." ) ;
index = tempwad . FindLumpIndex ( TEMP_MAP_HEADER ) ;
if ( index = = - 1 ) index = 0 ;
io . Write ( outputset , TEMP_MAP_HEADER , index ) ;
outputset . Dispose ( ) ;
2008-11-15 13:12:09 +00:00
// Get the corresponding nodebuilder
2009-01-04 11:35:05 +00:00
nodebuildername = savemode = = SAVE_TEST ? configinfo . NodebuilderTest : configinfo . NodebuilderSave ;
2008-11-15 13:12:09 +00:00
// Build the nodes
2009-02-26 14:16:18 +00:00
oldstatus = General . MainWindow . Status ;
General . MainWindow . DisplayStatus ( StatusType . Busy , "Building map nodes..." ) ;
2009-01-04 11:35:05 +00:00
if ( ! string . IsNullOrEmpty ( nodebuildername ) )
2008-11-15 13:12:09 +00:00
includenodes = BuildNodes ( nodebuildername , true ) ;
else
includenodes = false ;
General . MainWindow . DisplayStatus ( oldstatus ) ;
}
2009-01-04 11:35:05 +00:00
else
{
// Check if we have nodebuilder lumps
includenodes = VerifyNodebuilderLumps ( tempwad , TEMP_MAP_HEADER ) ;
}
2007-10-13 14:05:45 +00:00
// Suspend data resources
data . Suspend ( ) ;
2009-01-05 19:49:55 +00:00
// Determine original map name
origmapname = ( options . PreviousName ! = "" ) ? options . PreviousName : options . CurrentName ;
2007-10-15 05:08:39 +00:00
try
2007-10-14 17:48:15 +00:00
{
2009-01-04 22:26:23 +00:00
// Backup existing file, if any
if ( File . Exists ( newfilepathname ) )
{
if ( File . Exists ( newfilepathname + ".backup3" ) ) File . Delete ( newfilepathname + ".backup3" ) ;
if ( File . Exists ( newfilepathname + ".backup2" ) ) File . Move ( newfilepathname + ".backup2" , newfilepathname + ".backup3" ) ;
if ( File . Exists ( newfilepathname + ".backup1" ) ) File . Move ( newfilepathname + ".backup1" , newfilepathname + ".backup2" ) ;
File . Copy ( newfilepathname , newfilepathname + ".backup1" ) ;
}
2007-10-15 05:08:39 +00:00
// Except when saving INTO another file,
// kill the target file if it is different from source file
if ( ( savemode ! = SAVE_INTO ) & & ( newfilepathname ! = filepathname ) )
{
// Kill target file
if ( File . Exists ( newfilepathname ) ) File . Delete ( newfilepathname ) ;
// Kill .dbs settings file
settingsfile = newfilepathname . Substring ( 0 , newfilepathname . Length - 4 ) + ".dbs" ;
if ( File . Exists ( settingsfile ) ) File . Delete ( settingsfile ) ;
}
2007-10-14 21:31:45 +00:00
2007-10-15 05:08:39 +00:00
// On Save AS we have to copy the previous file to the new file
if ( ( savemode = = SAVE_AS ) & & ( filepathname ! = "" ) )
{
// Copy if original file still exists
if ( File . Exists ( filepathname ) ) File . Copy ( filepathname , newfilepathname , true ) ;
}
2009-01-05 19:49:55 +00:00
// If the target file exists, we need to rebuild it
if ( File . Exists ( newfilepathname ) )
{
// Move the target file aside
string origwadfile = newfilepathname + ".temp" ;
File . Move ( newfilepathname , origwadfile ) ;
// Open original file
WAD origwad = new WAD ( origwadfile , true ) ;
// Create new target file
targetwad = new WAD ( newfilepathname ) ;
// Copy all lumps, except the original map
CopyAllLumpsExceptMap ( origwad , targetwad , origmapname ) ;
// Close original file and delete it
origwad . Dispose ( ) ;
File . Delete ( origwadfile ) ;
}
else
{
// Create new target file
targetwad = new WAD ( newfilepathname ) ;
}
2007-10-14 17:48:15 +00:00
}
2007-10-15 05:08:39 +00:00
catch ( IOException )
2007-10-14 15:44:55 +00:00
{
2007-10-15 05:08:39 +00:00
General . ShowErrorMessage ( "IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program." , MessageBoxButtons . OK ) ;
data . Resume ( ) ;
General . WriteLogLine ( "Map saving failed" ) ;
return false ;
}
catch ( UnauthorizedAccessException )
{
General . ShowErrorMessage ( "Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program." , MessageBoxButtons . OK ) ;
data . Resume ( ) ;
General . WriteLogLine ( "Map saving failed" ) ;
return false ;
2007-10-14 15:44:55 +00:00
}
// Copy map lumps to target file
2007-10-14 21:35:49 +00:00
CopyLumpsByType ( tempwad , TEMP_MAP_HEADER , targetwad , origmapname , true , true , includenodes , true ) ;
2007-10-14 15:44:55 +00:00
// Was the map lump name renamed?
if ( ( options . PreviousName ! = options . CurrentName ) & &
( options . PreviousName ! = "" ) )
{
General . WriteLogLine ( "Renaming map lump name from " + options . PreviousName + " to " + options . CurrentName ) ;
// Find the map header in target
index = targetwad . FindLumpIndex ( options . PreviousName ) ;
if ( index > - 1 )
{
// Rename the map lump name
targetwad . Lumps [ index ] . Rename ( options . CurrentName ) ;
options . PreviousName = "" ;
}
else
{
// Houston, we've got a problem!
General . ShowErrorMessage ( "Error renaming map lump name: the original map lump could not be found!" , MessageBoxButtons . OK ) ;
options . CurrentName = options . PreviousName ;
options . PreviousName = "" ;
}
}
// Done with the target file
targetwad . Dispose ( ) ;
2007-10-13 14:05:45 +00:00
// Resume data resources
data . Resume ( ) ;
2007-10-14 21:31:45 +00:00
2008-11-15 13:12:09 +00:00
// Not saved for testing purpose?
if ( savemode ! = SAVE_TEST )
2007-10-14 21:31:45 +00:00
{
2008-11-15 13:12:09 +00:00
// Saved in a different file?
if ( newfilepathname ! = filepathname )
{
// Keep new filename
filepathname = newfilepathname ;
filetitle = Path . GetFileName ( filepathname ) ;
// Reload resources
ReloadResources ( ) ;
}
try
{
// Open or create the map settings
settingsfile = newfilepathname . Substring ( 0 , newfilepathname . Length - 4 ) + ".dbs" ;
options . WriteConfiguration ( settingsfile ) ;
}
catch ( Exception e )
{
// Warning only
2009-02-26 23:27:46 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , e . GetType ( ) . Name + ": " + e . Message ) ;
2009-03-01 09:15:58 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Could not write the map settings configuration file" ) ;
2008-11-15 13:12:09 +00:00
}
// Check for compile errors, if the scripts were compiled above
if ( CheckScriptChanged ( ) & & ( errors ! = null ) & & ( errors . Count > 0 ) )
{
// Show the errors in the script editor
ShowScriptEditor ( ) ;
scriptwindow . Editor . ShowErrors ( errors ) ;
}
2007-10-14 21:31:45 +00:00
// Changes saved
changed = false ;
2008-11-15 13:12:09 +00:00
scriptschanged = false ;
2007-10-14 21:31:45 +00:00
}
2007-10-13 14:05:45 +00:00
// Success!
2007-10-14 17:48:15 +00:00
General . WriteLogLine ( "Map saving done" ) ;
2007-10-13 14:05:45 +00:00
return true ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Nodebuild
// This builds the nodes in the temproary file with the given configuration name
2007-10-14 18:11:03 +00:00
private bool BuildNodes ( string nodebuildername , bool failaswarning )
2007-10-13 14:05:45 +00:00
{
NodebuilderInfo nodebuilder ;
2009-01-16 12:25:47 +00:00
string tempfile1 , tempfile2 , sourcefile ;
2008-11-14 10:44:03 +00:00
bool lumpscomplete = false ;
2007-10-13 14:05:45 +00:00
WAD buildwad ;
2007-10-14 18:11:03 +00:00
2007-10-13 14:05:45 +00:00
// Find the nodebuilder
nodebuilder = General . GetNodebuilderByName ( nodebuildername ) ;
if ( nodebuilder = = null )
{
// Problem! Can't find that nodebuilder!
2007-10-14 18:11:03 +00:00
General . ShowWarningMessage ( "Unable to build the nodes: The configured nodebuilder cannot be found.\nPlease check your game configuration settings!" , MessageBoxButtons . OK ) ;
2007-10-13 14:05:45 +00:00
return false ;
}
else
{
2008-11-14 10:44:03 +00:00
// Create the compiler interface that will run the nodebuilder
// This automatically creates a temporary directory for us
2008-11-14 16:19:25 +00:00
Compiler compiler = nodebuilder . CreateCompiler ( ) ;
2008-11-14 10:44:03 +00:00
// Make temporary filename
tempfile1 = General . MakeTempFilename ( compiler . Location ) ;
2009-01-04 11:35:05 +00:00
// Make the temporary WAD file
General . WriteLogLine ( "Creating temporary build file: " + tempfile1 ) ;
buildwad = new WAD ( tempfile1 ) ;
2009-01-16 12:25:47 +00:00
// Determine source file
if ( filepathname . Length > 0 )
sourcefile = filepathname ;
else
sourcefile = tempwad . Filename ;
2009-01-04 11:35:05 +00:00
// Copy lumps to buildwad
General . WriteLogLine ( "Copying map lumps to temporary build file..." ) ;
CopyLumpsByType ( tempwad , TEMP_MAP_HEADER , buildwad , BUILD_MAP_HEADER , true , false , false , true ) ;
// Close buildwad
buildwad . Dispose ( ) ;
2008-11-14 10:44:03 +00:00
2007-10-13 14:05:45 +00:00
// Does the nodebuilder require an output file?
if ( nodebuilder . HasSpecialOutputFile )
{
// Make a temporary output file for the nodebuilder
2008-11-14 10:44:03 +00:00
tempfile2 = General . MakeTempFilename ( compiler . Location ) ;
General . WriteLogLine ( "Temporary output file: " + tempfile2 ) ;
2007-10-13 14:05:45 +00:00
}
else
{
// Output file is same as input file
tempfile2 = tempfile1 ;
}
2008-11-14 10:44:03 +00:00
2007-10-13 14:05:45 +00:00
// Run the nodebuilder
2008-11-14 16:19:25 +00:00
compiler . Parameters = nodebuilder . Parameters ;
compiler . InputFile = Path . GetFileName ( tempfile1 ) ;
2008-11-14 10:44:03 +00:00
compiler . OutputFile = Path . GetFileName ( tempfile2 ) ;
2009-01-16 12:25:47 +00:00
compiler . SourceFile = sourcefile ;
2008-11-14 16:19:25 +00:00
compiler . WorkingDirectory = Path . GetDirectoryName ( tempfile1 ) ;
if ( compiler . Run ( ) )
2007-10-13 14:05:45 +00:00
{
// Open the output file
buildwad = new WAD ( tempfile2 ) ;
2008-11-14 10:44:03 +00:00
2007-10-13 14:05:45 +00:00
// Output lumps complete?
2009-01-04 11:35:05 +00:00
lumpscomplete = VerifyNodebuilderLumps ( buildwad , BUILD_MAP_HEADER ) ;
2007-10-13 14:05:45 +00:00
if ( lumpscomplete )
{
// Copy nodebuilder lumps to temp file
General . WriteLogLine ( "Copying nodebuilder lumps to temporary file..." ) ;
CopyLumpsByType ( buildwad , BUILD_MAP_HEADER , tempwad , TEMP_MAP_HEADER , false , false , true , false ) ;
}
else
{
2007-10-14 18:11:03 +00:00
// Nodebuilder did not build the lumps!
if ( failaswarning )
General . ShowWarningMessage ( "Unable to build the nodes: The nodebuilder failed to build the expected data structures.\nThe map will be saved without the nodes." , MessageBoxButtons . OK ) ;
else
General . ShowErrorMessage ( "Unable to build the nodes: The nodebuilder failed to build the expected data structures." , MessageBoxButtons . OK ) ;
2007-10-13 14:05:45 +00:00
}
// Done with the build wad
buildwad . Dispose ( ) ;
}
2008-11-14 10:44:03 +00:00
// Clean up
compiler . Dispose ( ) ;
// Return result
return lumpscomplete ;
2007-10-13 14:05:45 +00:00
}
}
2009-01-04 11:35:05 +00:00
// This verifies if the nodebuilder lumps exist in a WAD file
private bool VerifyNodebuilderLumps ( WAD wad , string mapheader )
{
bool lumpscomplete = false ;
// Find the map header in source
int srcindex = wad . FindLumpIndex ( mapheader ) ;
if ( srcindex > - 1 )
{
// Go for all the map lump names
lumpscomplete = true ;
foreach ( DictionaryEntry ml in config . MapLumpNames )
{
// Read lump settings from map config
bool lumpnodebuild = config . ReadSetting ( "maplumpnames." + ml . Key + ".nodebuild" , false ) ;
bool lumpallowempty = config . ReadSetting ( "maplumpnames." + ml . Key + ".allowempty" , false ) ;
// Check if this lump should exist
if ( lumpnodebuild & & ! lumpallowempty )
{
// Find the lump in the source
if ( wad . FindLump ( ml . Key . ToString ( ) , srcindex , srcindex + config . MapLumpNames . Count + 2 ) = = null )
{
// Missing a lump!
lumpscomplete = false ;
break ;
}
}
}
}
return lumpscomplete ;
}
2007-10-13 14:05:45 +00:00
#endregion
2007-10-14 15:44:55 +00:00
#region = = = = = = = = = = = = = = = = = = Lumps
2007-06-15 18:30:55 +00:00
2008-11-10 06:48:36 +00:00
// This returns a copy of the requested lump stream data
// This is copied from the temp wad file and returns null when the lump is not found
internal MemoryStream GetLumpData ( string lumpname )
{
Lump l = tempwad . FindLump ( lumpname ) ;
if ( l ! = null )
{
l . Stream . Seek ( 0 , SeekOrigin . Begin ) ;
return new MemoryStream ( l . Stream . ReadAllBytes ( ) ) ;
}
else
{
return null ;
}
}
// This writes a copy of the data to a lump in the temp file
internal void SetLumpData ( string lumpname , MemoryStream data )
{
int insertindex = tempwad . Lumps . Count ;
// Remove the lump if it already exists
int li = tempwad . FindLumpIndex ( lumpname ) ;
if ( li > - 1 )
{
insertindex = li ;
tempwad . RemoveAt ( li ) ;
}
// Insert new lump
Lump l = tempwad . Insert ( lumpname , insertindex , ( int ) data . Length ) ;
l . Stream . Seek ( 0 , SeekOrigin . Begin ) ;
data . WriteTo ( l . Stream ) ;
}
2007-10-14 17:48:15 +00:00
// This creates empty lumps for those required
private void CreateRequiredLumps ( WAD target , string mapname )
{
int headerindex , insertindex , targetindex ;
string lumpname ;
bool lumprequired ;
// Find the map header in target
headerindex = target . FindLumpIndex ( mapname ) ;
if ( headerindex = = - 1 )
{
// If this header doesnt exists in the target
// then insert at the end of the target
headerindex = target . Lumps . Count ;
}
// Begin inserting at target header index
insertindex = headerindex ;
// Go for all the map lump names
2007-10-21 18:06:10 +00:00
foreach ( DictionaryEntry ml in config . MapLumpNames )
2007-10-14 17:48:15 +00:00
{
// Read lump settings from map config
lumprequired = config . ReadSetting ( "maplumpnames." + ml . Key + ".required" , false ) ;
// Check if this lump is required
if ( lumprequired )
{
// Get the lump name
lumpname = ml . Key . ToString ( ) ;
if ( lumpname = = CONFIG_MAP_HEADER ) lumpname = mapname ;
// Check if the lump is missing at the target
2007-10-21 18:06:10 +00:00
targetindex = FindSpecificLump ( target , lumpname , headerindex , mapname , config . MapLumpNames ) ;
2007-10-14 17:48:15 +00:00
if ( targetindex = = - 1 )
{
// Determine target index
insertindex + + ;
if ( insertindex > target . Lumps . Count ) insertindex = target . Lumps . Count ;
// Create new, emtpy lump
General . WriteLogLine ( lumpname + " is required! Created empty lump." ) ;
target . Insert ( lumpname , insertindex , 0 ) ;
}
else
{
// Move insert index
insertindex = targetindex ;
}
}
}
}
2009-01-05 19:49:55 +00:00
// This copies all lumps, except those of a specific map
private void CopyAllLumpsExceptMap ( WAD source , WAD target , string sourcemapname )
{
// Go for all lumps
bool skipping = false ;
foreach ( Lump srclump in source . Lumps )
{
// Check if we should stop skipping lumps here
if ( skipping & & ! config . MapLumpNames . Contains ( srclump . Name ) )
{
// Stop skipping
skipping = false ;
}
// Check if we should start skipping lumps here
if ( ! skipping & & ( srclump . Name = = sourcemapname ) )
{
// We have encountered the map header, start skipping!
skipping = true ;
}
// Not skipping this lump?
if ( ! skipping )
{
// Copy lump over!
Lump tgtlump = target . Insert ( srclump . Name , target . Lumps . Count , srclump . Length ) ;
srclump . CopyTo ( tgtlump ) ;
}
}
}
2007-06-24 18:56:43 +00:00
// This copies specific map lumps from one WAD to another
private void CopyLumpsByType ( WAD source , string sourcemapname ,
WAD target , string targetmapname ,
bool copyrequired , bool copyblindcopy ,
bool copynodebuild , bool copyscript )
2007-06-15 18:30:55 +00:00
{
2007-06-24 18:56:43 +00:00
bool lumprequired , lumpblindcopy , lumpnodebuild ;
2007-10-14 15:44:55 +00:00
string lumpscript , srclumpname , tgtlumpname ;
int srcheaderindex , tgtheaderindex , targetindex , sourceindex , lumpindex ;
2007-06-24 18:56:43 +00:00
Lump lump , newlump ;
2007-06-15 18:30:55 +00:00
2007-06-24 18:56:43 +00:00
// Find the map header in target
2007-10-14 15:44:55 +00:00
tgtheaderindex = target . FindLumpIndex ( targetmapname ) ;
if ( tgtheaderindex = = - 1 )
2007-10-13 14:05:45 +00:00
{
// If this header doesnt exists in the target
// then insert at the end of the target
2007-10-14 15:44:55 +00:00
tgtheaderindex = target . Lumps . Count ;
2007-10-13 14:05:45 +00:00
}
2007-10-14 15:44:55 +00:00
// Begin inserting at target header index
targetindex = tgtheaderindex ;
2007-06-24 18:56:43 +00:00
// Find the map header in source
2007-10-14 15:44:55 +00:00
srcheaderindex = source . FindLumpIndex ( sourcemapname ) ;
if ( srcheaderindex > - 1 )
2007-06-15 18:30:55 +00:00
{
2007-06-24 18:56:43 +00:00
// Copy the map header from source to target
2007-10-14 15:44:55 +00:00
//newlump = target.Insert(targetmapname, tgtindex++, source.Lumps[srcindex].Length);
//source.Lumps[srcindex].CopyTo(newlump);
2007-06-24 18:56:43 +00:00
// Go for all the map lump names
2007-10-21 18:06:10 +00:00
foreach ( DictionaryEntry ml in config . MapLumpNames )
2007-06-24 18:56:43 +00:00
{
// Read lump settings from map config
lumprequired = config . ReadSetting ( "maplumpnames." + ml . Key + ".required" , false ) ;
lumpblindcopy = config . ReadSetting ( "maplumpnames." + ml . Key + ".blindcopy" , false ) ;
lumpnodebuild = config . ReadSetting ( "maplumpnames." + ml . Key + ".nodebuild" , false ) ;
lumpscript = config . ReadSetting ( "maplumpnames." + ml . Key + ".script" , "" ) ;
// Check if this lump should be copied
if ( ( lumprequired & & copyrequired ) | | ( lumpblindcopy & & copyblindcopy ) | |
2007-10-19 14:27:46 +00:00
( lumpnodebuild & & copynodebuild ) | | ( ( lumpscript . Length ! = 0 ) & & copyscript ) )
2007-06-24 18:56:43 +00:00
{
2007-10-14 15:44:55 +00:00
// Get the lump name
srclumpname = ml . Key . ToString ( ) ;
tgtlumpname = ml . Key . ToString ( ) ;
if ( srclumpname = = CONFIG_MAP_HEADER ) srclumpname = sourcemapname ;
if ( tgtlumpname = = CONFIG_MAP_HEADER ) tgtlumpname = targetmapname ;
2007-06-24 18:56:43 +00:00
// Find the lump in the source
2007-10-21 18:06:10 +00:00
sourceindex = FindSpecificLump ( source , srclumpname , srcheaderindex , sourcemapname , config . MapLumpNames ) ;
2007-10-14 15:44:55 +00:00
if ( sourceindex > - 1 )
2007-06-24 18:56:43 +00:00
{
2007-10-14 15:44:55 +00:00
// Remove lump at target
2007-10-21 18:06:10 +00:00
lumpindex = RemoveSpecificLump ( target , tgtlumpname , tgtheaderindex , targetmapname , config . MapLumpNames ) ;
2007-10-14 15:44:55 +00:00
// Determine target index
// When original lump was found and removed then insert at that position
// otherwise insert after last insertion position
if ( lumpindex > - 1 ) targetindex = lumpindex ; else targetindex + + ;
if ( targetindex > target . Lumps . Count ) targetindex = target . Lumps . Count ;
2007-06-24 18:56:43 +00:00
// Copy the lump to the target
2007-10-14 15:44:55 +00:00
//General.WriteLogLine(srclumpname + " copying as " + tgtlumpname);
lump = source . Lumps [ sourceindex ] ;
newlump = target . Insert ( tgtlumpname , targetindex , lump . Length ) ;
2007-06-24 18:56:43 +00:00
lump . CopyTo ( newlump ) ;
}
2007-10-05 11:17:58 +00:00
else
{
2009-03-01 09:15:58 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , ml . Key . ToString ( ) + " should be read but was not found in the WAD file" ) ;
2007-10-05 11:17:58 +00:00
}
2007-06-24 18:56:43 +00:00
}
}
2007-06-15 18:30:55 +00:00
}
2007-06-24 18:56:43 +00:00
}
2007-10-14 15:44:55 +00:00
// This finds a lump within the range of known lump names
// Returns -1 when the lump cannot be found
2008-01-02 21:49:43 +00:00
internal static int FindSpecificLump ( WAD source , string lumpname , int mapheaderindex , string mapheadername , IDictionary maplumps )
2007-06-24 18:56:43 +00:00
{
2007-10-14 15:44:55 +00:00
// Use the configured map lump names to find the specific lump within range,
// because when an unknown lump is met, this search must stop.
2007-06-24 18:56:43 +00:00
2007-10-14 15:44:55 +00:00
// Go for all lumps in order to find the specified lump
for ( int i = 0 ; i < maplumps . Count + 1 ; i + + )
{
// Still within bounds?
if ( ( mapheaderindex + i ) < source . Lumps . Count )
2007-06-24 18:56:43 +00:00
{
2007-10-14 15:44:55 +00:00
// Check if this is a known lump name
if ( maplumps . Contains ( source . Lumps [ mapheaderindex + i ] . Name ) | |
( maplumps . Contains ( CONFIG_MAP_HEADER ) & & ( source . Lumps [ mapheaderindex + i ] . Name = = mapheadername ) ) )
2007-06-24 18:56:43 +00:00
{
2007-10-14 15:44:55 +00:00
// Is this the lump we are looking for?
if ( source . Lumps [ mapheaderindex + i ] . Name = = lumpname )
{
// Return this index
return mapheaderindex + i ;
}
2007-06-24 18:56:43 +00:00
}
else
{
2007-10-14 15:44:55 +00:00
// Unknown lump hit, abort search
break ;
2007-06-24 18:56:43 +00:00
}
}
2007-06-15 18:30:55 +00:00
}
2008-11-10 21:06:02 +00:00
2007-10-14 15:44:55 +00:00
// Nothing found
return - 1 ;
}
// This removes a specific lump and returns the position where the lump was removed
// Returns -1 when the lump could not be found
2008-01-02 21:49:43 +00:00
internal static int RemoveSpecificLump ( WAD source , string lumpname , int mapheaderindex , string mapheadername , IDictionary maplumps )
2007-10-14 15:44:55 +00:00
{
int lumpindex ;
// Find the specific lump index
lumpindex = FindSpecificLump ( source , lumpname , mapheaderindex , mapheadername , maplumps ) ;
if ( lumpindex > - 1 )
{
// Remove this lump
//General.WriteLogLine(lumpname + " removed");
source . RemoveAt ( lumpindex ) ;
}
else
{
// Lump not found
2009-02-26 23:27:46 +00:00
//General.ErrorLogger.Add(ErrorType.Warning, lumpname + " should be removed but was not found!");
2007-10-14 15:44:55 +00:00
}
// Return result
return lumpindex ;
2007-06-24 18:56:43 +00:00
}
2007-10-14 15:44:55 +00:00
#endregion
2008-10-16 09:33:35 +00:00
#region = = = = = = = = = = = = = = = = = = Selection Groups
// This adds selection to a group
private void AddSelectionToGroup ( int groupindex )
{
General . Interface . SetCursor ( Cursors . WaitCursor ) ;
// Make undo
2008-12-24 18:27:13 +00:00
undoredo . CreateUndo ( "Assign to group " + groupindex ) ;
2008-10-16 09:33:35 +00:00
// Make selection
map . AddSelectionToGroup ( 0x01 < < groupindex ) ;
General . Interface . SetCursor ( Cursors . Default ) ;
}
// This selects a group
private void SelectGroup ( int groupindex )
{
// Select
int groupmask = 0x01 < < groupindex ;
map . SelectVerticesByGroup ( groupmask ) ;
map . SelectLinedefsByGroup ( groupmask ) ;
map . SelectSectorsByGroup ( groupmask ) ;
map . SelectThingsByGroup ( groupmask ) ;
// Redraw to show selection
General . Interface . RedrawDisplay ( ) ;
}
// Select actions
[BeginAction("selectgroup1")] internal void SelectGroup1 ( ) { SelectGroup ( 0 ) ; }
[BeginAction("selectgroup2")] internal void SelectGroup2 ( ) { SelectGroup ( 1 ) ; }
[BeginAction("selectgroup3")] internal void SelectGroup3 ( ) { SelectGroup ( 2 ) ; }
[BeginAction("selectgroup4")] internal void SelectGroup4 ( ) { SelectGroup ( 3 ) ; }
[BeginAction("selectgroup5")] internal void SelectGroup5 ( ) { SelectGroup ( 4 ) ; }
[BeginAction("selectgroup6")] internal void SelectGroup6 ( ) { SelectGroup ( 5 ) ; }
[BeginAction("selectgroup7")] internal void SelectGroup7 ( ) { SelectGroup ( 6 ) ; }
[BeginAction("selectgroup8")] internal void SelectGroup8 ( ) { SelectGroup ( 7 ) ; }
[BeginAction("selectgroup9")] internal void SelectGroup9 ( ) { SelectGroup ( 8 ) ; }
[BeginAction("selectgroup10")] internal void SelectGroup10 ( ) { SelectGroup ( 9 ) ; }
// Assign actions
[BeginAction("assigngroup1")] internal void AssignGroup1 ( ) { AddSelectionToGroup ( 0 ) ; }
[BeginAction("assigngroup2")] internal void AssignGroup2 ( ) { AddSelectionToGroup ( 1 ) ; }
[BeginAction("assigngroup3")] internal void AssignGroup3 ( ) { AddSelectionToGroup ( 2 ) ; }
[BeginAction("assigngroup4")] internal void AssignGroup4 ( ) { AddSelectionToGroup ( 3 ) ; }
[BeginAction("assigngroup5")] internal void AssignGroup5 ( ) { AddSelectionToGroup ( 4 ) ; }
[BeginAction("assigngroup6")] internal void AssignGroup6 ( ) { AddSelectionToGroup ( 5 ) ; }
[BeginAction("assigngroup7")] internal void AssignGroup7 ( ) { AddSelectionToGroup ( 6 ) ; }
[BeginAction("assigngroup8")] internal void AssignGroup8 ( ) { AddSelectionToGroup ( 7 ) ; }
[BeginAction("assigngroup9")] internal void AssignGroup9 ( ) { AddSelectionToGroup ( 8 ) ; }
[BeginAction("assigngroup10")] internal void AssignGroup10 ( ) { AddSelectionToGroup ( 9 ) ; }
2008-09-23 10:04:10 +00:00
2008-10-16 09:33:35 +00:00
#endregion
2008-11-13 23:05:16 +00:00
#region = = = = = = = = = = = = = = = = = = Script Editing
2008-11-10 16:11:44 +00:00
// Show the script editor
[BeginAction("openscripteditor")]
internal void ShowScriptEditor ( )
{
2008-11-15 13:58:47 +00:00
Cursor . Current = Cursors . WaitCursor ;
2008-11-10 16:11:44 +00:00
if ( scriptwindow = = null )
{
// Load the window
scriptwindow = new ScriptEditorForm ( ) ;
}
// Show the window
2009-01-14 23:12:52 +00:00
if ( General . Settings . ScriptOnTop )
2009-01-14 23:24:05 +00:00
{
if ( scriptwindow . Visible & & ( scriptwindow . Owner = = null ) ) scriptwindow . Hide ( ) ;
2009-01-14 23:12:52 +00:00
scriptwindow . Show ( General . MainWindow ) ;
2009-01-14 23:24:05 +00:00
}
2009-01-14 23:12:52 +00:00
else
2009-01-14 23:24:05 +00:00
{
if ( scriptwindow . Visible & & ( scriptwindow . Owner ! = null ) ) scriptwindow . Hide ( ) ;
2009-01-14 23:12:52 +00:00
scriptwindow . Show ( ) ;
2009-01-14 23:24:05 +00:00
}
2008-11-10 16:11:44 +00:00
scriptwindow . Focus ( ) ;
2008-11-15 13:58:47 +00:00
Cursor . Current = Cursors . Default ;
2008-11-10 16:11:44 +00:00
}
// This asks the user to save changes in script files
// Returns false when cancelled by the user
internal bool AskSaveScriptChanges ( )
{
// Window open?
if ( scriptwindow ! = null )
{
// Ask to save changes
// This also saves implicitly
return scriptwindow . AskSaveAll ( ) ;
}
else
{
// No problems
return true ;
}
}
// Close the script editor
// Specify true for the closing parameter when
// the window is already in the closing process
internal void CloseScriptEditor ( bool closing )
{
if ( scriptwindow ! = null )
{
if ( ! scriptwindow . IsDisposed )
{
2008-11-11 06:43:33 +00:00
// Remember what files were open
scriptwindow . Editor . WriteOpenFilesToConfiguration ( ) ;
2008-11-10 16:11:44 +00:00
// Remember if lumps are changed
scriptschanged | = scriptwindow . Editor . CheckImplicitChanges ( ) ;
// Close now
if ( ! closing ) scriptwindow . Close ( ) ;
}
// Done
scriptwindow = null ;
}
}
// This checks if the scripts are changed
internal bool CheckScriptChanged ( )
{
2008-11-10 21:06:02 +00:00
if ( scriptwindow ! = null )
{
// Check if scripts are changed
return scriptschanged | | scriptwindow . Editor . CheckImplicitChanges ( ) ;
}
else
{
// Check if scripts are changed
return scriptschanged ;
}
2008-11-10 16:11:44 +00:00
}
2008-11-15 13:12:09 +00:00
// This compiles all lumps that require compiling and stores the results
// Returns true when our code worked properly (even when the compiler returned errors)
private bool CompileScriptLumps ( )
{
bool success = true ;
errors = new List < CompilerError > ( ) ;
// Go for all the map lumps
foreach ( MapLumpInfo lumpinfo in config . MapLumps . Values )
{
// Is this a script lump?
if ( lumpinfo . script ! = null )
{
// Compile it now
success & = CompileLump ( lumpinfo . name , false ) ;
}
}
return success ;
}
2008-11-10 16:11:44 +00:00
2008-11-13 23:05:16 +00:00
// This compiles a script lump and returns any errors that may have occurred
2008-11-14 16:19:25 +00:00
// Returns true when our code worked properly (even when the compiler returned errors)
2008-11-15 13:12:09 +00:00
internal bool CompileLump ( string lumpname , bool clearerrors )
2008-11-13 23:05:16 +00:00
{
2009-01-16 12:25:47 +00:00
string inputfile , outputfile , sourcefile ;
2008-11-15 13:12:09 +00:00
Compiler compiler ;
byte [ ] filedata ;
2009-01-14 23:12:52 +00:00
string reallumpname = lumpname ;
2008-11-14 16:19:25 +00:00
// Find the lump
2009-01-14 23:12:52 +00:00
if ( lumpname = = CONFIG_MAP_HEADER ) reallumpname = TEMP_MAP_HEADER ;
Lump lump = tempwad . FindLump ( reallumpname ) ;
if ( lump = = null ) throw new Exception ( "No such lump in temporary wad file '" + reallumpname + "'." ) ;
2008-11-14 16:19:25 +00:00
2009-01-16 12:25:47 +00:00
// Determine source file
if ( filepathname . Length > 0 )
sourcefile = filepathname ;
else
sourcefile = tempwad . Filename ;
2008-11-14 16:19:25 +00:00
// New list of errors
2008-11-15 13:12:09 +00:00
if ( clearerrors | | ( errors = = null ) )
errors = new List < CompilerError > ( ) ;
2008-11-13 23:05:16 +00:00
// Determine the script configuration to use
2009-01-14 23:12:52 +00:00
ScriptConfiguration scriptconfig = config . MapLumps [ lumpname ] . script ;
if ( scriptconfig . Compiler ! = null )
2008-11-14 16:19:25 +00:00
{
2009-01-14 23:12:52 +00:00
try
2008-11-15 13:12:09 +00:00
{
2009-01-14 23:12:52 +00:00
// Initialize compiler
compiler = scriptconfig . Compiler . Create ( ) ;
}
catch ( Exception e )
{
// Fail
errors . Add ( new CompilerError ( "Unable to initialize compiler. " + e . GetType ( ) . Name + ": " + e . Message ) ) ;
return false ;
}
2008-11-15 13:12:09 +00:00
2009-01-14 23:12:52 +00:00
try
{
// Write lump data to temp script file in compiler's temp directory
inputfile = General . MakeTempFilename ( compiler . Location , "tmp" ) ;
lump . Stream . Seek ( 0 , SeekOrigin . Begin ) ;
BinaryReader reader = new BinaryReader ( lump . Stream ) ;
File . WriteAllBytes ( inputfile , reader . ReadBytes ( ( int ) lump . Stream . Length ) ) ;
}
catch ( Exception e )
{
// Fail
compiler . Dispose ( ) ;
errors . Add ( new CompilerError ( "Unable to write script to working file. " + e . GetType ( ) . Name + ": " + e . Message ) ) ;
return false ;
2008-11-15 13:12:09 +00:00
}
2009-01-16 12:25:47 +00:00
2009-01-14 23:12:52 +00:00
// Make random output filename
outputfile = General . MakeTempFilename ( compiler . Location , "tmp" ) ;
2009-01-16 12:25:47 +00:00
2009-01-14 23:12:52 +00:00
// Run compiler
compiler . Parameters = scriptconfig . Parameters ;
compiler . InputFile = Path . GetFileName ( inputfile ) ;
compiler . OutputFile = Path . GetFileName ( outputfile ) ;
2009-01-16 12:25:47 +00:00
compiler . SourceFile = sourcefile ;
2009-01-14 23:12:52 +00:00
compiler . WorkingDirectory = Path . GetDirectoryName ( inputfile ) ;
if ( compiler . Run ( ) )
2008-11-15 13:12:09 +00:00
{
2009-01-14 23:12:52 +00:00
// Process errors
foreach ( CompilerError e in compiler . Errors )
{
CompilerError newerror = e ;
// If the error's filename equals our temporary file,
// use the lump name instead and prefix it with ?
if ( string . Compare ( e . filename , inputfile , true ) = = 0 )
newerror . filename = "?" + reallumpname ;
errors . Add ( newerror ) ;
}
// No errors?
if ( compiler . Errors . Length = = 0 )
2008-11-15 13:12:09 +00:00
{
2009-01-14 23:12:52 +00:00
// Output file exists?
if ( File . Exists ( outputfile ) )
2008-11-15 13:12:09 +00:00
{
2009-01-14 23:12:52 +00:00
// Copy output file data into a lump?
if ( ( scriptconfig . ResultLump ! = null ) & & ( scriptconfig . ResultLump . Length > 0 ) )
2008-11-15 13:12:09 +00:00
{
2009-01-14 23:12:52 +00:00
// Do that now then
try
{
filedata = File . ReadAllBytes ( outputfile ) ;
}
catch ( Exception e )
{
// Fail
compiler . Dispose ( ) ;
errors . Add ( new CompilerError ( "Unable to read compiler output file. " + e . GetType ( ) . Name + ": " + e . Message ) ) ;
return false ;
}
// Store data
MemoryStream stream = new MemoryStream ( filedata ) ;
SetLumpData ( scriptconfig . ResultLump , stream ) ;
2008-11-15 13:12:09 +00:00
}
}
}
2009-01-14 23:12:52 +00:00
// Clean up
compiler . Dispose ( ) ;
if ( errors . Count = = 0 ) errors = null ;
// Done
return true ;
}
else
{
// Fail
compiler . Dispose ( ) ;
errors = null ;
return false ;
2008-11-15 13:12:09 +00:00
}
2008-11-14 16:19:25 +00:00
}
else
{
2009-01-14 23:12:52 +00:00
// No compiler to run for this script type
if ( errors . Count = = 0 ) errors = null ;
return true ;
2008-11-14 16:19:25 +00:00
}
}
// This clears all compiler errors
internal void ClearCompilerErrors ( )
{
errors = null ;
2008-11-13 23:05:16 +00:00
}
2008-11-10 16:11:44 +00:00
#endregion
2008-10-16 09:33:35 +00:00
#region = = = = = = = = = = = = = = = = = = Methods
2008-11-30 02:17:19 +00:00
// This updates everything after the configuration or settings have been changed
internal void UpdateConfiguration ( )
{
// Update map
map . UpdateConfiguration ( ) ;
// Update settings
renderer3d . CreateProjection ( ) ;
}
2008-05-26 20:06:15 +00:00
// This changes thing filter
internal void ChangeThingFilter ( ThingsFilter newfilter )
{
// We have a special filter for null
if ( newfilter = = null ) newfilter = new NullThingsFilter ( ) ;
// Deactivate old filter
if ( thingsfilter ! = null ) thingsfilter . Deactivate ( ) ;
// Change
thingsfilter = newfilter ;
// Activate filter
thingsfilter . Activate ( ) ;
// Redraw
General . MainWindow . RedrawDisplay ( ) ;
}
2007-11-12 22:43:01 +00:00
// This sets a new mapset for editing
2008-01-02 21:49:43 +00:00
internal void ChangeMapSet ( MapSet newmap )
2007-11-12 22:43:01 +00:00
{
2008-12-24 18:27:13 +00:00
// Let the plugin and editing mode know
General . Plugins . OnMapSetChangeBegin ( ) ;
if ( General . Editing . Mode ! = null ) General . Editing . Mode . OnMapSetChangeBegin ( ) ;
2009-01-10 00:26:24 +00:00
this . visualcamera . Sector = null ;
2007-11-12 22:43:01 +00:00
// Can't have a selection in an old map set
2007-12-01 18:29:58 +00:00
map . ClearAllSelected ( ) ;
2007-11-12 22:43:01 +00:00
// Apply
map . Dispose ( ) ;
map = newmap ;
2008-12-06 13:20:47 +00:00
map . UpdateConfiguration ( ) ;
2009-01-03 22:18:59 +00:00
map . SnapAllToAccuracy ( ) ;
2007-11-12 22:43:01 +00:00
map . Update ( ) ;
2008-05-26 20:06:15 +00:00
thingsfilter . Update ( ) ;
2008-12-24 18:27:13 +00:00
// Let the plugin and editing mode know
General . Plugins . OnMapSetChangeEnd ( ) ;
if ( General . Editing . Mode ! = null ) General . Editing . Mode . OnMapSetChangeEnd ( ) ;
2007-11-12 22:43:01 +00:00
}
2007-10-14 21:31:45 +00:00
// This reloads resources
2008-04-27 12:07:26 +00:00
[BeginAction("reloadresources")]
2008-01-02 21:49:43 +00:00
internal void ReloadResources ( )
2007-10-14 21:31:45 +00:00
{
DataLocation maplocation ;
2009-02-26 14:16:18 +00:00
StatusInfo oldstatus ;
2007-10-14 21:31:45 +00:00
Cursor oldcursor ;
// Keep old display info
2009-02-26 14:16:18 +00:00
oldstatus = General . MainWindow . Status ;
2007-10-14 21:31:45 +00:00
oldcursor = Cursor . Current ;
// Show status
2009-02-26 14:16:18 +00:00
General . MainWindow . DisplayStatus ( StatusType . Busy , "Reloading data resources..." ) ;
2007-10-14 21:31:45 +00:00
Cursor . Current = Cursors . WaitCursor ;
2007-10-27 13:59:24 +00:00
// Clean up
data . Dispose ( ) ;
data = null ;
2008-02-24 21:52:18 +00:00
config = null ;
configinfo = null ;
2007-10-27 13:59:24 +00:00
GC . Collect ( ) ;
2008-09-28 21:20:56 +00:00
GC . WaitForPendingFinalizers ( ) ;
2007-10-27 13:59:24 +00:00
2007-10-14 21:31:45 +00:00
// Reload game configuration
General . WriteLogLine ( "Reloading game configuration..." ) ;
configinfo = General . GetConfigurationInfo ( options . ConfigFile ) ;
2007-10-21 18:06:10 +00:00
config = new GameConfiguration ( General . LoadGameConfiguration ( options . ConfigFile ) ) ;
2008-11-27 11:59:17 +00:00
General . Editing . UpdateCurrentEditModes ( ) ;
2007-10-14 21:31:45 +00:00
// Reload data resources
General . WriteLogLine ( "Reloading data resources..." ) ;
data = new DataManager ( ) ;
2009-01-03 22:18:59 +00:00
if ( ! string . IsNullOrEmpty ( filepathname ) )
{
maplocation = new DataLocation ( DataLocation . RESOURCE_WAD , filepathname , false , false ) ;
data . Load ( configinfo . Resources , options . Resources , maplocation ) ;
}
else
{
data . Load ( configinfo . Resources , options . Resources ) ;
}
2007-10-21 22:41:46 +00:00
// Apply new settings to map elements
map . UpdateConfiguration ( ) ;
2007-11-10 19:24:52 +00:00
// Re-link the background image
grid . LinkBackground ( ) ;
2007-10-21 22:41:46 +00:00
2008-12-10 22:58:58 +00:00
// Inform all plugins that the resources are reloaded
2008-05-14 21:48:36 +00:00
General . Plugins . ReloadResources ( ) ;
2008-12-10 22:58:58 +00:00
// Inform editing mode that the resources are reloaded
if ( General . Editing . Mode ! = null ) General . Editing . Mode . OnReloadResources ( ) ;
2008-05-14 21:48:36 +00:00
2007-10-14 21:31:45 +00:00
// Reset status
General . MainWindow . DisplayStatus ( oldstatus ) ;
Cursor . Current = oldcursor ;
}
2007-10-20 19:50:03 +00:00
2007-10-14 21:31:45 +00:00
// Game Configuration action
2008-04-27 12:07:26 +00:00
[BeginAction("mapoptions")]
2008-01-02 21:49:43 +00:00
internal void ShowMapOptions ( )
2007-10-14 21:31:45 +00:00
{
2008-05-08 16:39:14 +00:00
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General . DisengageVolatileMode ( ) ;
2008-05-08 16:39:14 +00:00
2007-10-14 21:31:45 +00:00
// Show map options dialog
MapOptionsForm optionsform = new MapOptionsForm ( options ) ;
if ( optionsform . ShowDialog ( General . MainWindow ) = = DialogResult . OK )
{
// Update interface
General . MainWindow . UpdateInterface ( ) ;
2007-10-20 19:50:03 +00:00
2008-02-15 14:08:26 +00:00
// Stop data manager
data . Dispose ( ) ;
// Apply new options
this . options = optionsform . Options ;
// Load new game configuration
General . WriteLogLine ( "Loading game configuration..." ) ;
configinfo = General . GetConfigurationInfo ( options . ConfigFile ) ;
config = new GameConfiguration ( General . LoadGameConfiguration ( options . ConfigFile ) ) ;
2008-11-27 19:25:13 +00:00
configinfo . ApplyDefaults ( config ) ;
2008-11-27 11:59:17 +00:00
General . Editing . UpdateCurrentEditModes ( ) ;
2008-02-15 14:08:26 +00:00
// Setup new map format IO
General . WriteLogLine ( "Initializing map format interface " + config . FormatInterface + "..." ) ;
io = MapSetIO . Create ( config . FormatInterface , tempwad , this ) ;
// Create required lumps if they don't exist yet
CreateRequiredLumps ( tempwad , TEMP_MAP_HEADER ) ;
2008-05-15 09:43:19 +00:00
// Let the plugins know
General . Plugins . MapReconfigure ( ) ;
2008-02-15 14:08:26 +00:00
2008-09-24 14:53:42 +00:00
// Update interface
General . MainWindow . UpdateInterface ( ) ;
2007-10-14 21:31:45 +00:00
// Reload resources
ReloadResources ( ) ;
2008-09-24 14:53:42 +00:00
// Done
General . MainWindow . DisplayReady ( ) ;
2007-10-14 21:31:45 +00:00
}
// Done
optionsform . Dispose ( ) ;
}
2007-10-14 15:44:55 +00:00
2008-05-26 20:06:15 +00:00
// This shows the things filters setup
[BeginAction("thingsfilterssetup")]
internal void ShowThingsFiltersSetup ( )
{
2008-09-01 12:14:35 +00:00
// Show things filter dialog
2008-05-26 20:06:15 +00:00
ThingsFiltersForm f = new ThingsFiltersForm ( ) ;
f . ShowDialog ( General . MainWindow ) ;
f . Dispose ( ) ;
}
2007-12-29 15:50:16 +00:00
// This returns true is the given type matches
public bool IsType ( Type t )
{
return io . GetType ( ) . Equals ( t ) ;
}
2007-06-14 23:31:57 +00:00
#endregion
}
}