// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using ClassicalSharp; using ClassicalSharp.Textures; namespace Launcher.Patcher { public partial class ResourcePatcher { public ResourcePatcher(ResourceFetcher fetcher, IDrawer2D drawer) { jarClassic = fetcher.jarClassic; jar162 = fetcher.jar162; pngTerrainPatch = fetcher.pngTerrainPatch; pngGuiPatch = fetcher.pngGuiPatch; this.drawer = drawer; } ZipReader reader; ZipWriter writer; IDrawer2D drawer; Bitmap animBitmap; List existing = new List(); 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 dst = new FileStream(path, FileMode.Create, FileAccess.Write)) { writer = new ZipWriter(dst); writer.entries = new ZipEntry[100]; for (int i = 0; i < entries.Count; i++) writer.WriteZipEntry(entries[i], datas[i]); ExtractClassic(); ExtractModern(); if (pngGuiPatch != null) { using (Bitmap gui = Platform.ReadBmp32Bpp(drawer, pngGuiPatch)) writer.WriteNewImage(gui, "gui.png"); } writer.WriteCentralDirectoryRecords(); } } #region From default.zip List entries = new List(); List datas = new List(); 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") || filename.StartsWith("mob") || filename.IndexOf('/') < 0; } StringComparison comp = StringComparison.OrdinalIgnoreCase; void ProcessZipEntry_Classic(string filename, byte[] data, ZipEntry entry) { if (!filename.EndsWith(".png", comp)) return; entry.Filename = ResourceList.GetFile(filename); if (entry.Filename != "terrain.png") { if (entry.Filename == "gui.png") entry.Filename = "gui_classic.png"; if (!existing.Contains(entry.Filename)) writer.WriteZipEntry(entry, data); return; } else if (!existing.Contains("terrain.png")){ using (Bitmap dst = Platform.ReadBmp32Bpp(drawer, data), mask = Platform.ReadBmp32Bpp(drawer, pngTerrainPatch)) { PatchImage(dst, mask); writer.WriteNewImage(dst, "terrain.png"); } } } #endregion #region From Modern void ExtractModern() { if (jar162 == null) return; using (Stream src = new MemoryStream(jar162)) { // Grab animations and snow animBitmap = Platform.CreateBmp(1024, 64); 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(); } } bool ShouldProcessZipEntry_Modern(string filename) { return filename.StartsWith("assets/minecraft/textures") && (filename == "assets/minecraft/textures/environment/snow.png" || filename == "assets/minecraft/textures/blocks/water_still.png" || filename == "assets/minecraft/textures/blocks/lava_still.png" || filename == "assets/minecraft/textures/blocks/fire_layer_1.png" || filename == "assets/minecraft/textures/entity/chicken.png"); } void ProcessZipEntry_Modern(string filename, byte[] data, ZipEntry entry) { entry.Filename = ResourceList.GetFile(filename); switch(filename) { case "assets/minecraft/textures/environment/snow.png": if (!existing.Contains("snow.png")) writer.WriteZipEntry(entry, data); break; case "assets/minecraft/textures/entity/chicken.png": if (!existing.Contains("chicken.png")) writer.WriteZipEntry(entry, data); break; case "assets/minecraft/textures/blocks/water_still.png": PatchDefault(data, 0); break; case "assets/minecraft/textures/blocks/lava_still.png": PatchCycle(data, 16); break; case "assets/minecraft/textures/blocks/fire_layer_1.png": PatchDefault(data, 32); break; } } #endregion unsafe void PatchImage(Bitmap dstBitmap, Bitmap maskBitmap) { using (FastBitmap dst = new FastBitmap(dstBitmap, true, false), src = new FastBitmap(maskBitmap, true, 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); } } } } } void CopyTile(int src, int dst, int y, Bitmap bmp) { for (int yy = 0; yy < 16; yy++) { for (int xx = 0; xx < 16; xx++) { animBitmap.SetPixel(dst + xx, y + yy, bmp.GetPixel(xx, src + yy)); } } } } }