ClassiCube/ClassicalSharp/Map/Formats/MapCw.Exporter.cs
2016-05-11 19:29:59 +10:00

200 lines
7.1 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.IO;
using System.IO.Compression;
using ClassicalSharp.Entities;
using OpenTK;
namespace ClassicalSharp.Map {
public sealed class MapCwExporter : IMapFormatExporter {
BinaryWriter writer;
NbtFile nbt;
Game game;
World map;
public void Save( Stream stream, Game game ) {
using( GZipStream wrapper = new GZipStream( stream, CompressionMode.Compress ) ) {
writer = new BinaryWriter( wrapper );
nbt = new NbtFile( writer );
this.game = game;
map = game.World;
nbt.Write( NbtTagType.Compound ); nbt.Write( "ClassicWorld" );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "FormatVersion" ); nbt.WriteInt8( 1 );
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "UUID" ); nbt.WriteInt32( 16 );
nbt.WriteBytes( map.Uuid.ToByteArray() );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "X" ); nbt.WriteInt16( (short)map.Width );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Y" ); nbt.WriteInt16( (short)map.Height );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Z" ); nbt.WriteInt16( (short)map.Length );
WriteSpawnCompoundTag();
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "BlockArray" ); nbt.WriteInt32( map.blocks.Length );
nbt.WriteBytes( map.blocks );
WriteMetadata();
nbt.Write( NbtTagType.End );
}
}
void WriteSpawnCompoundTag() {
nbt.Write( NbtTagType.Compound ); nbt.Write( "Spawn" );
LocalPlayer p = game.LocalPlayer;
Vector3 spawn = p.Position; // TODO: Maybe also keep real spawn too?
nbt.Write( NbtTagType.Int16 );
nbt.Write( "X" ); nbt.WriteInt16( (short)spawn.X );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Y" ); nbt.WriteInt16( (short)spawn.Y );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Z" ); nbt.WriteInt16( (short)spawn.Z );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "H" );
nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnYaw ) );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "P" );
nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnPitch ) );
nbt.Write( NbtTagType.End );
}
void WriteMetadata() {
nbt.Write( NbtTagType.Compound ); nbt.Write( "Metadata" );
nbt.Write( NbtTagType.Compound ); nbt.Write( "CPE" );
LocalPlayer p = game.LocalPlayer;
nbt.WriteCpeExtCompound( "ClickDistance", 1 );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Distance" ); nbt.WriteInt16( (short)(p.ReachDistance * 32) );
nbt.Write( NbtTagType.End );
nbt.WriteCpeExtCompound( "EnvWeatherType", 1 );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "WeatherType" ); nbt.WriteUInt8( (byte)map.Env.Weather );
nbt.Write( NbtTagType.End );
nbt.WriteCpeExtCompound( "EnvMapAppearance", 1 );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "SideBlock" ); nbt.WriteUInt8( (byte)map.Env.SidesBlock );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "EdgeBlock" ); nbt.WriteUInt8( (byte)map.Env.EdgeBlock );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "SideLevel" ); nbt.WriteInt16( (short)map.Env.EdgeHeight );
nbt.Write( NbtTagType.String );
string url = game.World.TextureUrl == null ? "" : game.World.TextureUrl;
nbt.Write( "TextureURL" ); nbt.Write( url );
nbt.Write( NbtTagType.End );
nbt.WriteCpeExtCompound( "EnvColors", 1 );
WriteColourCompound( "Sky", map.Env.SkyCol );
WriteColourCompound( "Cloud", map.Env.CloudsCol );
WriteColourCompound( "Fog", map.Env.FogCol );
WriteColourCompound( "Ambient", map.Env.Shadowlight );
WriteColourCompound( "Sunlight", map.Env.Sunlight );
nbt.Write( NbtTagType.End );
nbt.WriteCpeExtCompound( "BlockDefinitions", 1 );
uint[] flags = game.BlockInfo.DefinedCustomBlocks;
for( int tile = 1; tile < 256; tile++ ) {
if( (flags[tile >> 5] & (1u << (tile & 0x1F))) != 0 )
WriteBlockDefinitionCompound( (byte)tile );
}
nbt.Write( NbtTagType.End );
nbt.Write( NbtTagType.End );
nbt.Write( NbtTagType.End );
}
void WriteColourCompound( string name, FastColour col ) {
nbt.Write( NbtTagType.Compound ); nbt.Write( name );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "R" ); nbt.WriteInt16( col.R );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "G" ); nbt.WriteInt16( col.G );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "B" ); nbt.WriteInt16( col.B );
nbt.Write( NbtTagType.End );
}
unsafe void WriteBlockDefinitionCompound( byte id ) {
BlockInfo info = game.BlockInfo;
nbt.Write( NbtTagType.Compound ); nbt.Write( "Block" + id );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "ID" ); nbt.WriteUInt8( id );
nbt.Write( NbtTagType.String );
nbt.Write( "Name" ); nbt.Write( info.Name[id] );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "CollideType" ); nbt.WriteUInt8( (byte)info.Collide[id] );
float speed = info.SpeedMultiplier[id];
nbt.Write( NbtTagType.Real32 );
nbt.Write( "Speed" ); nbt.WriteInt32( *((int*)&speed) );
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "Textures" ); nbt.WriteInt32( 6 );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Top ) );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Bottom ) );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Left ) );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Right ) );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Front ) );
nbt.WriteUInt8( info.GetTextureLoc( id, Side.Back ) );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "TransmitsLight" ); nbt.WriteUInt8( info.BlocksLight[id] ? 0 : 1 );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "WalkSound" ); nbt.WriteUInt8( (byte)info.DigSounds[id] );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "FullBright" ); nbt.WriteUInt8( info.FullBright[id] ? 1 : 0 );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "Shape" ); nbt.WriteUInt8( GetShape( info, id ) );
nbt.Write( NbtTagType.Int8 );
nbt.Write( "BlockDraw" ); nbt.WriteUInt8( GetDraw( info, id ) );
FastColour col = info.FogColour[id];
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "Fog" ); nbt.WriteInt32( 4 );
nbt.WriteUInt8( (byte)(128 * info.FogDensity[id] - 1) );
nbt.WriteUInt8( col.R ); nbt.WriteUInt8( col.G ); nbt.WriteUInt8( col.B );
Vector3 min = info.MinBB[id], max = info.MaxBB[id];
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "Coords" ); nbt.WriteInt32( 6 );
nbt.WriteUInt8( (byte)(min.X * 16) ); nbt.WriteUInt8( (byte)(min.Y * 16) );
nbt.WriteUInt8( (byte)(min.Z * 16) ); nbt.WriteUInt8( (byte)(max.X * 16) );
nbt.WriteUInt8( (byte)(max.Y * 16) ); nbt.WriteUInt8( (byte)(max.Z * 16) );
nbt.Write( NbtTagType.End );
}
int GetShape( BlockInfo info, byte id ) {
return info.IsSprite[id] ? 0 : (byte)(info.MaxBB[id].Y * 16);
}
int GetDraw( BlockInfo info, byte id) {
if( info.IsTranslucent[id] ) return 3;
if( info.IsAir[id] ) return 4;
if( info.IsTransparent[id] )
return info.CullWithNeighbours[id] ? 1 : 2;
return 0;
}
}
}