Implement partial default.zip updates.

This commit is contained in:
UnknownShadow200 2016-05-15 20:44:32 +10:00
parent babf253b59
commit 619fd5ded4
6 changed files with 201 additions and 95 deletions

View File

@ -49,11 +49,10 @@ namespace ClassicalSharp.TexturePack {
}
/// <summary> Sets the atlas bitmap that animation frames are contained within. </summary>
public void SetAtlas( Bitmap bmp ) {
void SetAtlas( Bitmap bmp ) {
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) )
game.Drawer2D.ConvertTo32Bpp( ref bmp );
Clear();
this.animBmp = bmp;
animsBuffer = new FastBitmap( bmp, true, true );
}

View File

@ -36,7 +36,7 @@ namespace Launcher {
failed = true;
if( fetcher.Done ) {
if( !fetcher.defaultZipExists ) {
if( ResourceList.Files.Count > 0 ) {
ResourcePatcher patcher = new ResourcePatcher( fetcher );
patcher.Run();
}

View File

@ -17,16 +17,36 @@ namespace Launcher {
string texDir = Path.Combine( Program.AppDirectory, "texpacks" );
string zipPath = Path.Combine( texDir, "default.zip" );
defaultZipExists = File.Exists( zipPath );
if( defaultZipExists )
CheckClassicGuiPng( zipPath );
if( !defaultZipExists ) {
// classic.jar + 1.6.2.jar + terrain-patch.png + gui.png
DownloadSize += (291 + 4621 + 7 + 21) / 1024f;
ResourcesCount += 4;
AllResourcesExist = false;
}
bool defaultZipExists = File.Exists( zipPath );
if( File.Exists( zipPath ) )
CheckDefaultZip( zipPath );
CheckTexturePack();
CheckMusic( audioPath );
CheckSounds();
}
void CheckTexturePack() {
ushort flags = 0;
foreach( var entry in ResourceList.Files )
flags |= entry.Value;
if( flags != 0 ) AllResourcesExist = false;
if( (flags & ResourceList.cMask) != 0 ) {
DownloadSize += 291/1024f; ResourcesCount++;
}
if( (flags & ResourceList.mMask) != 0 ) {
DownloadSize += 4621/1024f; ResourcesCount++;
}
if( (flags & ResourceList.tMask) != 0 ) {
DownloadSize += 7/1024f; ResourcesCount++;
}
if( (flags & ResourceList.gMask) != 0 ) {
DownloadSize += 21/1024f; ResourcesCount++;
}
}
void CheckMusic( string audioPath ) {
string[] files = ResourceList.MusicFiles;
for( int i = 0; i < files.Length; i++ ) {
string file = Path.Combine( audioPath, files[i] + ".ogg" );
@ -37,7 +57,9 @@ namespace Launcher {
AllResourcesExist = false;
}
}
}
void CheckSounds() {
if( !DigSoundsExist ) {
ResourcesCount += ResourceList.DigSounds.Length;
DownloadSize += 173 / 1024f;
@ -52,22 +74,20 @@ namespace Launcher {
public float DownloadSize;
public int ResourcesCount;
internal bool[] musicExists = new bool[7];
internal bool classicGuiPngExists, defaultZipExists;
internal bool defaultZipExists;
void CheckClassicGuiPng( string path ) {
void CheckDefaultZip( string path ) {
ZipReader reader = new ZipReader();
reader.ShouldProcessZipEntry = ShouldProcessZipEntry;
reader.ProcessZipEntry = ProcessZipEntry;
using( Stream src = new FileStream( path, FileMode.Open, FileAccess.Read ) )
reader.Extract( src );
if( !classicGuiPngExists )
defaultZipExists = false;
}
bool ShouldProcessZipEntry( string filename ) {
if( filename == "gui_classic.png" )
classicGuiPngExists = true;
bool ShouldProcessZipEntry( string filename ) {
string name = ResourceList.GetFile( filename );
ResourceList.Files.Remove( name );
return false;
}

View File

@ -2,7 +2,6 @@
using System;
using System.IO;
using ClassicalSharp.Network;
using ClassicalSharp.TexturePack;
namespace Launcher {
@ -23,6 +22,7 @@ namespace Launcher {
const string musicUri = "http://s3.amazonaws.com/MinecraftResources/music/";
const string newMusicUri = "http://s3.amazonaws.com/MinecraftResources/newmusic/";
ushort flags;
public void DownloadItems( AsyncDownloader downloader, Action<string> setStatus ) {
this.downloader = downloader;
DownloadMusicFiles();
@ -31,12 +31,18 @@ namespace Launcher {
stepPatcher = new SoundPatcher( ResourceList.StepSounds, "step_", "classic jar" );
stepPatcher.FetchFiles( stepSoundsUri, altStepSoundsUri, this, StepSoundsExist );
if( !defaultZipExists ) {
flags = 0;
foreach( var entry in ResourceList.Files )
flags |= entry.Value;
if( (flags & ResourceList.cMask) != 0 )
downloader.DownloadData( jarClassicUri, false, "classic_jar" );
if( (flags & ResourceList.mMask) != 0 )
downloader.DownloadData( jar162Uri, false, "162_jar" );
downloader.DownloadData( pngTerrainPatchUri, false, "terrain_patch" );
if( (flags & ResourceList.gMask) != 0 )
downloader.DownloadData( pngGuiPatchUri, false, "gui_patch" );
}
if( (flags & ResourceList.tMask) != 0 )
downloader.DownloadData( pngTerrainPatchUri, false, "terrain_patch" );
SetFirstStatus( setStatus );
}
@ -56,10 +62,7 @@ namespace Launcher {
setStatus( MakeNext( ResourceList.MusicFiles[i] ) );
return;
}
string next = !DigSoundsExist ? "dig_cloth1" :
(!StepSoundsExist ? "step_cloth1" : " classic jar");
setStatus( MakeNext( next ) );
setStatus( MakeNext( FirstItem() ) );
}
@ -74,25 +77,44 @@ namespace Launcher {
if( !stepPatcher.CheckDownloaded( this, setStatus ) )
return false;
if( !Download( "classic_jar", "classic jar",
"1.6.2 jar", ref jarClassic, setStatus ) )
if( !Download( "classic_jar", "classic jar", "1.6.2 jar", ref jarClassic, setStatus ) )
return false;
if( !Download( "162_jar", "1.6.2 jar",
"terrain patch", ref jar162, setStatus ) )
if( !Download( "162_jar", "1.6.2 jar", "terrain patch", ref jar162, setStatus ) )
return false;
if( !Download( "terrain_patch", "terrain.png patch",
"gui", ref pngTerrainPatch, setStatus ) )
if( !Download( "gui_patch", "gui.png patch", null, ref pngGuiPatch, setStatus ) )
return false;
if( !Download( "gui_patch", "gui.png patch",
null, ref pngGuiPatch, setStatus ) )
if( !Download( "terrain_patch", "terrain.png patch", "gui", ref pngTerrainPatch, setStatus ) )
return false;
Done |= IsDone();
return true;
}
string FirstItem() {
if( !DigSoundsExist ) return "dig_cloth1";
if( !StepSoundsExist ) return "step_cloth1";
bool done = !defaultZipExists ? pngGuiPatch != null :
stepPatcher.Done;
if( done ) {
Done = true;
return true;
}
if( (flags & ResourceList.cMask) != 0 )
return "classic jar";
if( (flags & ResourceList.mMask) != 0 )
return "1.6.2 jar";
if( (flags & ResourceList.gMask) != 0 )
return "gui.png patch";
if( (flags & ResourceList.tMask) != 0 )
return "terrain.png patch";
return "(unknown)";
}
bool IsDone() {
if( flags == 0 ) return stepPatcher.Done;
if( (flags & ResourceList.tMask) != 0 )
return pngTerrainPatch != null;
if( (flags & ResourceList.gMask) != 0 )
return pngGuiPatch != null;
if( (flags & ResourceList.mMask) != 0 )
return jar162 != null;
if( (flags & ResourceList.cMask) != 0 )
return jarClassic != null;
return true;
}
@ -151,13 +173,11 @@ namespace Launcher {
DownloadSize = checker.DownloadSize;
ResourcesCount = checker.ResourcesCount;
musicExists = checker.musicExists;
defaultZipExists = checker.defaultZipExists;
}
public bool AllResourcesExist, DigSoundsExist, StepSoundsExist;
public float DownloadSize;
public int ResourcesCount, CurrentResource;
bool[] musicExists = new bool[7];
internal bool defaultZipExists;
}
}

View File

@ -1,5 +1,6 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
@ -16,65 +17,116 @@ namespace Launcher {
pngTerrainPatch = fetcher.pngTerrainPatch;
pngGuiPatch = fetcher.pngGuiPatch;
}
ZipReader reader;
ZipWriter writer;
Bitmap animBitmap;
List<string> existing = new List<string>();
byte[] jarClassic, jar162, pngTerrainPatch, pngGuiPatch;
public void Run() {
byte[] jarClassic, jar162, pngTerrainPatch, pngGuiPatch;
public void Run() {
reader = new ZipReader();
reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Classic;
reader.ProcessZipEntry = ProcessZipEntry_Classic;
string texDir = Path.Combine( Program.AppDirectory, "texpacks" );
string path = Path.Combine( texDir, "default.zip" );
ExtractExisting( path );
using( Stream srcClassic = new MemoryStream( jarClassic ),
srcModern = new MemoryStream( jar162 ),
dst = new FileStream( path, FileMode.Create, FileAccess.Write ) ) {
using( Stream dst = new FileStream( path, FileMode.Create, FileAccess.Write ) ) {
writer = new ZipWriter( dst );
reader.Extract( srcClassic );
writer.entries = new ZipEntry[100];
for( int i = 0; i < entries.Count; i++ )
writer.WriteZipEntry( entries[i], datas[i] );
// Grab animations and snow
animBitmap = new Bitmap( 1024, 64, PixelFormat.Format32bppArgb );
reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Modern;
reader.ProcessZipEntry = ProcessZipEntry_Modern;
reader.Extract( srcModern );
writer.WriteNewImage( animBitmap, "animations.png" );
writer.WriteNewString( animationsTxt, "animations.txt" );
using( Bitmap guiBitmap = new Bitmap( new MemoryStream( pngGuiPatch ) ) ) {
writer.WriteNewImage( guiBitmap, "gui.png" );
ExtractClassic();
ExtractModern();
if( pngGuiPatch != null ) {
using( Bitmap guiBitmap = new Bitmap( new MemoryStream( pngGuiPatch ) ) )
writer.WriteNewImage( guiBitmap, "gui.png" );
}
animBitmap.Dispose();
writer.WriteCentralDirectoryRecords();
}
}
ZipReader reader;
ZipWriter writer;
Bitmap animBitmap;
#region From default.zip
List<ZipEntry> entries = new List<ZipEntry>();
List<byte[]> datas = new List<byte[]>();
void ExtractExisting( string path ) {
if( !File.Exists( path ) ) return;
using( Stream src = new FileStream( path, FileMode.Open, FileAccess.Read ) ) {
reader.ShouldProcessZipEntry = (file) => true;
reader.ProcessZipEntry = ExtractExisting;
reader.Extract( src );
}
}
void ExtractExisting( string filename, byte[] data, ZipEntry entry ) {
filename = ResourceList.GetFile( filename );
entry.Filename = filename;
existing.Add( filename );
entries.Add( entry );
datas.Add( data );
}
#endregion
#region From classic
void ExtractClassic() {
if( jarClassic == null ) return;
using( Stream src = new MemoryStream( jarClassic ) ) {
reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Classic;
reader.ProcessZipEntry = ProcessZipEntry_Classic;
reader.Extract( src );
}
}
bool ShouldProcessZipEntry_Classic( string filename ) {
return filename.StartsWith( "gui" )
return filename.StartsWith( "gui" )
|| filename.StartsWith( "mob" ) || filename.IndexOf( '/' ) < 0;
}
StringComparison comp = StringComparison.OrdinalIgnoreCase;
void ProcessZipEntry_Classic( string filename, byte[] data, ZipEntry entry ) {
if( writer.entries == null )
writer.entries = new ZipEntry[reader.entries.Length];
if( !filename.EndsWith( ".png", comp ) ) return;
entry.Filename = ResourceList.GetFile( filename );
if( filename != "terrain.png" ) {
int lastSlash = filename.LastIndexOf( '/' );
if( lastSlash >= 0 )
entry.Filename = filename.Substring( lastSlash + 1 );
if( entry.Filename == "gui.png" )
if( entry.Filename != "terrain.png" ) {
if( entry.Filename == "gui.png" )
entry.Filename = "gui_classic.png";
writer.WriteZipEntry( entry, data );
if( !existing.Contains( entry.Filename ) )
writer.WriteZipEntry( entry, data );
return;
} else if( !existing.Contains( "terrain.png" ) ){
using( Bitmap dstBitmap = new Bitmap( new MemoryStream( data ) ),
maskBitmap = new Bitmap( new MemoryStream( pngTerrainPatch ) ) ) {
PatchImage( dstBitmap, maskBitmap );
writer.WriteNewImage( dstBitmap, "terrain.png" );
}
}
}
#endregion
#region From Modern
void ExtractModern() {
if( jar162 == null ) return;
using( Bitmap dstBitmap = new Bitmap( new MemoryStream( data ) ),
maskBitmap = new Bitmap( new MemoryStream( pngTerrainPatch ) ) ) {
PatchImage( dstBitmap, maskBitmap );
writer.WriteNewImage( dstBitmap, "terrain.png" );
using( Stream src = new MemoryStream( jar162 ) ) {
// Grab animations and snow
animBitmap = new Bitmap( 1024, 64, PixelFormat.Format32bppArgb );
reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Modern;
reader.ProcessZipEntry = ProcessZipEntry_Modern;
reader.Extract( src );
if( !existing.Contains( "animations.png" ) )
writer.WriteNewImage( animBitmap, "animations.png" );
if( !existing.Contains( "animations.txt" ) )
writer.WriteNewString( animationsTxt, "animations.txt" );
animBitmap.Dispose();
}
}
@ -88,14 +140,15 @@ namespace Launcher {
}
void ProcessZipEntry_Modern( string filename, byte[] data, ZipEntry entry ) {
entry.Filename = ResourceList.GetFile( filename );
switch( filename ) {
case "assets/minecraft/textures/environment/snow.png":
entry.Filename = "snow.png";
writer.WriteZipEntry( entry, data );
if( !existing.Contains( "snow.png" ) )
writer.WriteZipEntry( entry, data );
break;
case "assets/minecraft/textures/entity/chicken.png":
entry.Filename = "mob/chicken.png";
writer.WriteZipEntry( entry, data );
if( !existing.Contains( "chicken.png" ) )
writer.WriteZipEntry( entry, data );
break;
case "assets/minecraft/textures/blocks/water_still.png":
PatchDefault( data, 0 );
@ -109,6 +162,8 @@ namespace Launcher {
}
}
#endregion
unsafe void PatchImage( Bitmap dstBitmap, Bitmap maskBitmap ) {
using( FastBitmap dst = new FastBitmap( dstBitmap, true, false ),
src = new FastBitmap( maskBitmap, true, true ) ) {

View File

@ -1,28 +1,30 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using System.IO;
using ClassicalSharp.TexturePack;
namespace Launcher {
public sealed class ResourceList {
// Nibbles: Classic jar, 1.6.2 jar, gui patch, terrain patch
public const ushort cMask = 0xF000;
public const ushort mMask = 0x0F00;
public const ushort gMask = 0x00F0;
public const ushort tMask = 0x000F;
public static Dictionary<string, ushort> Files = new Dictionary<string, ushort>() {
// classic jar files
{ "char.png", 0x1000 }, { "clouds.png", 0x1000 },
{ "default.png", 0x1000 }, { "particles.png", 0x1000 },
{ "rain.png", 0x1000 }, { "terrain.png", 0x1001 },
{ "gui.png", 0x1000 }, { "icons.png", 0x1000 },
{ "arrows.png", 0x1000 }, { "sign.png", 0x1000 },
{ "creeper.png", 0x1000 }, { "pig.png", 0x1000 },
{ "sheep.png", 0x1000 }, { "sheep_fur.png", 0x1000 },
{ "skeleton.png", 0x1000 }, { "spider.png", 0x1000 },
{ "zombie.png", 0x1000 },
{ "char.png", cMask }, { "clouds.png", cMask },
{ "default.png", cMask }, { "particles.png", cMask },
{ "rain.png", cMask }, { "terrain.png", cMask | tMask },
{ "gui_classic.png", cMask }, { "icons.png", cMask },
//{ "arrows.png", cMask }, { "sign.png", cMask },
{ "creeper.png", cMask }, { "pig.png", cMask },
{ "sheep.png", cMask }, { "sheep_fur.png", cMask },
{ "skeleton.png", cMask }, { "spider.png", cMask },
{ "zombie.png", cMask },
// Other files
{ "snow.png", 0x0100 }, { "chicken.png", 0x0100 },
{ "animations.png", 0x0100 }, { "gui_classic.png", 0x0010 },
{ "snow.png", mMask }, { "chicken.png", mMask },
{ "animations.png", mMask }, { "gui.png", gMask },
};
public static string[] DigSounds = new [] { "Acloth1", "Acloth2", "Acloth3", "Acloth4", "Bglass1",
@ -36,5 +38,15 @@ namespace Launcher {
"Astone3", "Astone4", "Awood1", "Awood2", "Awood3", "Awood4" };
public static string[] MusicFiles = new [] { "calm1", "calm2", "calm3", "hal1", "hal2", "hal3", "hal4" };
public static string GetFile( string path ) {
// Ignore directories: convert x/name to name and x\name to name.
string name = path.ToLower();
int i = name.LastIndexOf( '\\' );
if( i >= 0 ) name = name.Substring( i + 1, name.Length - 1 - i );
i = name.LastIndexOf( '/' );
if( i >= 0 ) name = name.Substring( i + 1, name.Length - 1 - i );
return name;
}
}
}