diff --git a/ClassicalSharp.sln b/ClassicalSharp.sln
index f812403c2..06c6fef8c 100644
--- a/ClassicalSharp.sln
+++ b/ClassicalSharp.sln
@@ -1,6 +1,6 @@
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
# SharpDevelop 4.4
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassicalSharp", "ClassicalSharp\ClassicalSharp.csproj", "{BEB1C785-5CAD-48FF-A886-876BF0A318D4}"
EndProject
diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index 6c3af61e6..46e712c18 100644
--- a/ClassicalSharp/ClassicalSharp.csproj
+++ b/ClassicalSharp/ClassicalSharp.csproj
@@ -162,7 +162,8 @@
-
+
+
diff --git a/ClassicalSharp/Commands/DefaultCommands.cs b/ClassicalSharp/Commands/DefaultCommands.cs
index 9660b954f..b8914a950 100644
--- a/ClassicalSharp/Commands/DefaultCommands.cs
+++ b/ClassicalSharp/Commands/DefaultCommands.cs
@@ -306,10 +306,8 @@ namespace ClassicalSharp.Commands {
if( String.IsNullOrEmpty( path ) ) return;
try {
- using( FileStream fs = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read ) ) {
- ZipExtractor extractor = new ZipExtractor( game );
- extractor.Extract( fs );
- }
+ TexturePackExtractor extractor = new TexturePackExtractor();
+ extractor.Extract( path, game );
} catch( FileNotFoundException ) {
game.AddChat( "&e/client texturepack: Couldn't find file \"" + path + "\"" );
}
diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs
index 4ba2dd38e..d228878e3 100644
--- a/ClassicalSharp/Game/Game.cs
+++ b/ClassicalSharp/Game/Game.cs
@@ -45,7 +45,7 @@ namespace ClassicalSharp {
public PickingRenderer Picking;
public PickedPos SelectedPos = new PickedPos();
public ModelCache ModelCache;
- internal string skinServer, chatInInputBuffer;
+ internal string skinServer, chatInInputBuffer, defaultTexPack;
internal int defaultIb;
public bool CanUseThirdPersonCamera = true;
FpsScreen fpsScreen;
@@ -102,6 +102,7 @@ namespace ClassicalSharp {
public int MouseSensitivity = 30;
public bool HideGui = false;
public Animations Animations;
+ internal int CloudsTextureId, RainTextureId, SnowTextureId;
void LoadAtlas( Bitmap bmp ) {
TerrainAtlas1D.Dispose();
@@ -115,7 +116,11 @@ namespace ClassicalSharp {
Raise( TerrainAtlasChanged );
}
- public Game() : base() {
+ public Game( string username, string mppass, string skinServer, string defaultTexPack ) : base() {
+ Username = username;
+ Mppass = mppass;
+ this.skinServer = skinServer;
+ this.defaultTexPack = defaultTexPack;
// We can't use enum array initaliser because this causes problems when building with mono
// and running on default .NET (https://bugzilla.xamarin.com/show_bug.cgi?id=572)
#if !__MonoCS__
@@ -142,10 +147,11 @@ namespace ClassicalSharp {
ModelCache.InitCache();
AsyncDownloader = new AsyncDownloader( skinServer );
Graphics.PrintGraphicsInfo();
- Bitmap terrainBmp = new Bitmap( "terrain.png" );
TerrainAtlas1D = new TerrainAtlas1D( Graphics );
TerrainAtlas = new TerrainAtlas2D( Graphics );
- LoadAtlas( terrainBmp );
+ TexturePackExtractor extractor = new TexturePackExtractor();
+ extractor.Extract( defaultTexPack, this );
+
BlockInfo = new BlockInfo();
BlockInfo.Init();
BlockInfo.SetDefaultBlockPermissions( CanPlace, CanDelete );
@@ -311,6 +317,10 @@ namespace ClassicalSharp {
Graphics.DeleteIb( defaultIb );
Graphics.Dispose();
Utils2D.Dispose();
+ Animations.Dispose();
+ Graphics.DeleteTexture( ref CloudsTextureId );
+ Graphics.DeleteTexture( ref RainTextureId );
+ Graphics.DeleteTexture( ref SnowTextureId );
base.Dispose();
}
diff --git a/ClassicalSharp/Model/ChickenModel.cs b/ClassicalSharp/Model/ChickenModel.cs
index b5e79b1ce..90b85e790 100644
--- a/ClassicalSharp/Model/ChickenModel.cs
+++ b/ClassicalSharp/Model/ChickenModel.cs
@@ -16,9 +16,6 @@ namespace ClassicalSharp.Model {
RightLeg = MakeLeg( 0f, 0.1875f, 0.0625f, 0.125f );
LeftWing = MakeWing( -0.25f, -0.1875f );
RightWing = MakeWing( 0.1875f, 0.25f );
-
- if( cache.ChickenTexId <= 0 )
- cache.ChickenTexId = graphics.CreateTexture( "chicken.png" );
}
ModelPart MakeHead() {
diff --git a/ClassicalSharp/Model/CreeperModel.cs b/ClassicalSharp/Model/CreeperModel.cs
index 277fca294..7a22c5987 100644
--- a/ClassicalSharp/Model/CreeperModel.cs
+++ b/ClassicalSharp/Model/CreeperModel.cs
@@ -14,9 +14,6 @@ namespace ClassicalSharp.Model {
RightLegFront = MakeLeg( 0, 0.25f, -0.375f, -0.125f );
LeftLegBack = MakeLeg( -0.25f, 0, 0.125f, 0.375f );
RightLegBack = MakeLeg( 0, 0.25f, 0.125f, 0.375f );
-
- if( cache.CreeperTexId <= 0 )
- cache.CreeperTexId = graphics.CreateTexture( "creeper.png" );
}
ModelPart MakeHead() {
diff --git a/ClassicalSharp/Model/PigModel.cs b/ClassicalSharp/Model/PigModel.cs
index de7aff27d..5cf377392 100644
--- a/ClassicalSharp/Model/PigModel.cs
+++ b/ClassicalSharp/Model/PigModel.cs
@@ -14,9 +14,6 @@ namespace ClassicalSharp.Model {
RightLegFront = MakeLeg( 0.0625f, 0.3125f, -0.4375f, -0.1875f );
LeftLegBack = MakeLeg( -0.3125f, -0.0625f, 0.3125f, 0.5625f );
RightLegBack = MakeLeg( 0.0625f, 0.3125f, 0.3125f, 0.5625f );
-
- if( cache.PigTexId <= 0 )
- cache.PigTexId = graphics.CreateTexture( "pig.png" );
}
ModelPart MakeHead() {
diff --git a/ClassicalSharp/Model/PlayerModel.cs b/ClassicalSharp/Model/PlayerModel.cs
index 1026e3c46..283dcb45b 100644
--- a/ClassicalSharp/Model/PlayerModel.cs
+++ b/ClassicalSharp/Model/PlayerModel.cs
@@ -36,11 +36,6 @@ namespace ClassicalSharp.Model {
Set64x64Slim.LeftArm = MakeLeftArm( 32, 48, 0.25f, 0.4375f, 3, true );
Set64x64Slim.RightArm = MakeRightArm( 40, 16, 0.25f, 0.4375f, 3, true );
Set64x64Slim.Hat = Set64x64.Hat;
-
- using( Bitmap bmp = new Bitmap( "char.png" ) ) {
- window.DefaultPlayerSkinType = Utils.GetSkinType( bmp );
- cache.HumanoidTexId = graphics.CreateTexture( bmp );
- }
}
ModelPart MakeLeftArm( int x, int y, float x1, float x2, int width, bool _64x64 ) {
diff --git a/ClassicalSharp/Model/SheepModel.cs b/ClassicalSharp/Model/SheepModel.cs
index 6634f0dfa..1a39a05d0 100644
--- a/ClassicalSharp/Model/SheepModel.cs
+++ b/ClassicalSharp/Model/SheepModel.cs
@@ -25,11 +25,6 @@ namespace ClassicalSharp.Model {
FurLeftLegBack = MakeFurLeg( -0.34375f, -0.03125f, 0.28125f, 0.59375f );
FurRightLegBack = MakeFurLeg( 0.03125f, 0.34375f, 0.28125f, 0.59375f );
}
-
- if( cache.SheepTexId <= 0 )
- cache.SheepTexId = graphics.CreateTexture( "sheep.png" );
- if( cache.SheepFurTexId <= 0 )
- cache.SheepFurTexId = graphics.CreateTexture( "sheep_fur.png" );
}
ModelPart MakeHead() {
diff --git a/ClassicalSharp/Model/SkeletonModel.cs b/ClassicalSharp/Model/SkeletonModel.cs
index d6a29463d..ce0fccdd7 100644
--- a/ClassicalSharp/Model/SkeletonModel.cs
+++ b/ClassicalSharp/Model/SkeletonModel.cs
@@ -13,9 +13,6 @@ namespace ClassicalSharp.Model {
RightLeg = MakeRightLeg( 0.0625f, 0.1875f );
LeftArm = MakeLeftArm( 0.375f, 0.25f );
RightArm = MakeRightArm( 0.25f, 0.375f );
-
- if( cache.SkeletonTexId <= 0 )
- cache.SkeletonTexId = graphics.CreateTexture( "skeleton.png" );
}
ModelPart MakeLeftArm( float x1, float x2 ) {
diff --git a/ClassicalSharp/Model/SpiderModel.cs b/ClassicalSharp/Model/SpiderModel.cs
index 020c73966..df6a54a97 100644
--- a/ClassicalSharp/Model/SpiderModel.cs
+++ b/ClassicalSharp/Model/SpiderModel.cs
@@ -12,9 +12,6 @@ namespace ClassicalSharp.Model {
End = MakeEnd();
LeftLeg = MakeLeg( -1.1875f, -0.1875f );
RightLeg = MakeLeg( 0.1875f, 1.1875f );
-
- if( cache.SpiderTexId <= 0 )
- cache.SpiderTexId = graphics.CreateTexture( "spider.png" );
}
ModelPart MakeHead() {
diff --git a/ClassicalSharp/Model/ZombieModel.cs b/ClassicalSharp/Model/ZombieModel.cs
index aa378c717..6cfc174d3 100644
--- a/ClassicalSharp/Model/ZombieModel.cs
+++ b/ClassicalSharp/Model/ZombieModel.cs
@@ -14,9 +14,6 @@ namespace ClassicalSharp.Model {
RightLeg = MakeRightLeg( 0, 0.25f );
LeftArm = MakeLeftArm( 0.5f, 0.25f );
RightArm = MakeRightArm( 0.25f, 0.5f );
-
- if( cache.ZombieTexId <= 0 )
- cache.ZombieTexId = graphics.CreateTexture( "zombie.png" );
}
ModelPart MakeLeftArm( float x1, float x2 ) {
diff --git a/ClassicalSharp/Program.cs b/ClassicalSharp/Program.cs
index 38ac9d72e..acb050f17 100644
--- a/ClassicalSharp/Program.cs
+++ b/ClassicalSharp/Program.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.IO;
using System.Net;
using System.Windows.Forms;
+using ClassicalSharp.TexturePack;
namespace ClassicalSharp {
@@ -15,14 +16,15 @@ namespace ClassicalSharp {
}
Utils.Log( "Starting " + Utils.AppName + ".." );
- if( !AllResourcesExist( "terrain.png", "char.png", "clouds.png" ) ) {
+ if( !File.Exists( "default.zip" ) ) {
+ Fail( "default.zip not found. Cannot start." );
return;
}
- if( args.Length == 0 ) {
+
+ if( args.Length == 0 || args.Length == 1 ) {
Utils.Log( "Starting singleplayer mode." );
- using( Game game = new Game() ) {
- game.Username = "LocalPlayer";
- game.skinServer = "http://s3.amazonaws.com/MinecraftSkins/";
+ const string skinServer = "http://s3.amazonaws.com/MinecraftSkins/";
+ using( Game game = new Game( "LocalPlayer", null, skinServer, "default.zip" ) ) {
game.Run();
}
} else if( args.Length < 4 ) {
@@ -48,26 +50,13 @@ namespace ClassicalSharp {
}
string skinServer = args.Length >= 5 ? args[4] : "http://s3.amazonaws.com/MinecraftSkins/";
- using( Game game = new Game() ) {
- game.Username = args[0];
- game.Mppass = args[1];
+ using( Game game = new Game( args[0], args[1], skinServer, "default.zip" ) ) {
game.IPAddress = ip;
game.Port = port;
- game.skinServer = skinServer;
game.Run();
}
}
- static bool AllResourcesExist( params string[] resources ) {
- foreach( string resource in resources ) {
- if( !File.Exists( resource ) ) {
- Fail( resource + " not found. Cannot start." );
- return false;
- }
- }
- return true;
- }
-
static void Fail( string text ) {
Utils.LogWarning( text );
Utils.Log( "Press any key to exit.." );
diff --git a/ClassicalSharp/Rendering/StandardEnvRenderer.cs b/ClassicalSharp/Rendering/StandardEnvRenderer.cs
index 71e81c10b..fdcd78fa8 100644
--- a/ClassicalSharp/Rendering/StandardEnvRenderer.cs
+++ b/ClassicalSharp/Rendering/StandardEnvRenderer.cs
@@ -12,7 +12,7 @@ namespace ClassicalSharp.Renderers {
map = game.Map;
}
- int cloudTexture = -1, cloudsVb = -1, cloudsIndices;
+ int cloudsVb = -1, cloudsIndices;
int skyOffset = 10, skyVb = -1, skyIndices;
public float CloudsSpeed = 1;
bool legacy;
@@ -69,7 +69,6 @@ namespace ClassicalSharp.Renderers {
base.Init();
graphics.Fog = true;
ResetAllEnv( null, null );
- cloudTexture = graphics.CreateTexture( "clouds.png" );
game.ViewDistanceChanged += ResetAllEnv;
}
@@ -84,7 +83,6 @@ namespace ClassicalSharp.Renderers {
game.ViewDistanceChanged -= ResetAllEnv;
graphics.DeleteVb( skyVb );
graphics.DeleteVb( cloudsVb );
- graphics.DeleteTexture( ref cloudTexture );
}
void RenderClouds( double delta ) {
@@ -97,7 +95,7 @@ namespace ClassicalSharp.Renderers {
graphics.AlphaTest = true;
graphics.Texturing = true;
- graphics.BindTexture( cloudTexture );
+ graphics.BindTexture( game.CloudsTextureId );
graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );
graphics.BindVb( cloudsVb );
graphics.DrawIndexedVb_TrisT2fC4b( cloudsIndices, 0 );
diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs
index da72ba29b..dbf433622 100644
--- a/ClassicalSharp/Rendering/WeatherRenderer.cs
+++ b/ClassicalSharp/Rendering/WeatherRenderer.cs
@@ -19,7 +19,6 @@ namespace ClassicalSharp {
}
int weatherVb;
- int rainTexture, snowTexture;
short[] heightmap;
float vOffset;
VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[8 * 9 * 9];
@@ -28,7 +27,7 @@ namespace ClassicalSharp {
if( weather == Weather.Sunny ) return;
graphics.Texturing = true;
- graphics.BindTexture( weather == Weather.Rainy ? rainTexture : snowTexture );
+ graphics.BindTexture( weather == Weather.Rainy ? game.RainTextureId : game.SnowTextureId );
Vector3I pos = Vector3I.Floor( game.LocalPlayer.Position );
float speed = weather == Weather.Rainy ? 1f : 0.25f;
vOffset = -(float)game.accumulator * speed;
@@ -90,8 +89,6 @@ namespace ClassicalSharp {
}
public void Init() {
- rainTexture = graphics.CreateTexture( "rain.png" );
- snowTexture = graphics.CreateTexture( "snow.png" );
game.OnNewMap += OnNewMap;
game.OnNewMapLoaded += OnNewMapLoaded;
}
@@ -99,8 +96,6 @@ namespace ClassicalSharp {
public void Dispose() {
game.OnNewMap -= OnNewMap;
game.OnNewMapLoaded -= OnNewMapLoaded;
- graphics.DeleteTexture( ref rainTexture );
- graphics.DeleteTexture( ref snowTexture );
}
int GetRainHeight( int x, int z ) {
diff --git a/ClassicalSharp/TexturePack/TexturePackExtractor.cs b/ClassicalSharp/TexturePack/TexturePackExtractor.cs
new file mode 100644
index 000000000..1e447b8eb
--- /dev/null
+++ b/ClassicalSharp/TexturePack/TexturePackExtractor.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Drawing;
+using System.IO;
+using ClassicalSharp.GraphicsAPI;
+using ClassicalSharp.Model;
+
+namespace ClassicalSharp.TexturePack {
+
+ public sealed class TexturePackExtractor {
+
+ Game game;
+ public void Extract( string path, Game game ) {
+ this.game = game;
+ using( FileStream fs = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read ) ) {
+ ZipReader reader = new ZipReader();
+ reader.ShouldProcessZipEntry = ShouldProcessZipEntry;
+ reader.ProcessZipEntry = ProcessZipEntry;
+ reader.Extract( fs );
+ }
+ }
+
+ bool ShouldProcessZipEntry( string filename ) {
+ return true;
+ }
+
+ void ProcessZipEntry( string filename, byte[] data, ZipEntry entry ) {
+ MemoryStream stream = new MemoryStream( data );
+ ModelCache cache = game.ModelCache;
+ IGraphicsApi api = game.Graphics;
+
+ switch( filename ) {
+ case "terrain.png":
+ game.ChangeTerrainAtlas( new Bitmap( stream ) ); break;
+ case "mob/chicken.png":
+ case "chicken.png":
+ UpdateTexture( ref cache.ChickenTexId, stream, false ); break;
+ case "mob/creeper.png":
+ case "creeper.png":
+ UpdateTexture( ref cache.CreeperTexId, stream, false ); break;
+ case "mob/pig.png":
+ case "pig.png":
+ UpdateTexture( ref cache.PigTexId, stream, false ); break;
+ case "mob/sheep.png":
+ case "sheep.png":
+ UpdateTexture( ref cache.SheepTexId, stream, false ); break;
+ case "mob/skeleton.png":
+ case "skeleton.png":
+ UpdateTexture( ref cache.SkeletonTexId, stream, false ); break;
+ case "mob/spider.png":
+ case "spider.png":
+ UpdateTexture( ref cache.SpiderTexId, stream, false ); break;
+ case "mob/zombie.png":
+ case "zombie.png":
+ UpdateTexture( ref cache.ZombieTexId, stream, false ); break;
+ case "mob/sheep_fur.png":
+ case "sheep_fur.png":
+ UpdateTexture( ref cache.SheepFurTexId, stream, false ); break;
+ case "char.png":
+ UpdateTexture( ref cache.HumanoidTexId, stream, true ); break;
+ case "animations.png":
+ case "animation.png":
+ game.Animations.SetAtlas( new Bitmap( stream ) ); break;
+ case "clouds.png":
+ case "cloud.png":
+ UpdateTexture( ref game.CloudsTextureId, stream, false ); break;
+ case "rain.png":
+ UpdateTexture( ref game.RainTextureId, stream, false ); break;
+ case "snow.png":
+ UpdateTexture( ref game.SnowTextureId, stream, false ); break;
+ }
+ }
+
+ void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) {
+ game.Graphics.DeleteTexture( ref texId );
+ using( Bitmap bmp = new Bitmap( stream ) ) {
+ if( setSkinType )
+ game.DefaultPlayerSkinType = Utils.GetSkinType( bmp );
+ texId = game.Graphics.CreateTexture( bmp );
+ }
+ }
+ }
+}
diff --git a/ClassicalSharp/TexturePack/ZipExtractor.cs b/ClassicalSharp/TexturePack/ZipReader.cs
similarity index 61%
rename from ClassicalSharp/TexturePack/ZipExtractor.cs
rename to ClassicalSharp/TexturePack/ZipReader.cs
index 5e3669c88..b1babd39d 100644
--- a/ClassicalSharp/TexturePack/ZipExtractor.cs
+++ b/ClassicalSharp/TexturePack/ZipReader.cs
@@ -1,19 +1,23 @@
using System;
-using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Text;
-using ClassicalSharp.GraphicsAPI;
-using ClassicalSharp.Model;
namespace ClassicalSharp.TexturePack {
- public sealed class ZipExtractor {
+ public struct ZipEntry {
+ public int CompressedDataSize, UncompressedDataSize;
+ public int LocalHeaderOffset, CentralHeaderOffset;
+ public uint Crc32;
+ public string Filename;
+ }
+
+ public sealed class ZipReader {
- Game game;
- public ZipExtractor( Game game ) {
- this.game = game;
- }
+ public Action ProcessZipEntry;
+ public Func ShouldProcessZipEntry;
+ public ZipEntry[] entries;
+ public int index;
static Encoding enc = Encoding.ASCII;
public void Extract( Stream stream ) {
@@ -27,7 +31,7 @@ namespace ClassicalSharp.TexturePack {
}
int entriesCount, centralDirectoryOffset;
ReadEndOfCentralDirectory( reader, out entriesCount, out centralDirectoryOffset );
- ZipData[] entries = new ZipData[entriesCount];
+ entries = new ZipEntry[entriesCount];
reader.BaseStream.Seek( centralDirectoryOffset, SeekOrigin.Begin );
// Read all the central directory entries
@@ -44,21 +48,18 @@ namespace ClassicalSharp.TexturePack {
// Now read the local file header entries
for( int i = 0; i < entriesCount; i++ ) {
- ZipData entry = entries[i];
+ index = i;
+ ZipEntry entry = entries[i];
reader.BaseStream.Seek( entry.LocalHeaderOffset, SeekOrigin.Begin );
sig = reader.ReadUInt32();
if( sig != 0x04034b50 )
throw new NotSupportedException( "Unsupported signature: " + sig.ToString( "X8" ) );
ReadLocalFileHeader( reader, entry );
}
+ entries = null;
}
- struct ZipData {
- public int CompressedSize, UncompressedSize;
- public int LocalHeaderOffset;
- }
-
- void ReadLocalFileHeader( BinaryReader reader, ZipData entry ) {
+ void ReadLocalFileHeader( BinaryReader reader, ZipEntry entry ) {
ushort versionNeeded = reader.ReadUInt16();
ushort flags = reader.ReadUInt16();
ushort compressionMethod = reader.ReadUInt16();
@@ -66,30 +67,32 @@ namespace ClassicalSharp.TexturePack {
reader.ReadUInt32(); // CRC 32
int compressedSize = reader.ReadInt32();
- if( compressedSize == 0 ) compressedSize = entry.CompressedSize;
+ if( compressedSize == 0 ) compressedSize = entry.CompressedDataSize;
int uncompressedSize = reader.ReadInt32();
- if( uncompressedSize == 0 ) uncompressedSize = entry.UncompressedSize;
+ if( uncompressedSize == 0 ) uncompressedSize = entry.UncompressedDataSize;
ushort fileNameLen = reader.ReadUInt16();
ushort extraFieldLen = reader.ReadUInt16();
string fileName = enc.GetString( reader.ReadBytes( fileNameLen ) );
- reader.ReadBytes( extraFieldLen );
+ if( !ShouldProcessZipEntry( fileName ) ) return;
+ reader.ReadBytes( extraFieldLen );
if( versionNeeded > 20 )
Utils.LogWarning( "May not be able to properly extract a .zip enty with a version later than 2.0" );
byte[] data = DecompressEntry( reader, compressionMethod, compressedSize, uncompressedSize );
if( data != null )
- HandleZipEntry( fileName, data );
+ ProcessZipEntry( fileName, data, entry );
}
- int index;
- void ReadCentralDirectory( BinaryReader reader, ZipData[] entries ) {
+ void ReadCentralDirectory( BinaryReader reader, ZipEntry[] entries ) {
+ ZipEntry entry;
+ entry.CentralHeaderOffset = (int)( reader.BaseStream.Position - 4 );
reader.ReadUInt16(); // OS
ushort versionNeeded = reader.ReadUInt16();
ushort flags = reader.ReadUInt16();
ushort compressionMethod = reader.ReadUInt16();
reader.ReadUInt32(); // last modified
- reader.ReadUInt32(); // CRC 32
+ uint crc32 = reader.ReadUInt32();
int compressedSize = reader.ReadInt32();
int uncompressedSize = reader.ReadInt32();
ushort fileNameLen = reader.ReadUInt16();
@@ -103,11 +106,12 @@ namespace ClassicalSharp.TexturePack {
string fileName = enc.GetString( reader.ReadBytes( fileNameLen ) );
reader.ReadBytes( extraFieldLen );
reader.ReadBytes( fileCommentLen );
-
- ZipData entry;
- entry.CompressedSize = compressedSize;
- entry.UncompressedSize = uncompressedSize;
+
+ entry.CompressedDataSize = compressedSize;
+ entry.UncompressedDataSize = uncompressedSize;
entry.LocalHeaderOffset = localHeaderOffset;
+ entry.Filename = fileName;
+ entry.Crc32 = crc32;
entries[index++] = entry;
}
@@ -144,54 +148,5 @@ namespace ClassicalSharp.TexturePack {
return null;
}
}
-
- void HandleZipEntry( string filename, byte[] data ) {
- MemoryStream stream = new MemoryStream( data );
- ModelCache cache = game.ModelCache;
- IGraphicsApi api = game.Graphics;
-
- switch( filename ) {
- case "terrain.png":
- game.ChangeTerrainAtlas( new Bitmap( stream ) ); break;
- case "mob/chicken.png":
- case "chicken.png":
- UpdateTexture( ref cache.ChickenTexId, stream, false ); break;
- case "mob/creeper.png":
- case "creeper.png":
- UpdateTexture( ref cache.CreeperTexId, stream, false ); break;
- case "mob/pig.png":
- case "pig.png":
- UpdateTexture( ref cache.PigTexId, stream, false ); break;
- case "mob/sheep.png":
- case "sheep.png":
- UpdateTexture( ref cache.SheepTexId, stream, false ); break;
- case "mob/skeleton.png":
- case "skeleton.png":
- UpdateTexture( ref cache.SkeletonTexId, stream, false ); break;
- case "mob/spider.png":
- case "spider.png":
- UpdateTexture( ref cache.SpiderTexId, stream, false ); break;
- case "mob/zombie.png":
- case "zombie.png":
- UpdateTexture( ref cache.ZombieTexId, stream, false ); break;
- case "mob/sheep_fur.png":
- case "sheep_fur.png":
- UpdateTexture( ref cache.SheepFurTexId, stream, false ); break;
- case "char.png":
- UpdateTexture( ref cache.HumanoidTexId, stream, true ); break;
- case "animations.png":
- case "animation.png":
- game.Animations.SetAtlas( new Bitmap( stream ) ); break;
- }
- }
-
- void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) {
- game.Graphics.DeleteTexture( ref texId );
- using( Bitmap bmp = new Bitmap( stream ) ) {
- if( setSkinType )
- game.DefaultPlayerSkinType = Utils.GetSkinType( bmp );
- texId = game.Graphics.CreateTexture( bmp );
- }
- }
}
}
diff --git a/ClassicalSharp/Utils/FastBitmap.cs b/ClassicalSharp/Utils/FastBitmap.cs
index b249684d5..d3c771af2 100644
--- a/ClassicalSharp/Utils/FastBitmap.cs
+++ b/ClassicalSharp/Utils/FastBitmap.cs
@@ -71,7 +71,7 @@ namespace ClassicalSharp {
return (int*)( scan0Byte + ( y * Stride ) );
}
- internal static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
+ public static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
for( int y = 0; y < size; y++ ) {
int* srcRow = src.GetRowPtr( srcY + y );
int* dstRow = dst.GetRowPtr( dstY + y );
diff --git a/ClassicalSharp/Utils/Utils.cs b/ClassicalSharp/Utils/Utils.cs
index fa30efbc1..477c1baa8 100644
--- a/ClassicalSharp/Utils/Utils.cs
+++ b/ClassicalSharp/Utils/Utils.cs
@@ -14,6 +14,7 @@ namespace ClassicalSharp {
public delegate TResult Func();
public delegate TResult Func( T1 arg1 );
public delegate TResult Func( T1 arg1, T2 arg2 );
+ public delegate TResult Func( T1 arg1, T2 arg2, T3 arg3 );
public delegate bool TryParseFunc( string s, out T value );
// ################################################################
diff --git a/Launcher/Launcher.csproj b/Launcher/Launcher.csproj
index a19d0fbad..395e9449c 100644
--- a/Launcher/Launcher.csproj
+++ b/Launcher/Launcher.csproj
@@ -33,7 +33,7 @@
true
False
False
- False
+ True
False
4
False
@@ -55,6 +55,7 @@
True
DEBUG;TRACE
obj\
+ Project
..\output\release\
@@ -63,6 +64,8 @@
True
False
TRACE
+ obj\
+ Project
@@ -82,9 +85,10 @@
+
+
-
@@ -118,5 +122,14 @@
true
+
+
+ {BEB1C785-5CAD-48FF-A886-876BF0A318D4}
+ ClassicalSharp
+
+
+
+
+
\ No newline at end of file
diff --git a/Launcher/Patcher/ResourceFetcher.cs b/Launcher/Patcher/ResourceFetcher.cs
new file mode 100644
index 000000000..63ff2c5f1
--- /dev/null
+++ b/Launcher/Patcher/ResourceFetcher.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Drawing;
+using System.IO;
+using System.Net;
+using System.Windows.Forms;
+using ClassicalSharp;
+using ClassicalSharp.TexturePack;
+
+namespace Launcher {
+
+ public class ResourceFetcher {
+
+ const string classicJarUri = "http://s3.amazonaws.com/Minecraft.Download/versions/c0.30_01c/c0.30_01c.jar";
+ const string modernJarUri = "http://s3.amazonaws.com/Minecraft.Download/versions/1.6.2/1.6.2.jar";
+ const string terrainPatchUri = "http://static.classicube.net/terrain-patch.png";
+ static int resourcesCount = 2;
+
+ public void Run( MainForm form ) {
+ using( WebClient client = new GZipWebClient() ) {
+ WebRequest.DefaultWebProxy = null;
+ int i = 0;
+ DownloadData( classicJarUri, client, "classic.jar", form, ref i );
+ DownloadData( terrainPatchUri, client, "terrain-patch.png", form, ref i );
+ }
+
+ reader = new ZipReader();
+ reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Classic;
+ reader.ProcessZipEntry = ProcessZipEntry_Classic;
+ using( FileStream src = new FileStream( "classic.jar", FileMode.Open, FileAccess.Read, FileShare.Read ),
+ dst = new FileStream( "default.zip", FileMode.Create, FileAccess.Write ) ) {
+ writer = new ZipWriter( dst );
+ reader.Extract( src );
+ writer.WriteCentralDirectoryRecords();
+ }
+ File.Move( "terrain-patch.png", "terrain-patched.png" );
+ }
+ ZipReader reader;
+ ZipWriter writer;
+
+ bool ShouldProcessZipEntry_Classic( string filename ) {
+ return filename.StartsWith( "mob" ) || ( filename.IndexOf( '/' ) < 0 );
+ }
+
+ void ProcessZipEntry_Classic( string filename, byte[] data, ZipEntry entry ) {
+ if( writer.entries == null )
+ writer.entries = new ZipEntry[reader.entries.Length];
+ if( filename != "terrain.png" ) {
+ writer.WriteZipEntry( entry, data );
+ return;
+ }
+
+ using( Bitmap dstBitmap = new Bitmap( new MemoryStream( data ) ),
+ maskBitmap = new Bitmap( "terrain-patch.png" ) ) {
+ PatchImage( dstBitmap, maskBitmap );
+ writer.WriteTerrainImage( dstBitmap, entry );
+ }
+ }
+
+ unsafe void PatchImage( Bitmap dstBitmap, Bitmap maskBitmap ) {
+ using( FastBitmap dst = new FastBitmap( dstBitmap, true ),
+ src = new FastBitmap( maskBitmap, true ) ) {
+ int size = src.Width, tileSize = size / 16;
+
+ for( int y = 0; y < size; y += tileSize ) {
+ int* row = src.GetRowPtr( y );
+ for( int x = 0; x < size; x += tileSize ) {
+ if( row[x] != unchecked((int)0x80000000) ) {
+ FastBitmap.MovePortion( x, y, x, y, src, dst, tileSize );
+ }
+ }
+ }
+ }
+ }
+
+ public bool CheckAllResourcesExist() {
+ return File.Exists( "default.zip" ) && File.Exists( "terrain-patched.png" );
+ }
+
+ class GZipWebClient : WebClient {
+
+ protected override WebRequest GetWebRequest( Uri address ) {
+ HttpWebRequest request = (HttpWebRequest)base.GetWebRequest( address );
+ request.AutomaticDecompression = DecompressionMethods.GZip;
+ return request;
+ }
+ }
+
+ static bool DownloadData( string uri, WebClient client, string output, MainForm form, ref int i ) {
+ i++;
+ if( File.Exists( output ) ) return true;
+ form.Text = MainForm.AppName + " - fetching " + output + "(" + i + "/" + resourcesCount + ")";
+
+ try {
+ client.DownloadFile( uri, output );
+ } catch( WebException ex ) {
+ Program.LogException( ex );
+ MessageBox.Show( "Unable to download or save " + output, "Failed to download or save resource", MessageBoxButtons.OK, MessageBoxIcon.Error );
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/Launcher/Patcher/ZipWriter.cs b/Launcher/Patcher/ZipWriter.cs
new file mode 100644
index 000000000..b8008d768
--- /dev/null
+++ b/Launcher/Patcher/ZipWriter.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using ClassicalSharp.TexturePack;
+
+namespace Launcher {
+
+ public sealed class ZipWriter {
+
+ BinaryWriter writer;
+ Stream stream;
+ public ZipWriter( Stream stream ) {
+ this.stream = stream;
+ writer = new BinaryWriter( stream );
+ }
+
+ internal ZipEntry[] entries;
+ internal int entriesCount;
+
+ public void WriteZipEntry( ZipEntry entry, byte[] data ) {
+ entry.CompressedDataSize = (int)entry.UncompressedDataSize;
+ entry.LocalHeaderOffset = (int)stream.Position;
+ entries[entriesCount++] = entry;
+ WriteLocalFileHeader( entry, data, data.Length );
+ }
+
+ public void WriteTerrainImage( Bitmap bmp, ZipEntry entry ) {
+ MemoryStream data = new MemoryStream( entry.UncompressedDataSize );
+ bmp.Save( data, ImageFormat.Png );
+ byte[] buffer = data.GetBuffer();
+ entry.UncompressedDataSize = (int)data.Length;
+ entry.Crc32 = CRC32( buffer, entry.UncompressedDataSize );
+ entry.CompressedDataSize = entry.UncompressedDataSize;
+
+ entry.LocalHeaderOffset = (int)stream.Position;
+ entries[entriesCount++] = entry;
+ WriteLocalFileHeader( entry, buffer, entry.UncompressedDataSize );
+ }
+
+ public void WriteCentralDirectoryRecords() {
+ int dirOffset = (int)stream.Position;
+ for( int i = 0; i < entriesCount; i++ ) {
+ WriteCentralDirectoryHeaderEntry( entries[i] );
+ }
+ int dirSize = (int)( stream.Position - dirOffset );
+ WriteEndOfCentralDirectoryRecord( (ushort)entriesCount, dirSize, dirOffset );
+ }
+
+ void WriteLocalFileHeader( ZipEntry entry, byte[] data, int length ) {
+ writer.Write( 0x04034b50 ); // signature
+ writer.Write( (ushort)20 ); // version needed
+ writer.Write( (ushort)8 ); // bitflags
+ writer.Write( (ushort)0 ); // compression method
+ writer.Write( 0 ); // last modified
+ writer.Write( 0 ); // CRC32
+ writer.Write( 0 ); // compressed size
+ writer.Write( 0 ); // uncompressed size
+ writer.Write( (ushort)entry.Filename.Length );
+ writer.Write( (ushort)0 ); // extra field length
+ for( int i = 0; i < entry.Filename.Length; i++ )
+ writer.Write( (byte)entry.Filename[i] );
+
+ writer.Write( data, 0, length );
+ // Data descriptor
+ writer.Write( entry.Crc32 );
+ writer.Write( entry.CompressedDataSize );
+ writer.Write( entry.UncompressedDataSize );
+ }
+
+ void WriteCentralDirectoryHeaderEntry( ZipEntry entry ) {
+ writer.Write( 0x02014b50 ); // signature
+ writer.Write( (ushort)20 ); // version
+ writer.Write( (ushort)20 ); // version needed
+ writer.Write( (ushort)8 ); // bitflags
+ writer.Write( (ushort)0 ); // compression method
+ writer.Write( 0 ); // last modified
+ writer.Write( entry.Crc32 );
+ writer.Write( entry.CompressedDataSize );
+ writer.Write( entry.UncompressedDataSize );
+
+ writer.Write( (ushort)entry.Filename.Length );
+ writer.Write( (ushort)0 ); // extra field length
+ writer.Write( (ushort)0 ); // file comment length
+ writer.Write( (ushort)0 ); // disk number
+ writer.Write( (ushort)0 ); // internal attributes
+ writer.Write( 0 ); // external attributes
+ writer.Write( entry.LocalHeaderOffset );
+ for( int i = 0; i < entry.Filename.Length; i++ )
+ writer.Write( (byte)entry.Filename[i] );
+ }
+
+ void WriteEndOfCentralDirectoryRecord( ushort entries, int centralDirSize, int centralDirOffset ) {
+ writer.Write( 0x06054b50 ); // signature
+ writer.Write( (ushort)0 ); // disk number
+ writer.Write( (ushort)0 ); // disk number of start
+ writer.Write( entries ); // disk entries
+ writer.Write( entries ); // total entries
+ writer.Write( centralDirSize );
+ writer.Write( centralDirOffset );
+ writer.Write( (ushort)0 ); // comment length
+ }
+
+ static uint CRC32( byte[] data, int length ) {
+ uint crc = 0xffffffffU;
+ for( int i = 0; i < length; i++ ) {
+ crc ^= data[i];
+ for( int j = 0; j < 8; j++ )
+ crc = (crc >> 1) ^ (crc & 1) * 0xEDB88320;
+ }
+ return crc ^ 0xffffffffU;
+ }
+ }
+}
diff --git a/Launcher/ResourceFetcher.cs b/Launcher/ResourceFetcher.cs
deleted file mode 100644
index 04785f5f8..000000000
--- a/Launcher/ResourceFetcher.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Windows.Forms;
-
-namespace Launcher {
-
- public class ResourceFetcher {
-
- const string resUri = "https://raw.githubusercontent.com/andrewphorn/ClassiCube-Client/master/src/main/resources/";
- static readonly string[] coreList = { "char.png", "clouds.png", "terrain.png", "rain.png", "snow.png" };
- static readonly string[] mobsList = { "chicken.png", "creeper.png", "pig.png", "sheep.png",
- "sheep_fur.png", "skeleton.png", "spider.png", "zombie.png" };
- static int resourcesCount = coreList.Length + mobsList.Length;
-
- public void Run( MainForm form ) {
- using( WebClient client = new WebClient() ) {
- client.Proxy = null;
- int i = 0;
- if( DownloadResources( "", client, form, ref i, coreList ) ) {
- DownloadResources( "mob/", client, form, ref i, mobsList );
- }
- }
- }
-
- static bool DownloadResources( string prefix, WebClient client, MainForm form, ref int i, params string[] resources ) {
- foreach( string resource in resources ) {
- if( !DownloadData( prefix + resource, client, resource, form, ref i ) ) return false;
- }
- return true;
- }
-
- static bool DownloadData( string uri, WebClient client, string output, MainForm form, ref int i ) {
- i++;
- if( File.Exists( output ) ) return true;
- form.Text = MainForm.AppName + " - fetching " + output + "(" + i + "/" + resourcesCount + ")";
-
- try {
- client.DownloadFile( resUri + uri, output );
- } catch( WebException ex ) {
- Program.LogException( ex );
- MessageBox.Show( "Unable to download or save " + output, "Failed to download or save resource", MessageBoxButtons.OK, MessageBoxIcon.Error );
- return false;
- }
- return true;
- }
-
- public bool CheckAllResourcesExist() {
- return CheckResourcesExist( coreList ) && CheckResourcesExist( mobsList );
- }
-
- static bool CheckResourcesExist( params string[] resources ) {
- foreach( string file in resources ) {
- if( !File.Exists( file ) )
- return false;
- }
- return true;
- }
- }
-}