Partial support for saving and loading maps.

This commit is contained in:
UnknownShadow200 2015-09-01 19:58:21 +10:00
parent 7826f84b55
commit c8c8b8072d
4 changed files with 191 additions and 0 deletions

View File

@ -115,6 +115,7 @@
<Compile Include="Map\ChunkMeshBuilder.cs" /> <Compile Include="Map\ChunkMeshBuilder.cs" />
<Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" /> <Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" />
<Compile Include="Map\Map.cs" /> <Compile Include="Map\Map.cs" />
<Compile Include="Map\MapFcm3.cs" />
<Compile Include="Model\BlockModel.cs" /> <Compile Include="Model\BlockModel.cs" />
<Compile Include="Model\ChickenModel.cs" /> <Compile Include="Model\ChickenModel.cs" />
<Compile Include="Model\CreeperModel.cs" /> <Compile Include="Model\CreeperModel.cs" />

View File

@ -0,0 +1,134 @@
// Part of fCraft | Copyright (c) 2009-2014 Matvei Stefarov <me@matvei.org> | BSD-3 | See LICENSE.txt
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
namespace ClassicalSharp {
public sealed class MapFcm3 {
const uint Identifier = 0x0FC2AF40;
const byte Revision = 13;
public static byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) {
BinaryReader reader = new BinaryReader( stream );
if( reader.ReadInt32() != Identifier || reader.ReadByte() != Revision ) {
throw new InvalidDataException( "Unexpected constant in .fcm file" );
}
width = reader.ReadInt16();
height = reader.ReadInt16();
length = reader.ReadInt16();
int posX = reader.ReadInt32();
int posY = reader.ReadInt32();
int posZ = reader.ReadInt32();
byte yaw = reader.ReadByte();
byte pitch = reader.ReadByte();
reader.ReadUInt32(); // date modified
reader.ReadUInt32(); // date created
reader.ReadBytes( 16 ); // guid
reader.ReadBytes( 26 ); // layer index
int metaSize = reader.ReadInt32();
using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Decompress ) ) {
reader = new BinaryReader( ds );
for( int i = 0; i < metaSize; i++ ) {
string group = ReadString( reader );
string key = ReadString( reader );
string value = ReadString( reader );
Console.WriteLine( group + "," + key + "," + value );
}
byte[] blocks = new byte[width * height * length];
int read = ds.Read( blocks, 0, blocks.Length );
return blocks;
}
}
public static void Save( Stream stream, Game game ) {
BinaryWriter writer = new BinaryWriter( stream );
LocalPlayer p = game.LocalPlayer;
Map map = game.Map;
writer.Write( Identifier );
writer.Write( Revision );
writer.Write( (short)map.Width );
writer.Write( (short)map.Height );
writer.Write( (short)map.Length );
writer.Write( (int)( p.SpawnPoint.X * 32 ) );
writer.Write( (int)( p.SpawnPoint.Y * 32 ) );
writer.Write( (int)( p.SpawnPoint.Z * 32 ) );
writer.Write( (byte)0 ); // spawn R
writer.Write( (byte)0 ); // spawn L
writer.Write( (uint)0 ); // date modified
writer.Write( (uint)0 ); // date created
writer.Write( new byte[16] ); // map guid
writer.Write( (byte)1 ); // layer count
long indexOffset = stream.Position;
writer.Seek( 25, SeekOrigin.Current );
writer.Write( 9 ); // meta count
int compressedLength;
long offset;
using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Compress, true ) ) {
WriteMetadata( ds, game );
offset = stream.Position;
ds.Write( map.mapData, 0, map.mapData.Length );
compressedLength = (int)( stream.Position - offset );
}
writer.BaseStream.Seek( indexOffset, SeekOrigin.Begin );
writer.Write( (byte)0 );
writer.Write( offset );
writer.Write( compressedLength );
writer.Write( 0 );
writer.Write( 1 );
writer.Write( map.mapData.Length );
}
static void WriteMetadata( Stream stream, Game game ) {
BinaryWriter writer = new BinaryWriter( stream );
LocalPlayer p = game.LocalPlayer;
Map map = game.Map;
WriteMetadataEntry( writer, "SkyCol", map.SkyCol.ToArgb() );
WriteMetadataEntry( writer, "CloudsCol", map.CloudsCol.ToArgb() );
WriteMetadataEntry( writer, "FogCol", map.FogCol.ToArgb() );
WriteMetadataEntry( writer, "ClickDist", (int)( p.ReachDistance * 32 ) );
WriteMetadataEntry( writer, "SunLight", map.Sunlight.ToArgb() );
WriteMetadataEntry( writer, "ShadowLight", map.Shadowlight.ToArgb() );
WriteMetadataEntry( writer, "Weather", (int)map.Weather );
WriteMetadataEntry( writer, "SidesBlock", (int)map.SidesBlock );
WriteMetadataEntry( writer, "EdgeBlock", (int)map.EdgeBlock );
}
static string ReadString( BinaryReader reader ) {
int length = reader.ReadUInt16();
byte[] data = reader.ReadBytes( length );
return Encoding.ASCII.GetString( data );
}
static void WriteString( BinaryWriter writer, string str ) {
byte[] data = Encoding.ASCII.GetBytes( str );
writer.Write( (ushort)data.Length );
writer.Write( data );
}
static void WriteMetadataEntry( BinaryWriter writer, string key, int value ) {
WriteString( writer, "CS_Client" );
WriteString( writer, key );
WriteString( writer, value.ToString() );
}
}
}

View File

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using ClassicalSharp.Commands; using ClassicalSharp.Commands;
namespace ClassicalSharp.Singleplayer { namespace ClassicalSharp.Singleplayer {
@ -40,4 +41,57 @@ namespace ClassicalSharp.Singleplayer {
} }
} }
} }
public sealed class LoadMapCommand : Command {
public LoadMapCommand() {
Name = "LoadMap";
Help = new [] {
"&a/client loadmap [filename]",
"&bfilename: &eLoads a fcm map from the specified filename.",
};
}
public override void Execute( CommandReader reader ) {
string path = reader.NextAll();
if( String.IsNullOrEmpty( path ) ) return;
path = Path.GetFileName( path );
try {
using( FileStream fs = File.OpenRead( path ) ) {
int width, height, length;
game.Map.Reset();
game.RaiseOnNewMap();
game.SelectionManager.Dispose();
byte[] blocks = MapFcm3.Load( fs, game, out width, out height, out length );
game.Map.UseRawMap( blocks, width, height, length );
game.RaiseOnNewMapLoaded();
}
} catch( FileNotFoundException ) {
game.AddChat( "&e/client load: Couldn't find file \"" + path + "\"" );
}
}
}
public sealed class SaveMapCommand : Command {
public SaveMapCommand() {
Name = "SaveMap";
Help = new [] {
"&a/client savemap [filename]",
"&bfilename: &eSpecifies name of the file to save the map as.",
};
}
public override void Execute( CommandReader reader ) {
string path = reader.NextAll();
if( String.IsNullOrEmpty( path ) ) return;
path = Path.GetFileName( path );
using( FileStream fs = File.Create( path ) ) {
MapFcm3.Save( fs, game );
}
}
}
} }

View File

@ -25,6 +25,8 @@ namespace ClassicalSharp.Singleplayer {
NewMap(); NewMap();
MakeMap( 128, 128, 128 ); MakeMap( 128, 128, 128 );
game.CommandManager.RegisterCommand( new GenerateCommand() ); game.CommandManager.RegisterCommand( new GenerateCommand() );
game.CommandManager.RegisterCommand( new SaveMapCommand() );
game.CommandManager.RegisterCommand( new LoadMapCommand() );
} }
public override void SendChat( string text ) { public override void SendChat( string text ) {