2013-12-17 08:19:40 +00:00
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections.Generic ;
using System.IO ;
using CodeImp.DoomBuilder.Config ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Types ;
2016-02-22 08:20:33 +00:00
using CodeImp.DoomBuilder.Windows ;
2013-12-17 08:19:40 +00:00
#endregion
namespace CodeImp.DoomBuilder.IO
{
internal class ClipboardStreamReader
{
#region = = = = = = = = = = = = = = = = = = Variables
private struct SidedefData
{
public int OffsetX ;
public int OffsetY ;
public int SectorID ;
public string HighTexture ;
public string MiddleTexture ;
public string LowTexture ;
public Dictionary < string , UniValue > Fields ;
public Dictionary < string , bool > Flags ;
}
2014-11-25 11:52:01 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2013-12-17 08:19:40 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Reading
// This reads from a stream
2016-02-22 08:20:33 +00:00
public bool Read ( MapSet map , Stream stream )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
BinaryReader reader = new BinaryReader ( stream ) ;
2016-02-22 08:20:33 +00:00
//mxd. Sanity checks
int numverts = reader . ReadInt32 ( ) ;
if ( map . Vertices . Count + numverts > = General . Map . FormatInterface . MaxVertices )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Cannot paste: resulting number of vertices (" + ( map . Vertices . Count + numverts ) + ") will exceed map format's maximum (" + General . Map . FormatInterface . MaxVertices + ")." ) ;
return false ;
}
int numsectors = reader . ReadInt32 ( ) ;
if ( map . Sectors . Count + numsectors > = General . Map . FormatInterface . MaxSectors )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Cannot paste: resulting number of sectors (" + ( map . Sectors . Count + numsectors ) + ") will exceed map format's maximum (" + General . Map . FormatInterface . MaxSectors + ")." ) ;
return false ;
}
int numlinedefs = reader . ReadInt32 ( ) ;
if ( map . Linedefs . Count + numlinedefs > = General . Map . FormatInterface . MaxLinedefs )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Cannot paste: resulting number of linedefs (" + ( map . Linedefs . Count + numlinedefs ) + ") will exceed map format's maximum (" + General . Map . FormatInterface . MaxLinedefs + ")." ) ;
return false ;
}
int numthings = reader . ReadInt32 ( ) ;
if ( map . Things . Count + numthings > = General . Map . FormatInterface . MaxThings )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Cannot paste: resulting number of things (" + ( map . Things . Count + numthings ) + ") will exceed map format's maximum (" + General . Map . FormatInterface . MaxThings + ")." ) ;
return false ;
}
2013-12-17 08:19:40 +00:00
// Read the map
Dictionary < int , Vertex > vertexlink = ReadVertices ( map , reader ) ;
Dictionary < int , Sector > sectorlink = ReadSectors ( map , reader ) ;
Dictionary < int , SidedefData > sidedeflink = ReadSidedefs ( reader ) ;
ReadLinedefs ( map , reader , vertexlink , sectorlink , sidedeflink ) ;
ReadThings ( map , reader ) ;
2016-02-22 08:20:33 +00:00
return true ;
2013-12-17 08:19:40 +00:00
}
2014-12-03 23:15:26 +00:00
private static Dictionary < int , Vertex > ReadVertices ( MapSet map , BinaryReader reader )
{
2013-12-17 08:19:40 +00:00
int count = reader . ReadInt32 ( ) ;
// Create lookup table
Dictionary < int , Vertex > link = new Dictionary < int , Vertex > ( count ) ;
// Go for all collections
map . SetCapacity ( map . Vertices . Count + count , 0 , 0 , 0 , 0 ) ;
2014-12-03 23:15:26 +00:00
for ( int i = 0 ; i < count ; i + + )
{
2013-12-17 08:19:40 +00:00
float x = reader . ReadSingle ( ) ;
float y = reader . ReadSingle ( ) ;
float zc = reader . ReadSingle ( ) ;
float zf = reader . ReadSingle ( ) ;
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Vertex v = map . CreateVertex ( new Vector2D ( x , y ) ) ;
2014-12-03 23:15:26 +00:00
if ( v ! = null )
{
2013-12-17 08:19:40 +00:00
//zoffsets
v . ZCeiling = zc ;
v . ZFloor = zf ;
// Add custom fields
v . Fields . BeforeFieldsChange ( ) ;
2015-12-28 15:01:53 +00:00
foreach ( KeyValuePair < string , UniValue > group in fields )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
v . Fields . Add ( group . Key , group . Value ) ;
}
// Add it to the lookup table
link . Add ( i , v ) ;
}
}
// Return lookup table
return link ;
}
2014-12-03 23:15:26 +00:00
private static Dictionary < int , Sector > ReadSectors ( MapSet map , BinaryReader reader )
{
2013-12-17 08:19:40 +00:00
int count = reader . ReadInt32 ( ) ;
// Create lookup table
Dictionary < int , Sector > link = new Dictionary < int , Sector > ( count ) ;
// Go for all collections
map . SetCapacity ( 0 , 0 , 0 , map . Sectors . Count + count , 0 ) ;
2015-12-28 15:01:53 +00:00
for ( int i = 0 ; i < count ; i + + )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
int effect = reader . ReadInt32 ( ) ;
int hfloor = reader . ReadInt32 ( ) ;
int hceil = reader . ReadInt32 ( ) ;
int bright = reader . ReadInt32 ( ) ;
2015-07-27 21:35:42 +00:00
//mxd. Tags
int numtags = reader . ReadInt32 ( ) ; //mxd
List < int > tags = new List < int > ( numtags ) ; //mxd
for ( int a = 0 ; a < numtags ; a + + ) tags . Add ( reader . ReadInt32 ( ) ) ; //mxd
2013-12-17 08:19:40 +00:00
string tfloor = ReadString ( reader ) ;
string tceil = ReadString ( reader ) ;
2014-08-25 11:15:19 +00:00
//mxd. Slopes
float foffset = reader . ReadSingle ( ) ;
Vector3D fslope = new Vector3D ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
float coffset = reader . ReadSingle ( ) ;
Vector3D cslope = new Vector3D ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
2013-12-17 08:19:40 +00:00
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
2016-01-15 22:27:18 +00:00
for ( int f = 0 ; f < numFlags ; f + + ) stringflags . Add ( ReadString ( reader ) , reader . ReadBoolean ( ) ) ;
2013-12-17 08:19:40 +00:00
//add missing flags
2015-12-28 15:01:53 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SectorFlags )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
2016-10-11 12:58:35 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . CeilingPortalFlags )
{
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
foreach ( KeyValuePair < string , string > flag in General . Map . Config . FloorPortalFlags )
{
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
2013-12-17 08:19:40 +00:00
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Sector s = map . CreateSector ( ) ;
2014-12-03 23:15:26 +00:00
if ( s ! = null )
{
2015-07-27 21:35:42 +00:00
s . Update ( hfloor , hceil , tfloor , tceil , effect , stringflags , tags , bright , foffset , fslope , coffset , cslope ) ;
2013-12-17 08:19:40 +00:00
// Add custom fields
s . Fields . BeforeFieldsChange ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , UniValue > group in fields )
{
2013-12-17 08:19:40 +00:00
s . Fields . Add ( group . Key , group . Value ) ;
}
// Add it to the lookup table
link . Add ( i , s ) ;
}
}
// Return lookup table
return link ;
}
// This reads the linedefs and sidedefs
2014-12-03 23:15:26 +00:00
private static void ReadLinedefs ( MapSet map , BinaryReader reader , Dictionary < int , Vertex > vertexlink , Dictionary < int , Sector > sectorlink , Dictionary < int , SidedefData > sidedeflink )
{
2013-12-17 08:19:40 +00:00
int count = reader . ReadInt32 ( ) ;
// Go for all lines
map . SetCapacity ( 0 , map . Linedefs . Count + count , map . Sidedefs . Count + sidedeflink . Count , 0 , 0 ) ;
2014-12-03 23:15:26 +00:00
for ( int i = 0 ; i < count ; i + + )
{
2013-12-17 08:19:40 +00:00
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
int v1 = reader . ReadInt32 ( ) ;
int v2 = reader . ReadInt32 ( ) ;
int s1 = reader . ReadInt32 ( ) ;
int s2 = reader . ReadInt32 ( ) ;
int special = reader . ReadInt32 ( ) ;
2014-12-03 23:15:26 +00:00
for ( int a = 0 ; a < Linedef . NUM_ARGS ; a + + ) args [ a ] = reader . ReadInt32 ( ) ;
2015-07-27 21:35:42 +00:00
int numtags = reader . ReadInt32 ( ) ; //mxd
List < int > tags = new List < int > ( numtags ) ; //mxd
for ( int a = 0 ; a < numtags ; a + + ) tags . Add ( reader . ReadInt32 ( ) ) ; //mxd
2013-12-17 08:19:40 +00:00
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
2016-01-15 22:27:18 +00:00
for ( int f = 0 ; f < numFlags ; f + + ) stringflags . Add ( ReadString ( reader ) , reader . ReadBoolean ( ) ) ;
2013-12-17 08:19:40 +00:00
//add missing flags
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . LinedefFlags )
{
2013-12-17 08:19:40 +00:00
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
//add missing activations
2015-12-28 15:01:53 +00:00
foreach ( LinedefActivateInfo activate in General . Map . Config . LinedefActivates )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
if ( stringflags . ContainsKey ( activate . Key ) ) continue ;
stringflags . Add ( activate . Key , false ) ;
}
// Read custom fields
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
// Check if not zero-length
2015-12-28 15:01:53 +00:00
if ( Vector2D . ManhattanDistance ( vertexlink [ v1 ] . Position , vertexlink [ v2 ] . Position ) > 0.0001f )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
// Create new linedef
Linedef l = map . CreateLinedef ( vertexlink [ v1 ] , vertexlink [ v2 ] ) ;
2015-12-28 15:01:53 +00:00
if ( l ! = null )
2014-12-03 23:15:26 +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 ( ) ;
// Add custom fields
l . Fields . BeforeFieldsChange ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , UniValue > group in fields )
{
2013-12-17 08:19:40 +00:00
l . Fields . Add ( group . Key , group . Value ) ;
}
// Connect sidedefs to the line
2014-12-03 23:15:26 +00:00
if ( s1 > - 1 )
{
2013-12-17 08:19:40 +00:00
if ( s1 < sidedeflink . Count )
2014-02-26 14:11:06 +00:00
AddSidedef ( map , sidedeflink [ s1 ] , l , true , sectorlink ) ;
2013-12-17 08:19:40 +00:00
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed." ) ;
}
2014-12-03 23:15:26 +00:00
if ( s2 > - 1 )
{
2013-12-17 08:19:40 +00:00
if ( s2 < sidedeflink . Count )
2014-02-26 14:11:06 +00:00
AddSidedef ( map , sidedeflink [ s2 ] , l , false , sectorlink ) ;
2013-12-17 08:19:40 +00:00
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed." ) ;
}
}
2014-12-03 23:15:26 +00:00
}
else
{
2013-12-17 08:19:40 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " is zero-length. Linedef has been removed." ) ;
}
}
}
2014-12-03 23:15:26 +00:00
private static void AddSidedef ( MapSet map , SidedefData data , Linedef ld , bool front , Dictionary < int , Sector > sectorlink )
{
2013-12-17 08:19:40 +00:00
// Create sidedef
2014-12-03 23:15:26 +00:00
if ( sectorlink . ContainsKey ( data . SectorID ) )
{
2013-12-17 08:19:40 +00:00
Sidedef s = map . CreateSidedef ( ld , front , sectorlink [ data . SectorID ] ) ;
2014-12-03 23:15:26 +00:00
if ( s ! = null )
{
2013-12-17 08:19:40 +00:00
s . Update ( data . OffsetX , data . OffsetY , data . HighTexture , data . MiddleTexture , data . LowTexture , data . Flags ) ;
// Add custom fields
2015-12-28 15:01:53 +00:00
foreach ( KeyValuePair < string , UniValue > group in data . Fields )
2014-12-03 23:15:26 +00:00
{
2013-12-17 08:19:40 +00:00
s . Fields . Add ( group . Key , group . Value ) ;
}
}
2014-12-03 23:15:26 +00:00
}
else
{
2013-12-17 08:19:40 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Sidedef references invalid sector " + data . SectorID + ". Sidedef has been removed." ) ;
}
}
2014-12-03 23:15:26 +00:00
private static Dictionary < int , SidedefData > ReadSidedefs ( BinaryReader reader )
{
2013-12-17 08:19:40 +00:00
Dictionary < int , SidedefData > sidedeflink = new Dictionary < int , SidedefData > ( ) ;
int count = reader . ReadInt32 ( ) ;
2014-12-03 23:15:26 +00:00
for ( int i = 0 ; i < count ; i + + )
{
2013-12-17 08:19:40 +00:00
SidedefData data = new SidedefData ( ) ;
data . OffsetX = reader . ReadInt32 ( ) ;
data . OffsetY = reader . ReadInt32 ( ) ;
data . SectorID = reader . ReadInt32 ( ) ;
data . HighTexture = ReadString ( reader ) ;
data . MiddleTexture = ReadString ( reader ) ;
data . LowTexture = ReadString ( reader ) ;
//flags
2014-02-26 14:11:06 +00:00
data . Flags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
2016-01-15 22:27:18 +00:00
for ( int f = 0 ; f < numFlags ; f + + ) data . Flags . Add ( ReadString ( reader ) , reader . ReadBoolean ( ) ) ;
2013-12-17 08:19:40 +00:00
//add missing flags
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SidedefFlags )
{
2013-12-17 08:19:40 +00:00
if ( data . Flags . ContainsKey ( flag . Key ) ) continue ;
data . Flags . Add ( flag . Key , false ) ;
}
//custom fields
data . Fields = ReadCustomFields ( reader ) ;
sidedeflink . Add ( i , data ) ;
}
return sidedeflink ;
}
2014-12-03 23:15:26 +00:00
private static void ReadThings ( MapSet map , BinaryReader reader )
{
2013-12-17 08:19:40 +00:00
int count = reader . ReadInt32 ( ) ;
// Go for all collections
map . SetCapacity ( 0 , 0 , 0 , 0 , map . Things . Count + count ) ;
2014-12-03 23:15:26 +00:00
for ( int i = 0 ; i < count ; i + + )
{
2013-12-17 08:19:40 +00:00
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
int tag = reader . ReadInt32 ( ) ;
float x = reader . ReadSingle ( ) ;
float y = reader . ReadSingle ( ) ;
float height = reader . ReadSingle ( ) ;
int angledeg = reader . ReadInt32 ( ) ;
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
int pitch = reader . ReadInt32 ( ) ; //mxd
int roll = reader . ReadInt32 ( ) ; //mxd
float scaleX = reader . ReadSingle ( ) ; //mxd
float scaleY = reader . ReadSingle ( ) ; //mxd
2013-12-17 08:19:40 +00:00
int type = reader . ReadInt32 ( ) ;
int special = reader . ReadInt32 ( ) ;
2014-12-03 23:15:26 +00:00
for ( int a = 0 ; a < Linedef . NUM_ARGS ; a + + ) args [ a ] = reader . ReadInt32 ( ) ;
2013-12-17 08:19:40 +00:00
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
2016-01-15 18:20:47 +00:00
for ( int f = 0 ; f < numFlags ; f + + ) stringflags . Add ( ReadString ( reader ) , reader . ReadBoolean ( ) ) ;
2013-12-17 08:19:40 +00:00
//add missing flags
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , string > flag in General . Map . Config . ThingFlags )
{
2013-12-17 08:19:40 +00:00
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Thing t = map . CreateThing ( ) ;
2014-12-03 23:15:26 +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 ) ;
2013-12-17 08:19:40 +00:00
// Add custom fields
t . Fields . BeforeFieldsChange ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , UniValue > group in fields )
{
2013-12-17 08:19:40 +00:00
t . Fields . Add ( group . Key , group . Value ) ;
}
}
}
}
2014-12-03 23:15:26 +00:00
private static Dictionary < string , UniValue > ReadCustomFields ( BinaryReader reader )
{
2014-02-26 14:11:06 +00:00
Dictionary < string , UniValue > fields = new Dictionary < string , UniValue > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int fieldscount = reader . ReadInt32 ( ) ;
2014-12-03 23:15:26 +00:00
for ( int f = 0 ; f < fieldscount ; f + + )
{
2013-12-17 08:19:40 +00:00
string name = ReadString ( reader ) ;
UniversalType type = ( UniversalType ) reader . ReadInt32 ( ) ;
UniversalType valueType = ( UniversalType ) reader . ReadInt32 ( ) ;
2014-12-03 23:15:26 +00:00
switch ( valueType )
{
2013-12-17 08:19:40 +00:00
case UniversalType . Float :
fields . Add ( name , new UniValue ( type , reader . ReadSingle ( ) ) ) ;
break ;
case UniversalType . Boolean :
fields . Add ( name , new UniValue ( type , reader . ReadBoolean ( ) ) ) ;
break ;
case UniversalType . Integer :
fields . Add ( name , new UniValue ( type , reader . ReadInt32 ( ) ) ) ;
break ;
case UniversalType . String :
fields . Add ( name , new UniValue ( type , ReadString ( reader ) ) ) ;
break ;
default : //WOLOLO! ERRORS!
2016-02-22 08:20:33 +00:00
throw new Exception ( "Got unknown value type while reading custom fields from clipboard data! Field \"" + name + "\", type \"" + type + "\", primitive type \"" + valueType + "\"" ) ;
2013-12-17 08:19:40 +00:00
}
}
return fields ;
}
2014-12-03 23:15:26 +00:00
private static string ReadString ( BinaryReader reader )
{
2013-12-17 08:19:40 +00:00
int len = reader . ReadInt32 ( ) ;
2015-12-28 15:01:53 +00:00
if ( len = = 0 ) return string . Empty ;
2013-12-17 08:19:40 +00:00
char [ ] chars = new char [ len ] ;
2015-12-28 15:01:53 +00:00
for ( int i = 0 ; i < len ; + + i ) chars [ i ] = reader . ReadChar ( ) ;
2013-12-17 08:19:40 +00:00
return new string ( chars ) ;
}
#endregion
}
}