44using System . IO . Compression ;
55using System . Text ;
66using JetBrains . Annotations ;
7+ using ServiceStack . Text ;
78
89namespace fCraft . MapConversion {
910 /// <summary> ClassicWorld map conversion implementation, for converting ClassicWorld map format into fCraft's default map format. </summary>
@@ -81,7 +82,8 @@ public Map Load( string fileName ) {
8182 map . Spawn = new Position {
8283 X = ( spawnTag [ "X" ] . GetShort ( ) * 32 ) ,
8384 Y = ( spawnTag [ "Z" ] . GetShort ( ) * 32 ) ,
84- Z = ( spawnTag [ "Y" ] . GetShort ( ) * 32 ) ,
85+ //I think a negative Player.CharacterHeight is being used somewhere and is breaking spawn height
86+ Z = ( spawnTag [ "Y" ] . GetShort ( ) * 32 ) + Player . CharacterHeight ,
8587 R = spawnTag [ "H" ] . GetByte ( ) ,
8688 L = spawnTag [ "P" ] . GetByte ( ) ,
8789 } ;
@@ -110,8 +112,159 @@ public Map Load( string fileName ) {
110112 }
111113
112114 map . Blocks = root [ "BlockArray" ] . GetBytes ( ) ;
115+ if ( root . Contains ( "Metadata" ) ) ReadMetadata ( root [ "Metadata" ] , map , fileName ) ;
113116 return map ;
114117 }
115118 }
119+ void ReadMetadata ( NBTag root , Map map , String fileName ) {
120+ if ( ! root . Contains ( "CPE" ) )
121+ return ;
122+ NBTag cpe = root [ "CPE" ] ;
123+
124+ if ( cpe . Contains ( "EnvWeatherType" ) )
125+ map . Metadata . Add ( "CPE" , "Weather" , cpe [ "EnvWeatherType" ] [ "WeatherType" ] . GetByte ( ) . ToString ( ) ) ;
126+ if ( cpe . Contains ( "ClickDistance" ) )
127+ map . Metadata . Add ( "CPE" , "ClickDistance" , cpe [ "ClickDistance" ] [ "Distance" ] . GetShort ( ) . ToString ( ) ) ;
128+ if ( cpe . Contains ( "EnvMapAppearance" ) )
129+ ParseEnvMapAppearance ( cpe , map ) ;
130+ if ( cpe . Contains ( "EnvColors" ) )
131+ ParseEnvColors ( cpe , map ) ;
132+ if ( cpe . Contains ( "BlockDefinitions" ) )
133+ ParseBlockDefinitions ( cpe , map , fileName ) ;
134+ }
135+
136+
137+ static void ParseEnvMapAppearance ( NBTag cpe , Map map ) {
138+ map . Metadata . Add ( "CPE" , "HasEnvMapAppearance" , "true" ) ;
139+ NBTag comp = cpe [ "EnvMapAppearance" ] ;
140+ map . Metadata . Add ( "CPE" , "HorizonBlock" , comp [ "EdgeBlock" ] . GetByte ( ) . ToString ( ) ) ;
141+ map . Metadata . Add ( "CPE" , "EdgeBlock" , comp [ "SideBlock" ] . GetByte ( ) . ToString ( ) ) ;
142+ map . Metadata . Add ( "CPE" , "EdgeLevel" , comp [ "SideLevel" ] . GetShort ( ) . ToString ( ) ) ;
143+ if ( ! comp . Contains ( "TextureURL" ) )
144+ return ;
145+
146+ string url = comp [ "TextureURL" ] . GetString ( ) ;
147+ map . Metadata . Add ( "CPE" , "Texture" , url == Server . DefaultTerrain ? "default" : url ) ;
148+ }
149+ static void ParseEnvColors ( NBTag cpe , Map map ) {
150+ map . Metadata . Add ( "CPE" , "HasEnvColors" , "true" ) ;
151+ NBTag comp = cpe [ "EnvColors" ] ;
152+ map . Metadata . Add ( "CPE" , "SkyColor" , GetColor ( comp , "Sky" ) ) ;
153+ map . Metadata . Add ( "CPE" , "CloudColor" , GetColor ( comp , "Cloud" ) ) ;
154+ map . Metadata . Add ( "CPE" , "FogColor" , GetColor ( comp , "Fog" ) ) ;
155+ map . Metadata . Add ( "CPE" , "LightColor" , GetColor ( comp , "Sunlight" ) ) ;
156+ map . Metadata . Add ( "CPE" , "ShadowColor" , GetColor ( comp , "Ambient" ) ) ;
157+ }
158+
159+ static string GetColor ( NBTag comp , string type ) {
160+ if ( ! comp . Contains ( type ) )
161+ return "" ;
162+ NBTag rgb = comp [ type ] ;
163+ short r = rgb [ "R" ] . GetShort ( ) , g = rgb [ "G" ] . GetShort ( ) , b = rgb [ "B" ] . GetShort ( ) ;
164+
165+ if ( r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 )
166+ return "" ;
167+ return r . ToString ( "X2" ) + g . ToString ( "X2" ) + b . ToString ( "X2" ) ;
168+ }
169+
170+ public static BlockDefinition [ ] blockDefs = new BlockDefinition [ 256 ] ;
171+
172+ static void ParseBlockDefinitions ( NBTag cpe , Map map , String fileName ) {
173+ NBTag blocks = cpe [ "BlockDefinitions" ] ;
174+ bool hasBlockDefs = false ;
175+ blockDefs = new BlockDefinition [ 256 ] ;
176+
177+ foreach ( NBTag tag in blocks ) {
178+ if ( tag . Type != NBTType . Compound ) continue ;
179+
180+ NBTag props = tag ;
181+ BlockDefinition def = new BlockDefinition ( ) ;
182+ def . BlockID = props [ "ID" ] . GetByte ( ) ;
183+ // can't change "ID" to short since backwards compatibility
184+ if ( props . Contains ( "ID2" ) ) {
185+ ushort tempID = ( ushort ) props [ "ID2" ] . GetShort ( ) ;
186+ if ( tempID >= 256 ) continue ;
187+ def . BlockID = ( byte ) tempID ;
188+ }
189+
190+ def . Name = props [ "Name" ] . GetString ( ) ;
191+ def . CollideType = props [ "CollideType" ] . GetByte ( ) ;
192+ def . Speed = props [ "Speed" ] . GetFloat ( ) ;
193+
194+ def . BlocksLight = props [ "TransmitsLight" ] . GetByte ( ) == 0 ;
195+ def . WalkSound = props [ "WalkSound" ] . GetByte ( ) ;
196+ def . FullBright = props [ "FullBright" ] . GetByte ( ) != 0 ;
197+ def . Shape = props [ "Shape" ] . GetByte ( ) ;
198+ def . BlockDraw = props [ "BlockDraw" ] . GetByte ( ) ;
199+
200+ byte [ ] fog = props [ "Fog" ] . GetBytes ( ) ;
201+ def . FogDensity = fog [ 0 ] ;
202+ // Fix for older ClassicalSharp versions which saved wrong value for density = 0
203+ if ( def . FogDensity == 0xFF )
204+ def . FogDensity = 0 ;
205+ def . FogR = fog [ 1 ] ;
206+ def . FogG = fog [ 2 ] ;
207+ def . FogB = fog [ 3 ] ;
208+
209+ byte [ ] tex = props [ "Textures" ] . GetBytes ( ) ;
210+ def . TopTex = tex [ 0 ] ;
211+ def . BottomTex = tex [ 1 ] ;
212+ def . LeftTex = tex [ 2 ] ;
213+ def . RightTex = tex [ 3 ] ;
214+ def . FrontTex = tex [ 4 ] ;
215+ def . BackTex = tex [ 5 ] ;
216+
217+ byte [ ] coords = props [ "Coords" ] . GetBytes ( ) ;
218+ def . MinX = coords [ 0 ] ;
219+ def . MinZ = coords [ 1 ] ;
220+ def . MinY = coords [ 2 ] ;
221+ def . MaxX = coords [ 3 ] ;
222+ def . MaxZ = coords [ 4 ] ;
223+ def . MaxY = coords [ 5 ] ;
224+
225+ // Don't define level custom block if same as global custom block
226+ if ( PropsEquals ( def , BlockDefinition . GlobalDefs [ def . BlockID ] ) )
227+ continue ;
228+
229+ blockDefs [ def . BlockID ] = def ;
230+ hasBlockDefs = true ;
231+ }
232+
233+ if ( hasBlockDefs ) {
234+ BlockDefinition [ ] realDefs = new BlockDefinition [ 256 ] ;
235+ int count = 0 ;
236+ for ( int i = 0 ; i < 256 ; i ++ ) {
237+ if ( blockDefs [ i ] == BlockDefinition . GlobalDefs [ i ] ) realDefs [ i ] = null ;
238+ else {
239+ count ++ ;
240+ realDefs [ i ] = blockDefs [ i ] ;
241+ }
242+ }
243+ blockDefs = realDefs ;
244+
245+ string path = Paths . BlockDefsDirectory ;
246+ path = Path . Combine ( path , Path . GetFileName ( fileName ) + ".txt" ) ;
247+ map . Metadata [ "CPE" , "HasBlockDefFile" ] = "true" ;
248+ map . Metadata [ "CPE" , "BlockDefFileName" ] = Path . GetFileName ( fileName ) ;
249+ try {
250+ using ( Stream s = File . Create ( path ) )
251+ JsonSerializer . SerializeToStream ( blockDefs , s ) ;
252+ }
253+ catch ( Exception ex ) {
254+ Logger . Log ( LogType . Error , "BlockDefinitions.Save: " + ex ) ;
255+ }
256+ }
257+ }
258+ static bool PropsEquals ( BlockDefinition a , BlockDefinition b ) {
259+ if ( b == null || b . Name == null )
260+ return false ;
261+ return a . Name == b . Name && a . CollideType == b . CollideType && a . Speed == b . Speed && a . TopTex == b . TopTex
262+ && a . BottomTex == b . BottomTex && a . BlocksLight == b . BlocksLight && a . WalkSound == b . WalkSound
263+ && a . FullBright == b . FullBright && a . Shape == b . Shape && a . BlockDraw == b . BlockDraw
264+ && a . FogDensity == b . FogDensity && a . FogR == b . FogR && a . FogG == b . FogG && a . FogB == b . FogB
265+ && a . MinX == b . MinX && a . MinY == b . MinY && a . MinZ == b . MinZ && a . MaxX == b . MaxX
266+ && a . MaxY == b . MaxY && a . MaxZ == b . MaxZ && a . LeftTex == b . LeftTex && a . RightTex == b . RightTex
267+ && a . FrontTex == b . FrontTex && a . BackTex == b . BackTex ;
268+ }
116269 }
117270}
0 commit comments