mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-12 17:17:09 -04:00
Partial support for saving and loading maps.
This commit is contained in:
parent
7826f84b55
commit
c8c8b8072d
@ -115,6 +115,7 @@
|
||||
<Compile Include="Map\ChunkMeshBuilder.cs" />
|
||||
<Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" />
|
||||
<Compile Include="Map\Map.cs" />
|
||||
<Compile Include="Map\MapFcm3.cs" />
|
||||
<Compile Include="Model\BlockModel.cs" />
|
||||
<Compile Include="Model\ChickenModel.cs" />
|
||||
<Compile Include="Model\CreeperModel.cs" />
|
||||
|
134
ClassicalSharp/Map/MapFcm3.cs
Normal file
134
ClassicalSharp/Map/MapFcm3.cs
Normal 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() );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using ClassicalSharp.Commands;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ namespace ClassicalSharp.Singleplayer {
|
||||
NewMap();
|
||||
MakeMap( 128, 128, 128 );
|
||||
game.CommandManager.RegisterCommand( new GenerateCommand() );
|
||||
game.CommandManager.RegisterCommand( new SaveMapCommand() );
|
||||
game.CommandManager.RegisterCommand( new LoadMapCommand() );
|
||||
}
|
||||
|
||||
public override void SendChat( string text ) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user