From c6bc398950b24f898207ffb2661c41ad2711e67a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Sep 2019 11:26:25 -0400 Subject: [PATCH] Texture packing --- core/assets/bundles/bundle.properties | 1 + .../io/anuke/mindustry/ClientLauncher.java | 8 +- .../src/io/anuke/mindustry/core/FileTree.java | 40 +------- core/src/io/anuke/mindustry/mod/Mods.java | 92 ++++++++++++++++++- 4 files changed, 100 insertions(+), 41 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 948fc716fb..1015b208e6 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -22,6 +22,7 @@ load.map = Maps load.image = Images load.content = Content load.system = System +load.mod = Mods stat.wave = Waves Defeated:[accent] {0} stat.enemiesDestroyed = Enemies Destroyed:[accent] {0} diff --git a/core/src/io/anuke/mindustry/ClientLauncher.java b/core/src/io/anuke/mindustry/ClientLauncher.java index 58509632d5..13f05a847c 100644 --- a/core/src/io/anuke/mindustry/ClientLauncher.java +++ b/core/src/io/anuke/mindustry/ClientLauncher.java @@ -55,6 +55,12 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform atlas = (TextureAtlas)t; }; + if(!mods.all().isEmpty()){ + assets.loadRun("mods", Mods.class, () -> { + mods.packSprites(); + }); + } + assets.loadRun("maps", Map.class, () -> maps.loadPreviews()); Musics.load(); @@ -186,7 +192,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform if(assets.getCurrentLoading() != null){ String name = assets.getCurrentLoading().fileName.toLowerCase(); - String key = name.contains("content") ? "content" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system"; + String key = name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system"; font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center); } } diff --git a/core/src/io/anuke/mindustry/core/FileTree.java b/core/src/io/anuke/mindustry/core/FileTree.java index 19b2658061..b55b063635 100644 --- a/core/src/io/anuke/mindustry/core/FileTree.java +++ b/core/src/io/anuke/mindustry/core/FileTree.java @@ -3,49 +3,13 @@ package io.anuke.mindustry.core; import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.files.*; -import io.anuke.arc.util.*; -import io.anuke.arc.util.io.*; -import io.anuke.mindustry.mod.Mods.*; /** Handles files in a modded context. */ public class FileTree{ private ObjectMap files = new ObjectMap<>(); - private ObjectMap> bundles = new ObjectMap<>(); - public void buildFiles(Array mods){ - //TODO many files should not be replaced - for(LoadedMod mod : mods){ - mod.root.walk(f -> { - //TODO calling child/parent on these files will give you gibberish; create wrapper class. - files.put(f.path(), f); - }); - - //load up bundles. - FileHandle folder = mod.root.child("bundles"); - if(folder.exists()){ - for(FileHandle file : folder.list()){ - if(file.name().startsWith("bundle") && file.extension().equals("properties")){ - String name = file.nameWithoutExtension(); - bundles.getOr(name, Array::new).add(file); - } - } - } - } - - //add new keys to each bundle - I18NBundle bundle = Core.bundle; - while(bundle != null){ - String str = bundle.getLocale().toString(); - String locale = "bundle" + (str.isEmpty() ? "" : "_" + str); - for(FileHandle file : bundles.getOr(locale, Array::new)){ - try{ - PropertiesUtils.load(bundle.getProperties(), file.reader()); - }catch(Exception e){ - throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e); - } - } - bundle = bundle.getParent(); - } + public void addFile(FileHandle f){ + files.put(f.path(), f); } /** Gets an asset file.*/ diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 219914b90f..58ef0cde02 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -1,10 +1,16 @@ package io.anuke.mindustry.mod; import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.function.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.Pixmap.*; +import io.anuke.arc.graphics.Texture.*; +import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.type.*; @@ -15,9 +21,12 @@ import static io.anuke.mindustry.Vars.*; public class Mods{ private Json json = new Json(); + private ContentParser parser = new ContentParser(); + private ObjectMap> bundles = new ObjectMap<>(); + private ObjectSet specialFolders = ObjectSet.with("bundles", "sprites"); + private Array loaded = new Array<>(); private ObjectMap, ModMeta> metas = new ObjectMap<>(); - private ContentParser parser = new ContentParser(); private boolean requiresRestart; /** Returns a file named 'config.json' in a special folder for the specified plugin. @@ -53,6 +62,47 @@ public class Mods{ } } + /** Repacks all in-game sprites. */ + public void packSprites(){ + int total = 0; + + PixmapPacker packer = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true); + for(LoadedMod mod : loaded){ + try{ + int packed = 0; + for(FileHandle file : mod.root.child("sprites").list()){ + if(file.extension().equals("png")){ + try(InputStream stream = file.read()){ + byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512)); + Pixmap pixmap = new Pixmap(bytes, 0, bytes.length); + packer.pack(mod.meta.name + ":" + file.nameWithoutExtension(), pixmap); + pixmap.dispose(); + packed ++; + total ++; + } + } + } + Log.info("Packed {0} images for mod '{1}'.", packed, mod.meta.name); + }catch(IOException e){ + Log.err("Error packing images for mod: {0}", mod.meta.name); + e.printStackTrace(); + if(!headless) ui.showException(e); + } + } + + if(total > 0){ + Core.app.post(() -> { + TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest; + + packer.getPages().each(page -> page.updateTexture(filter, filter, false)); + packer.getPages().each(page -> page.getRects().each((name, rect) -> Core.atlas.addRegion(name, page.getTexture(), (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height))); + packer.dispose(); + }); + }else{ + packer.dispose(); + } + } + /** Removes a mod file and marks it for requiring a restart. */ public void removeMod(LoadedMod mod){ mod.file.delete(); @@ -78,7 +128,45 @@ public class Mods{ } } - filet.buildFiles(loaded); + buildFiles(); + } + + private void buildFiles(){ + for(LoadedMod mod : loaded){ + for(FileHandle file : mod.root.list()){ + //ignore special folders like bundles or sprites + if(file.isDirectory() && !specialFolders.contains(file.name())){ + //TODO calling child/parent on these files will give you gibberish; create wrapper class. + file.walk(f -> filet.addFile(f)); + } + } + + //load up bundles. + FileHandle folder = mod.root.child("bundles"); + if(folder.exists()){ + for(FileHandle file : folder.list()){ + if(file.name().startsWith("bundle") && file.extension().equals("properties")){ + String name = file.nameWithoutExtension(); + bundles.getOr(name, Array::new).add(file); + } + } + } + } + + //add new keys to each bundle + I18NBundle bundle = Core.bundle; + while(bundle != null){ + String str = bundle.getLocale().toString(); + String locale = "bundle" + (str.isEmpty() ? "" : "_" + str); + for(FileHandle file : bundles.getOr(locale, Array::new)){ + try{ + PropertiesUtils.load(bundle.getProperties(), file.reader()); + }catch(Exception e){ + throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e); + } + } + bundle = bundle.getParent(); + } } /** Creates all the content found in mod files. */