2009-04-19 18:07:22 +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.Generic ;
using System.Text ;
using System.IO ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.Config ;
using CodeImp.DoomBuilder.Types ;
#endregion
namespace CodeImp.DoomBuilder.IO
{
internal class UniversalStreamReader
{
#region = = = = = = = = = = = = = = = = = = Constants
2013-08-12 10:15:08 +00:00
// Name of the UDMF configuration file
2009-04-19 18:07:22 +00:00
private const string UDMF_CONFIG_NAME = "UDMF.cfg" ;
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
2015-10-01 21:35:52 +00:00
private readonly Configuration config ;
2009-04-19 18:07:22 +00:00
private bool setknowncustomtypes ;
private bool strictchecking = true ;
Removed "Paste Properties Options" action.
Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action.
Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them.
Changed, Paste Properties Special window: only options relevant to current map format are now displayed.
Changed, Paste Properties Special window, UDMF: all UI-managed options are now available.
Fixed: MAPINFO parser was unable to process "include" directives.
Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection.
Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode.
Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time.
Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map.
Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled.
Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category.
Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll.
Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format.
Internal: merged methods from UDMFTools into UniFields, removed UDMFTools.
Updated Inno Setup script (added VC++ 2008 SP1 distributive).
Updated ZDoom_DECORATE.cfg (A_CheckBlock).
Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
private readonly Dictionary < MapElementType , Dictionary < string , UniversalType > > uifields ; //mxd
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public bool SetKnownCustomTypes { get { return setknowncustomtypes ; } set { setknowncustomtypes = value ; } }
public bool StrictChecking { get { return strictchecking ; } set { strictchecking = value ; } }
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
Removed "Paste Properties Options" action.
Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action.
Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them.
Changed, Paste Properties Special window: only options relevant to current map format are now displayed.
Changed, Paste Properties Special window, UDMF: all UI-managed options are now available.
Fixed: MAPINFO parser was unable to process "include" directives.
Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection.
Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode.
Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time.
Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map.
Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled.
Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category.
Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll.
Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format.
Internal: merged methods from UDMFTools into UniFields, removed UDMFTools.
Updated Inno Setup script (added VC++ 2008 SP1 distributive).
Updated ZDoom_DECORATE.cfg (A_CheckBlock).
Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
public UniversalStreamReader ( Dictionary < MapElementType , Dictionary < string , UniversalType > > uifields )
2009-04-19 18:07:22 +00:00
{
2013-08-12 10:15:08 +00:00
this . uifields = uifields ;
2009-04-19 18:07:22 +00:00
// Make configuration
config = new Configuration ( ) ;
// Find a resource named UDMF.cfg
string [ ] resnames = General . ThisAssembly . GetManifestResourceNames ( ) ;
foreach ( string rn in resnames )
{
// Found it?
2016-02-01 22:04:00 +00:00
if ( rn . EndsWith ( UDMF_CONFIG_NAME , StringComparison . OrdinalIgnoreCase ) )
2009-04-19 18:07:22 +00:00
{
// Get a stream from the resource
Stream udmfcfg = General . ThisAssembly . GetManifestResourceStream ( rn ) ;
StreamReader udmfcfgreader = new StreamReader ( udmfcfg , Encoding . ASCII ) ;
// Load configuration from stream
config . InputConfiguration ( udmfcfgreader . ReadToEnd ( ) ) ;
// Now we add the linedef flags, activations and thing flags
// to this list, so that these don't show up in the custom
// fields list either. We use true as dummy value (it has no meaning)
// Add linedef flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . LinedefFlags )
config . WriteSetting ( "managedfields.linedef." + flag . Key , true ) ;
// Add linedef activations
foreach ( LinedefActivateInfo activate in General . Map . Config . LinedefActivates )
config . WriteSetting ( "managedfields.linedef." + activate . Key , true ) ;
2010-08-14 15:44:47 +00:00
// Add linedef flag translations
foreach ( FlagTranslation f in General . Map . Config . LinedefFlagsTranslation )
{
foreach ( string fn in f . Fields )
config . WriteSetting ( "managedfields.linedef." + fn , true ) ;
}
2009-04-19 18:07:22 +00:00
2013-07-19 15:30:58 +00:00
//mxd. Add sidedef flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SidedefFlags )
config . WriteSetting ( "managedfields.sidedef." + flag . Key , true ) ;
2013-07-10 08:59:17 +00:00
//mxd. Add sector flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SectorFlags )
config . WriteSetting ( "managedfields.sector." + flag . Key , true ) ;
2009-04-19 18:07:22 +00:00
// Add thing flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . ThingFlags )
config . WriteSetting ( "managedfields.thing." + flag . Key , true ) ;
2010-08-14 15:44:47 +00:00
// Add thing flag translations
foreach ( FlagTranslation f in General . Map . Config . ThingFlagsTranslation )
{
foreach ( string fn in f . Fields )
config . WriteSetting ( "managedfields.thing." + fn , true ) ;
}
2009-04-19 18:07:22 +00:00
// Done
udmfcfgreader . Dispose ( ) ;
break ;
}
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Reading
// This reads from a stream
2015-10-01 21:35:52 +00:00
public void Read ( MapSet map , Stream stream )
2009-04-19 18:07:22 +00:00
{
StreamReader reader = new StreamReader ( stream , Encoding . ASCII ) ;
UniversalParser textmap = new UniversalParser ( ) ;
textmap . StrictChecking = strictchecking ;
2015-10-01 21:35:52 +00:00
// Read UDMF from stream
List < string > data = new List < string > ( 1000 ) ;
while ( ! reader . EndOfStream ) data . Add ( reader . ReadLine ( ) ) ;
2013-12-20 09:24:43 +00:00
2015-10-01 21:35:52 +00:00
// Parse it
textmap . InputConfiguration ( data . ToArray ( ) ) ;
2009-04-19 18:07:22 +00:00
2015-10-01 21:35:52 +00:00
// Check for errors
if ( textmap . ErrorResult ! = 0 )
2009-04-19 18:07:22 +00:00
{
2015-10-01 21:35:52 +00:00
//mxd. Throw parse error
throw new Exception ( "Error on line " + textmap . ErrorLine + " while parsing UDMF map data:\n" + textmap . ErrorDescription ) ;
2009-04-19 18:07:22 +00:00
}
2015-10-01 21:35:52 +00:00
// Read the map
Dictionary < int , Vertex > vertexlink = ReadVertices ( map , textmap ) ;
Dictionary < int , Sector > sectorlink = ReadSectors ( map , textmap ) ;
ReadLinedefs ( map , textmap , vertexlink , sectorlink ) ;
ReadThings ( map , textmap ) ;
2009-04-19 18:07:22 +00:00
}
// This reads the things
private void ReadThings ( MapSet map , UniversalParser textmap )
{
// Get list of entries
List < UniversalCollection > collections = GetNamedCollections ( textmap . Root , "thing" ) ;
// Go for all collections
2009-06-18 14:23:33 +00:00
map . SetCapacity ( 0 , 0 , 0 , 0 , map . Things . Count + collections . Count ) ;
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < collections . Count ; i + + )
{
// Read fields
UniversalCollection c = collections [ i ] ;
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
2009-06-15 21:58:34 +00:00
string where = "thing " + i ;
2014-12-03 23:15:26 +00:00
float x = GetCollectionEntry ( c , "x" , true , 0.0f , where ) ;
float y = GetCollectionEntry ( c , "y" , true , 0.0f , where ) ;
float height = GetCollectionEntry ( c , "height" , false , 0.0f , where ) ;
int tag = GetCollectionEntry ( c , "id" , false , 0 , where ) ;
int angledeg = GetCollectionEntry ( c , "angle" , false , 0 , where ) ;
int pitch = GetCollectionEntry ( c , "pitch" , false , 0 , where ) ; //mxd
int roll = GetCollectionEntry ( c , "roll" , false , 0 , where ) ; //mxd
float scaleX = GetCollectionEntry ( c , "scalex" , false , 1.0f , where ) ; //mxd
float scaleY = GetCollectionEntry ( c , "scaley" , false , 1.0f , where ) ; //mxd
float scale = GetCollectionEntry ( c , "scale" , false , 0f , where ) ; //mxd
int type = GetCollectionEntry ( c , "type" , true , 0 , where ) ;
int special = GetCollectionEntry ( c , "special" , false , 0 , where ) ;
args [ 0 ] = GetCollectionEntry ( c , "arg0" , false , 0 , where ) ;
args [ 1 ] = GetCollectionEntry ( c , "arg1" , false , 0 , where ) ;
args [ 2 ] = GetCollectionEntry ( c , "arg2" , false , 0 , where ) ;
args [ 3 ] = GetCollectionEntry ( c , "arg3" , false , 0 , where ) ;
args [ 4 ] = GetCollectionEntry ( c , "arg4" , false , 0 , where ) ;
2009-04-19 18:07:22 +00:00
2015-12-28 15:01:53 +00:00
if ( scale ! = 0 ) //mxd
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
{
scaleX = scale ;
scaleY = scale ;
}
2009-04-19 18:07:22 +00:00
// Flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . ThingFlags )
2014-12-03 23:15:26 +00:00
stringflags [ flag . Key ] = GetCollectionEntry ( c , flag . Key , false , false , where ) ;
2009-04-19 18:07:22 +00:00
foreach ( FlagTranslation ft in General . Map . Config . ThingFlagsTranslation )
{
foreach ( string field in ft . Fields )
2014-12-03 23:15:26 +00:00
stringflags [ field ] = GetCollectionEntry ( c , field , false , false , where ) ;
2009-04-19 18:07:22 +00:00
}
// Create new item
Thing t = map . CreateThing ( ) ;
2010-08-15 19:43:00 +00:00
if ( t ! = null )
{
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
t . Update ( type , x , y , height , angledeg , pitch , roll , scaleX , scaleY , stringflags , tag , special , args ) ;
2009-04-19 18:07:22 +00:00
2010-08-15 19:43:00 +00:00
// Custom fields
ReadCustomFields ( c , t , "thing" ) ;
}
2009-04-19 18:07:22 +00:00
}
}
// This reads the linedefs and sidedefs
private void ReadLinedefs ( MapSet map , UniversalParser textmap ,
Dictionary < int , Vertex > vertexlink , Dictionary < int , Sector > sectorlink )
{
// Get list of entries
List < UniversalCollection > linescolls = GetNamedCollections ( textmap . Root , "linedef" ) ;
List < UniversalCollection > sidescolls = GetNamedCollections ( textmap . Root , "sidedef" ) ;
// Go for all lines
2009-06-18 14:23:33 +00:00
map . SetCapacity ( 0 , map . Linedefs . Count + linescolls . Count , map . Sidedefs . Count + sidescolls . Count , 0 , 0 ) ;
2016-05-16 13:04:31 +00:00
char [ ] splitter = { ' ' } ; //mxd
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < linescolls . Count ; i + + )
{
// Read fields
UniversalCollection lc = linescolls [ i ] ;
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
2009-06-15 21:58:34 +00:00
string where = "linedef " + i ;
2014-12-03 23:15:26 +00:00
int v1 = GetCollectionEntry ( lc , "v1" , true , 0 , where ) ;
int v2 = GetCollectionEntry ( lc , "v2" , true , 0 , where ) ;
2013-12-17 08:19:40 +00:00
2016-05-16 13:04:31 +00:00
if ( ! vertexlink . ContainsKey ( v1 ) | | ! vertexlink . ContainsKey ( v2 ) )
{ //mxd
2013-12-17 08:19:40 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references one or more invalid vertices. Linedef has been removed." ) ;
continue ;
}
2014-12-03 23:15:26 +00:00
int tag = GetCollectionEntry ( lc , "id" , false , 0 , where ) ;
int special = GetCollectionEntry ( lc , "special" , false , 0 , where ) ;
args [ 0 ] = GetCollectionEntry ( lc , "arg0" , false , 0 , where ) ;
args [ 1 ] = GetCollectionEntry ( lc , "arg1" , false , 0 , where ) ;
args [ 2 ] = GetCollectionEntry ( lc , "arg2" , false , 0 , where ) ;
args [ 3 ] = GetCollectionEntry ( lc , "arg3" , false , 0 , where ) ;
args [ 4 ] = GetCollectionEntry ( lc , "arg4" , false , 0 , where ) ;
2016-06-26 22:42:24 +00:00
int s1 = GetCollectionEntry ( lc , "sidefront" , false , - 1 , where ) ;
2014-12-03 23:15:26 +00:00
int s2 = GetCollectionEntry ( lc , "sideback" , false , - 1 , where ) ;
2009-04-19 18:07:22 +00:00
2015-07-27 21:35:42 +00:00
//mxd. MoreIDs
List < int > tags = new List < int > { tag } ;
string moreids = GetCollectionEntry ( lc , "moreids" , false , string . Empty , where ) ;
if ( ! string . IsNullOrEmpty ( moreids ) )
{
string [ ] moreidscol = moreids . Split ( splitter , StringSplitOptions . RemoveEmptyEntries ) ;
2015-12-28 15:01:53 +00:00
foreach ( string sid in moreidscol )
2015-07-27 21:35:42 +00:00
{
2015-12-28 15:01:53 +00:00
int id ;
2015-07-27 21:35:42 +00:00
if ( int . TryParse ( sid . Trim ( ) , out id ) & & id ! = 0 & & ! tags . Contains ( id ) )
{
tags . Add ( id ) ;
}
}
}
2015-08-07 21:32:51 +00:00
if ( tag = = 0 & & tags . Count > 1 ) tags . RemoveAt ( 0 ) ;
2015-07-27 21:35:42 +00:00
2009-04-19 18:07:22 +00:00
// Flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . LinedefFlags )
2014-12-03 23:15:26 +00:00
stringflags [ flag . Key ] = GetCollectionEntry ( lc , flag . Key , false , false , where ) ;
2009-04-19 18:07:22 +00:00
foreach ( FlagTranslation ft in General . Map . Config . LinedefFlagsTranslation )
{
foreach ( string field in ft . Fields )
2014-12-03 23:15:26 +00:00
stringflags [ field ] = GetCollectionEntry ( lc , field , false , false , where ) ;
2009-04-19 18:07:22 +00:00
}
// Activations
foreach ( LinedefActivateInfo activate in General . Map . Config . LinedefActivates )
2014-12-03 23:15:26 +00:00
stringflags [ activate . Key ] = GetCollectionEntry ( lc , activate . Key , false , false , where ) ;
2013-12-17 08:19:40 +00:00
// Check if not zero-length
if ( Vector2D . ManhattanDistance ( vertexlink [ v1 ] . Position , vertexlink [ v2 ] . Position ) > 0.0001f )
2009-04-19 18:07:22 +00:00
{
2013-12-17 08:19:40 +00:00
// Create new linedef
Linedef l = map . CreateLinedef ( vertexlink [ v1 ] , vertexlink [ v2 ] ) ;
if ( l ! = null )
2009-04-19 18:07:22 +00:00
{
2015-07-27 21:35:42 +00:00
l . Update ( stringflags , 0 , tags , special , args ) ;
2013-12-17 08:19:40 +00:00
l . UpdateCache ( ) ;
// Custom fields
ReadCustomFields ( lc , l , "linedef" ) ;
// Read sidedefs and connect them to the line
if ( s1 > - 1 )
2009-05-12 18:20:03 +00:00
{
2013-12-17 08:19:40 +00:00
if ( s1 < sidescolls . Count )
ReadSidedef ( map , sidescolls [ s1 ] , l , true , sectorlink , s1 ) ;
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed." ) ;
}
2010-08-15 19:43:00 +00:00
2013-12-17 08:19:40 +00:00
if ( s2 > - 1 )
{
if ( s2 < sidescolls . Count )
ReadSidedef ( map , sidescolls [ s2 ] , l , false , sectorlink , s2 ) ;
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed." ) ;
2009-05-12 18:20:03 +00:00
}
2009-04-19 18:07:22 +00:00
}
2013-12-17 08:19:40 +00:00
}
else
2009-04-19 18:07:22 +00:00
{
2013-12-17 08:19:40 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " is zero-length. Linedef has been removed." ) ;
2009-04-19 18:07:22 +00:00
}
}
}
// This reads a single sidedef and connects it to the given linedef
private void ReadSidedef ( MapSet map , UniversalCollection sc , Linedef ld ,
2009-06-15 21:58:34 +00:00
bool front , Dictionary < int , Sector > sectorlink , int index )
2009-04-19 18:07:22 +00:00
{
// Read fields
2009-06-15 21:58:34 +00:00
string where = "linedef " + ld . Index + ( front ? " front sidedef " : " back sidedef " ) + index ;
2014-11-25 11:52:01 +00:00
int offsetx = GetCollectionEntry ( sc , "offsetx" , false , 0 , where ) ;
int offsety = GetCollectionEntry ( sc , "offsety" , false , 0 , where ) ;
string thigh = GetCollectionEntry ( sc , "texturetop" , false , "-" , where ) ;
string tlow = GetCollectionEntry ( sc , "texturebottom" , false , "-" , where ) ;
string tmid = GetCollectionEntry ( sc , "texturemiddle" , false , "-" , where ) ;
int sector = GetCollectionEntry ( sc , "sector" , true , 0 , where ) ;
2009-04-19 18:07:22 +00:00
2013-07-19 15:30:58 +00:00
//mxd. Flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-07-19 15:30:58 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SidedefFlags )
2014-12-03 23:15:26 +00:00
stringflags [ flag . Key ] = GetCollectionEntry ( sc , flag . Key , false , false , where ) ;
2013-07-19 15:30:58 +00:00
2009-04-19 18:07:22 +00:00
// Create sidedef
if ( sectorlink . ContainsKey ( sector ) )
{
Sidedef s = map . CreateSidedef ( ld , front , sectorlink [ sector ] ) ;
2010-08-15 19:43:00 +00:00
if ( s ! = null )
{
2013-07-19 15:30:58 +00:00
s . Update ( offsetx , offsety , thigh , tmid , tlow , stringflags ) ;
2009-04-19 18:07:22 +00:00
2010-08-15 19:43:00 +00:00
// Custom fields
ReadCustomFields ( sc , s , "sidedef" ) ;
}
2009-04-19 18:07:22 +00:00
}
else
{
General . ErrorLogger . Add ( ErrorType . Warning , "Sidedef references invalid sector " + sector + ". Sidedef has been removed." ) ;
}
}
// This reads the sectors
private Dictionary < int , Sector > ReadSectors ( MapSet map , UniversalParser textmap )
{
// Get list of entries
List < UniversalCollection > collections = GetNamedCollections ( textmap . Root , "sector" ) ;
// Create lookup table
2014-11-25 11:52:01 +00:00
Dictionary < int , Sector > link = new Dictionary < int , Sector > ( collections . Count ) ;
2009-04-19 18:07:22 +00:00
// Go for all collections
2009-06-18 14:23:33 +00:00
map . SetCapacity ( 0 , 0 , 0 , map . Sectors . Count + collections . Count , 0 ) ;
2015-08-07 21:32:51 +00:00
char [ ] splitter = new [ ] { ' ' } ; //mxd
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < collections . Count ; i + + )
{
// Read fields
UniversalCollection c = collections [ i ] ;
2009-06-15 21:58:34 +00:00
string where = "sector " + i ;
2014-08-25 11:15:19 +00:00
int hfloor = GetCollectionEntry ( c , "heightfloor" , false , 0 , where ) ;
int hceil = GetCollectionEntry ( c , "heightceiling" , false , 0 , where ) ;
string tfloor = GetCollectionEntry ( c , "texturefloor" , true , "-" , where ) ;
string tceil = GetCollectionEntry ( c , "textureceiling" , true , "-" , where ) ;
int bright = GetCollectionEntry ( c , "lightlevel" , false , 160 , where ) ;
int special = GetCollectionEntry ( c , "special" , false , 0 , where ) ;
int tag = GetCollectionEntry ( c , "id" , false , 0 , where ) ;
2015-07-27 21:35:42 +00:00
//mxd. MoreIDs
List < int > tags = new List < int > { tag } ;
string moreids = GetCollectionEntry ( c , "moreids" , false , string . Empty , where ) ;
if ( ! string . IsNullOrEmpty ( moreids ) )
{
string [ ] moreidscol = moreids . Split ( splitter , StringSplitOptions . RemoveEmptyEntries ) ;
2015-12-28 15:01:53 +00:00
foreach ( string sid in moreidscol )
2015-07-27 21:35:42 +00:00
{
2015-12-28 15:01:53 +00:00
int id ;
2015-07-27 21:35:42 +00:00
if ( int . TryParse ( sid . Trim ( ) , out id ) & & id ! = 0 & & ! tags . Contains ( id ) )
{
tags . Add ( id ) ;
}
}
}
2015-08-07 21:32:51 +00:00
if ( tag = = 0 & & tags . Count > 1 ) tags . RemoveAt ( 0 ) ;
2015-07-27 21:35:42 +00:00
2014-08-25 11:15:19 +00:00
//mxd. Read slopes
float fslopex = GetCollectionEntry ( c , "floorplane_a" , false , 0.0f , where ) ;
float fslopey = GetCollectionEntry ( c , "floorplane_b" , false , 0.0f , where ) ;
float fslopez = GetCollectionEntry ( c , "floorplane_c" , false , 0.0f , where ) ;
float foffset = GetCollectionEntry ( c , "floorplane_d" , false , float . NaN , where ) ;
float cslopex = GetCollectionEntry ( c , "ceilingplane_a" , false , 0.0f , where ) ;
float cslopey = GetCollectionEntry ( c , "ceilingplane_b" , false , 0.0f , where ) ;
float cslopez = GetCollectionEntry ( c , "ceilingplane_c" , false , 0.0f , where ) ;
float coffset = GetCollectionEntry ( c , "ceilingplane_d" , false , float . NaN , where ) ;
//mxd. Read flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-07-10 08:59:17 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SectorFlags )
2014-08-25 11:15:19 +00:00
stringflags [ flag . Key ] = GetCollectionEntry ( c , flag . Key , false , false , where ) ;
2013-07-10 08:59:17 +00:00
2009-04-19 18:07:22 +00:00
// Create new item
Sector s = map . CreateSector ( ) ;
2010-08-15 19:43:00 +00:00
if ( s ! = null )
{
2015-07-27 21:35:42 +00:00
s . Update ( hfloor , hceil , tfloor , tceil , special , stringflags , tags , bright , foffset , new Vector3D ( fslopex , fslopey , fslopez ) . GetNormal ( ) , coffset , new Vector3D ( cslopex , cslopey , cslopez ) . GetNormal ( ) ) ;
2009-04-19 18:07:22 +00:00
2010-08-15 19:43:00 +00:00
// Custom fields
ReadCustomFields ( c , s , "sector" ) ;
2009-04-19 18:07:22 +00:00
2010-08-15 19:43:00 +00:00
// Add it to the lookup table
link . Add ( i , s ) ;
}
2009-04-19 18:07:22 +00:00
}
// Return lookup table
return link ;
}
// This reads the vertices
private Dictionary < int , Vertex > ReadVertices ( MapSet map , UniversalParser textmap )
{
// Get list of entries
List < UniversalCollection > collections = GetNamedCollections ( textmap . Root , "vertex" ) ;
// Create lookup table
2014-11-25 11:52:01 +00:00
Dictionary < int , Vertex > link = new Dictionary < int , Vertex > ( collections . Count ) ;
2009-04-19 18:07:22 +00:00
// Go for all collections
2009-06-18 14:23:33 +00:00
map . SetCapacity ( map . Vertices . Count + collections . Count , 0 , 0 , 0 , 0 ) ;
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < collections . Count ; i + + )
{
// Read fields
UniversalCollection c = collections [ i ] ;
2009-06-15 21:58:34 +00:00
string where = "vertex " + i ;
2014-12-03 23:15:26 +00:00
float x = GetCollectionEntry ( c , "x" , true , 0.0f , where ) ;
float y = GetCollectionEntry ( c , "y" , true , 0.0f , where ) ;
2009-04-19 18:07:22 +00:00
// Create new item
Vertex v = map . CreateVertex ( new Vector2D ( x , y ) ) ;
2010-08-15 19:43:00 +00:00
if ( v ! = null )
{
2013-07-08 13:13:28 +00:00
//mxd. zoffsets
2014-12-03 23:15:26 +00:00
v . ZCeiling = GetCollectionEntry ( c , "zceiling" , false , float . NaN , where ) ; //mxd
v . ZFloor = GetCollectionEntry ( c , "zfloor" , false , float . NaN , where ) ; //mxd
2013-07-08 13:13:28 +00:00
2010-08-15 19:43:00 +00:00
// Custom fields
ReadCustomFields ( c , v , "vertex" ) ;
2009-04-19 18:07:22 +00:00
2010-08-15 19:43:00 +00:00
// Add it to the lookup table
link . Add ( i , v ) ;
}
2009-04-19 18:07:22 +00:00
}
// Return lookup table
return link ;
}
// This reads custom fields from a collection and adds them to a map element
private void ReadCustomFields ( UniversalCollection collection , MapElement element , string elementname )
{
2009-06-11 21:21:20 +00:00
element . Fields . BeforeFieldsChange ( ) ;
2009-04-19 18:07:22 +00:00
// Go for all the elements in the collection
foreach ( UniversalEntry e in collection )
{
2013-08-12 10:15:08 +00:00
// mxd. Check if uifield
Removed "Paste Properties Options" action.
Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action.
Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them.
Changed, Paste Properties Special window: only options relevant to current map format are now displayed.
Changed, Paste Properties Special window, UDMF: all UI-managed options are now available.
Fixed: MAPINFO parser was unable to process "include" directives.
Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection.
Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode.
Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time.
Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map.
Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled.
Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category.
Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll.
Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format.
Internal: merged methods from UDMFTools into UniFields, removed UDMFTools.
Updated Inno Setup script (added VC++ 2008 SP1 distributive).
Updated ZDoom_DECORATE.cfg (A_CheckBlock).
Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
if ( uifields . ContainsKey ( element . ElementType ) & & uifields [ element . ElementType ] . ContainsKey ( e . Key ) )
2014-12-03 23:15:26 +00:00
{
Removed "Paste Properties Options" action.
Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action.
Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them.
Changed, Paste Properties Special window: only options relevant to current map format are now displayed.
Changed, Paste Properties Special window, UDMF: all UI-managed options are now available.
Fixed: MAPINFO parser was unable to process "include" directives.
Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection.
Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode.
Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time.
Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map.
Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled.
Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category.
Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll.
Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format.
Internal: merged methods from UDMFTools into UniFields, removed UDMFTools.
Updated Inno Setup script (added VC++ 2008 SP1 distributive).
Updated ZDoom_DECORATE.cfg (A_CheckBlock).
Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
int type = ( int ) uifields [ element . ElementType ] [ e . Key ] ;
2013-08-12 10:15:08 +00:00
//mxd. Check type
object value = e . Value ;
// Let's be kind and cast any int to a float if needed
2014-12-03 23:15:26 +00:00
if ( type = = ( int ) UniversalType . Float & & e . Value is int )
{
2013-08-12 10:15:08 +00:00
value = ( float ) ( int ) e . Value ;
2014-12-03 23:15:26 +00:00
}
else if ( ! e . IsValidType ( e . Value . GetType ( ) ) )
{
2016-03-08 20:41:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , element + ": the value of entry \"" + e . Key + "\" is of incompatible type (expected " + e . GetType ( ) . Name + ", but got " + e . Value . GetType ( ) . Name + "). If you save the map, this value will be ignored." ) ;
2013-08-12 10:15:08 +00:00
continue ;
}
2009-04-19 18:07:22 +00:00
2013-08-12 10:15:08 +00:00
// Make custom field
element . Fields [ e . Key ] = new UniValue ( type , value ) ;
2013-08-10 11:28:51 +00:00
2013-08-12 10:15:08 +00:00
} // Check if not a managed field
2013-11-06 09:34:47 +00:00
else if ( ! config . SettingExists ( "managedfields." + elementname + "." + e . Key ) )
2013-08-12 10:15:08 +00:00
{
int type = ( int ) UniversalType . Integer ;
2013-08-10 11:28:51 +00:00
2013-11-06 09:34:47 +00:00
//mxd. Try to find the type from configuration
2014-12-03 23:15:26 +00:00
if ( setknowncustomtypes )
{
2016-05-16 13:04:31 +00:00
type = General . Map . Options . GetUniversalFieldType ( elementname , e . Key , - 1 ) ;
2013-11-06 09:34:47 +00:00
2014-12-03 23:15:26 +00:00
if ( type ! = - 1 )
{
2013-11-06 09:34:47 +00:00
object value = e . Value ;
2013-09-11 09:47:53 +00:00
2013-11-06 09:34:47 +00:00
// Let's be kind and cast any int to a float if needed
2014-12-03 23:15:26 +00:00
if ( type = = ( int ) UniversalType . Float & & e . Value is int )
{
2013-11-06 09:34:47 +00:00
value = ( float ) ( int ) e . Value ;
2014-12-03 23:15:26 +00:00
}
else if ( ! e . IsValidType ( e . Value . GetType ( ) ) )
{
2016-03-08 20:41:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , element + ": the value of entry \"" + e . Key + "\" is of incompatible type (expected " + e . GetType ( ) . Name + ", but got " + e . Value . GetType ( ) . Name + "). If you save the map, this value will be ignored." ) ;
2013-11-06 09:34:47 +00:00
continue ;
}
2013-09-11 09:47:53 +00:00
2013-11-06 09:34:47 +00:00
// Make custom field
element . Fields [ e . Key ] = new UniValue ( type , value ) ;
2013-09-11 09:47:53 +00:00
continue ;
}
}
2013-11-06 09:34:47 +00:00
// Determine default type
if ( e . Value is int ) type = ( int ) UniversalType . Integer ;
else if ( e . Value is float ) type = ( int ) UniversalType . Float ;
else if ( e . Value is bool ) type = ( int ) UniversalType . Boolean ;
else if ( e . Value is string ) type = ( int ) UniversalType . String ;
// Make custom field
element . Fields [ e . Key ] = new UniValue ( type , e . Value ) ;
2009-04-19 18:07:22 +00:00
}
}
}
// This validates and returns an entry
2014-12-03 23:15:26 +00:00
private static T GetCollectionEntry < T > ( UniversalCollection c , string entryname , bool required , T defaultvalue , string where )
2009-04-19 18:07:22 +00:00
{
T result = default ( T ) ;
bool found = false ;
// Find the entry
foreach ( UniversalEntry e in c )
{
// Check if matches
if ( e . Key = = entryname )
{
// Let's be kind and cast any int to a float if needed
2013-12-17 08:19:40 +00:00
if ( ( typeof ( T ) = = typeof ( float ) ) & & ( e . Value is int ) )
2009-04-19 18:07:22 +00:00
{
// Make it a float
2009-04-26 07:34:19 +00:00
object fvalue = ( float ) ( int ) e . Value ;
result = ( T ) fvalue ;
2009-04-19 18:07:22 +00:00
}
else
{
// Verify type
e . ValidateType ( typeof ( T ) ) ;
// Found it!
result = ( T ) e . Value ;
}
// Done
found = true ;
}
}
// Not found?
if ( ! found )
{
2009-06-15 21:58:34 +00:00
// Report error when entry is required!
2009-04-19 18:07:22 +00:00
if ( required )
2016-03-08 20:41:06 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Error while reading UDMF map data: Missing required field \"" + entryname + "\" at " + where + "." ) ;
2009-06-15 21:58:34 +00:00
// Make default entry
result = defaultvalue ;
2009-04-19 18:07:22 +00:00
}
// Return result
return result ;
}
// This makes a list of all collections with the given name
2014-12-03 23:15:26 +00:00
private static List < UniversalCollection > GetNamedCollections ( UniversalCollection collection , string entryname )
2009-04-19 18:07:22 +00:00
{
List < UniversalCollection > list = new List < UniversalCollection > ( ) ;
// Make list
2015-12-28 15:01:53 +00:00
foreach ( UniversalEntry e in collection )
2014-12-03 23:15:26 +00:00
{
2016-03-18 12:52:12 +00:00
UniversalCollection uc = e . Value as UniversalCollection ;
if ( uc ! = null & & e . Key = = entryname ) list . Add ( uc ) ;
2013-12-17 08:19:40 +00:00
}
2009-04-19 18:07:22 +00:00
return list ;
}
#endregion
}
}