mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 11:06:06 -04:00
Much more work on patching. Now we just depend on extract resources from classic's jar and terrain-patch.png. Snow is still broken.
This commit is contained in:
parent
69fb5dcb89
commit
58e5816acf
@ -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
|
||||
|
@ -162,7 +162,8 @@
|
||||
<Compile Include="TexturePack\Animations.cs" />
|
||||
<Compile Include="TexturePack\TerrainAtlas1D.cs" />
|
||||
<Compile Include="TexturePack\TerrainAtlas2D.cs" />
|
||||
<Compile Include="TexturePack\ZipExtractor.cs" />
|
||||
<Compile Include="TexturePack\TexturePackExtractor.cs" />
|
||||
<Compile Include="TexturePack\ZipReader.cs" />
|
||||
<Compile Include="Utils\Camera.cs" />
|
||||
<Compile Include="Utils\FastBitmap.cs" />
|
||||
<Compile Include="Utils\FastColour.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 + "\"" );
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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 ) {
|
||||
|
@ -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() {
|
||||
|
@ -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 ) {
|
||||
|
@ -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() {
|
||||
|
@ -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 ) {
|
||||
|
@ -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.." );
|
||||
|
@ -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 );
|
||||
|
@ -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 ) {
|
||||
|
82
ClassicalSharp/TexturePack/TexturePackExtractor.cs
Normal file
82
ClassicalSharp/TexturePack/TexturePackExtractor.cs
Normal file
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<string, byte[], ZipEntry> ProcessZipEntry;
|
||||
public Func<string, bool> 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
|
@ -14,6 +14,7 @@ namespace ClassicalSharp {
|
||||
public delegate TResult Func<TResult>();
|
||||
public delegate TResult Func<T1, TResult>( T1 arg1 );
|
||||
public delegate TResult Func<T1, T2, TResult>( T1 arg1, T2 arg2 );
|
||||
public delegate TResult Func<T1, T2, T3, TResult>( T1 arg1, T2 arg2, T3 arg3 );
|
||||
public delegate bool TryParseFunc<T>( string s, out T value );
|
||||
// ################################################################
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<SignAssembly>False</SignAssembly>
|
||||
<DelaySign>False</DelaySign>
|
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<NoStdLib>False</NoStdLib>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||
@ -55,6 +55,7 @@
|
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
|
||||
<StartAction>Project</StartAction>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<OutputPath>..\output\release\</OutputPath>
|
||||
@ -63,6 +64,8 @@
|
||||
<Optimize>True</Optimize>
|
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
|
||||
<StartAction>Project</StartAction>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@ -82,9 +85,10 @@
|
||||
</Compile>
|
||||
<Compile Include="MainForm.GameState.cs" />
|
||||
<Compile Include="MinecraftSession.cs" />
|
||||
<Compile Include="Patcher\ResourceFetcher.cs" />
|
||||
<Compile Include="Patcher\ZipWriter.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ResourceFetcher.cs" />
|
||||
<Compile Include="ServerListEntry.cs" />
|
||||
<Compile Include="WebUtility.cs" />
|
||||
</ItemGroup>
|
||||
@ -118,5 +122,14 @@
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ClassicalSharp\ClassicalSharp.csproj">
|
||||
<Project>{BEB1C785-5CAD-48FF-A886-876BF0A318D4}</Project>
|
||||
<Name>ClassicalSharp</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Patcher" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
103
Launcher/Patcher/ResourceFetcher.cs
Normal file
103
Launcher/Patcher/ResourceFetcher.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
114
Launcher/Patcher/ZipWriter.cs
Normal file
114
Launcher/Patcher/ZipWriter.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user