Skip to content

Commit

Permalink
Add support for loading dynamic paintings from resource packs.
Browse files Browse the repository at this point in the history
  • Loading branch information
leMaik committed Jul 6, 2024
1 parent ee088a7 commit 2cb9b7e
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 53 deletions.
121 changes: 68 additions & 53 deletions chunky/src/java/se/llbit/chunky/entity/PaintingEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

public class PaintingEntity extends Entity {

static class Painting {
public static class Painting {

protected final Quad[] quads;
protected final Material material;
Expand Down Expand Up @@ -78,58 +78,7 @@ public Painting(Texture painting, int w, int h) {
static final Map<String, Painting> paintings = new HashMap<>();

static {
paintings.put("Kebab", new Painting(Texture.paintingKebab, 1, 1));
paintings.put("minecraft:kebab", new Painting(Texture.paintingKebab, 1, 1));
paintings.put("Aztec", new Painting(Texture.paintingAztec, 1, 1));
paintings.put("minecraft:aztec", new Painting(Texture.paintingAztec, 1, 1));
paintings.put("Alban", new Painting(Texture.paintingAlban, 1, 1));
paintings.put("minecraft:alban", new Painting(Texture.paintingAlban, 1, 1));
paintings.put("Aztec2", new Painting(Texture.paintingAztec2, 1, 1));
paintings.put("minecraft:aztec2", new Painting(Texture.paintingAztec2, 1, 1));
paintings.put("Bomb", new Painting(Texture.paintingBomb, 1, 1));
paintings.put("minecraft:bomb", new Painting(Texture.paintingBomb, 1, 1));
paintings.put("Plant", new Painting(Texture.paintingPlant, 1, 1));
paintings.put("minecraft:plant", new Painting(Texture.paintingPlant, 1, 1));
paintings.put("Wasteland", new Painting(Texture.paintingWasteland, 1, 1));
paintings.put("minecraft:wasteland", new Painting(Texture.paintingWasteland, 1, 1));
paintings.put("Wanderer", new Painting(Texture.paintingWanderer, 1, 2));
paintings.put("minecraft:wanderer", new Painting(Texture.paintingWanderer, 1, 2));
paintings.put("Graham", new Painting(Texture.paintingGraham, 1, 2));
paintings.put("minecraft:graham", new Painting(Texture.paintingGraham, 1, 2));
paintings.put("Pool", new Painting(Texture.paintingPool, 2, 1));
paintings.put("minecraft:pool", new Painting(Texture.paintingPool, 2, 1));
paintings.put("Courbet", new Painting(Texture.paintingCourbet, 2, 1));
paintings.put("minecraft:courbet", new Painting(Texture.paintingCourbet, 2, 1));
paintings.put("Sunset", new Painting(Texture.paintingSunset, 2, 1));
paintings.put("minecraft:sunset", new Painting(Texture.paintingSunset, 2, 1));
paintings.put("Sea", new Painting(Texture.paintingSea, 2, 1));
paintings.put("minecraft:sea", new Painting(Texture.paintingSea, 2, 1));
paintings.put("Creebet", new Painting(Texture.paintingCreebet, 2, 1));
paintings.put("minecraft:creebet", new Painting(Texture.paintingCreebet, 2, 1));
paintings.put("Match", new Painting(Texture.paintingMatch, 2, 2));
paintings.put("minecraft:match", new Painting(Texture.paintingMatch, 2, 2));
paintings.put("Bust", new Painting(Texture.paintingBust, 2, 2));
paintings.put("minecraft:bust", new Painting(Texture.paintingBust, 2, 2));
paintings.put("Stage", new Painting(Texture.paintingStage, 2, 2));
paintings.put("minecraft:stage", new Painting(Texture.paintingStage, 2, 2));
paintings.put("Void", new Painting(Texture.paintingVoid, 2, 2));
paintings.put("minecraft:void", new Painting(Texture.paintingVoid, 2, 2));
paintings.put("SkullAndRoses", new Painting(Texture.paintingSkullAndRoses, 2, 2));
paintings.put("minecraft:skull_and_roses", new Painting(Texture.paintingSkullAndRoses, 2, 2));
paintings.put("Wither", new Painting(Texture.paintingWither, 2, 2));
paintings.put("minecraft:wither", new Painting(Texture.paintingWither, 2, 2));
paintings.put("Fighters", new Painting(Texture.paintingFighters, 4, 2));
paintings.put("minecraft:fighters", new Painting(Texture.paintingFighters, 4, 2));
paintings.put("Skeleton", new Painting(Texture.paintingSkeleton, 4, 3));
paintings.put("minecraft:skeleton", new Painting(Texture.paintingSkeleton, 4, 3));
paintings.put("DonkeyKong", new Painting(Texture.paintingDonkeyKong, 4, 3));
paintings.put("minecraft:donkey_kong", new Painting(Texture.paintingDonkeyKong, 4, 3));
paintings.put("Pointer", new Painting(Texture.paintingPointer, 4, 4));
paintings.put("minecraft:pointer", new Painting(Texture.paintingPointer, 4, 4));
paintings.put("Pigscene", new Painting(Texture.paintingPigscene, 4, 4));
paintings.put("minecraft:pigscene", new Painting(Texture.paintingPigscene, 4, 4));
paintings.put("BurningSkull", new Painting(Texture.paintingBurningSkull, 4, 4));
paintings.put("minecraft:burning_skull", new Painting(Texture.paintingBurningSkull, 4, 4));
resetPaintings();
}

private static final Material BACK_MATERIAL = new TextureMaterial(Texture.paintingBack);
Expand Down Expand Up @@ -204,4 +153,70 @@ public static Entity fromJson(JsonObject json) {
double angle = json.get("angle").doubleValue(0.0);
return new PaintingEntity(position, art, angle);
}

public static void resetPaintings() {
paintings.clear();

// hard-coded pre-24w18a paintings with legacy aliases
paintings.put("Kebab", new Painting(Texture.paintingKebab, 1, 1));
paintings.put("minecraft:kebab", new Painting(Texture.paintingKebab, 1, 1));
paintings.put("Aztec", new Painting(Texture.paintingAztec, 1, 1));
paintings.put("minecraft:aztec", new Painting(Texture.paintingAztec, 1, 1));
paintings.put("Alban", new Painting(Texture.paintingAlban, 1, 1));
paintings.put("minecraft:alban", new Painting(Texture.paintingAlban, 1, 1));
paintings.put("Aztec2", new Painting(Texture.paintingAztec2, 1, 1));
paintings.put("minecraft:aztec2", new Painting(Texture.paintingAztec2, 1, 1));
paintings.put("Bomb", new Painting(Texture.paintingBomb, 1, 1));
paintings.put("minecraft:bomb", new Painting(Texture.paintingBomb, 1, 1));
paintings.put("Plant", new Painting(Texture.paintingPlant, 1, 1));
paintings.put("minecraft:plant", new Painting(Texture.paintingPlant, 1, 1));
paintings.put("Wasteland", new Painting(Texture.paintingWasteland, 1, 1));
paintings.put("minecraft:wasteland", new Painting(Texture.paintingWasteland, 1, 1));
paintings.put("Wanderer", new Painting(Texture.paintingWanderer, 1, 2));
paintings.put("minecraft:wanderer", new Painting(Texture.paintingWanderer, 1, 2));
paintings.put("Graham", new Painting(Texture.paintingGraham, 1, 2));
paintings.put("minecraft:graham", new Painting(Texture.paintingGraham, 1, 2));
paintings.put("Pool", new Painting(Texture.paintingPool, 2, 1));
paintings.put("minecraft:pool", new Painting(Texture.paintingPool, 2, 1));
paintings.put("Courbet", new Painting(Texture.paintingCourbet, 2, 1));
paintings.put("minecraft:courbet", new Painting(Texture.paintingCourbet, 2, 1));
paintings.put("Sunset", new Painting(Texture.paintingSunset, 2, 1));
paintings.put("minecraft:sunset", new Painting(Texture.paintingSunset, 2, 1));
paintings.put("Sea", new Painting(Texture.paintingSea, 2, 1));
paintings.put("minecraft:sea", new Painting(Texture.paintingSea, 2, 1));
paintings.put("Creebet", new Painting(Texture.paintingCreebet, 2, 1));
paintings.put("minecraft:creebet", new Painting(Texture.paintingCreebet, 2, 1));
paintings.put("Match", new Painting(Texture.paintingMatch, 2, 2));
paintings.put("minecraft:match", new Painting(Texture.paintingMatch, 2, 2));
paintings.put("Bust", new Painting(Texture.paintingBust, 2, 2));
paintings.put("minecraft:bust", new Painting(Texture.paintingBust, 2, 2));
paintings.put("Stage", new Painting(Texture.paintingStage, 2, 2));
paintings.put("minecraft:stage", new Painting(Texture.paintingStage, 2, 2));
paintings.put("Void", new Painting(Texture.paintingVoid, 2, 2));
paintings.put("minecraft:void", new Painting(Texture.paintingVoid, 2, 2));
paintings.put("SkullAndRoses", new Painting(Texture.paintingSkullAndRoses, 2, 2));
paintings.put("minecraft:skull_and_roses", new Painting(Texture.paintingSkullAndRoses, 2, 2));
paintings.put("Wither", new Painting(Texture.paintingWither, 2, 2));
paintings.put("minecraft:wither", new Painting(Texture.paintingWither, 2, 2));
paintings.put("Fighters", new Painting(Texture.paintingFighters, 4, 2));
paintings.put("minecraft:fighters", new Painting(Texture.paintingFighters, 4, 2));
paintings.put("Skeleton", new Painting(Texture.paintingSkeleton, 4, 3));
paintings.put("minecraft:skeleton", new Painting(Texture.paintingSkeleton, 4, 3));
paintings.put("DonkeyKong", new Painting(Texture.paintingDonkeyKong, 4, 3));
paintings.put("minecraft:donkey_kong", new Painting(Texture.paintingDonkeyKong, 4, 3));
paintings.put("Pointer", new Painting(Texture.paintingPointer, 4, 4));
paintings.put("minecraft:pointer", new Painting(Texture.paintingPointer, 4, 4));
paintings.put("Pigscene", new Painting(Texture.paintingPigscene, 4, 4));
paintings.put("minecraft:pigscene", new Painting(Texture.paintingPigscene, 4, 4));
paintings.put("BurningSkull", new Painting(Texture.paintingBurningSkull, 4, 4));
paintings.put("minecraft:burning_skull", new Painting(Texture.paintingBurningSkull, 4, 4));
}

public static void registerPainting(String id, Painting painting) {
paintings.put(id, painting);
}

public static boolean containsPainting(String id) {
return paintings.containsKey(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package se.llbit.chunky.resources;

import se.llbit.chunky.PersistentSettings;
import se.llbit.chunky.entity.PaintingEntity;
import se.llbit.chunky.world.biome.Biomes;
import se.llbit.log.Log;

Expand All @@ -38,6 +39,7 @@ public class ResourcePackLoader {
static {
ResourcePackLoader.PACK_LOADER_FACTORIES.add(() -> new ResourcePackTextureLoader(TexturePackLoader.ALL_TEXTURES));
ResourcePackLoader.PACK_LOADER_FACTORIES.add(ResourcePackBiomeLoader::new);
ResourcePackLoader.PACK_LOADER_FACTORIES.add(ResourcePackPaintingLoader::new);
}

public interface PackLoader {
Expand Down Expand Up @@ -119,6 +121,7 @@ public static void loadAndPersistResourcePacks(List<File> resourcePacks) {
public static void loadResourcePacks(List<File> resourcePacks) {
TextureCache.reset();
Biomes.reset();
PaintingEntity.resetPaintings();

if (ResourcePackLoader.resourcePacks != null) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package se.llbit.chunky.resources;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import se.llbit.chunky.entity.PaintingEntity;
import se.llbit.chunky.resources.texturepack.SimpleTexture;
import se.llbit.log.Log;
import se.llbit.util.Pair;

import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.stream.Stream;

public class ResourcePackPaintingLoader implements ResourcePackLoader.PackLoader {

protected static final Gson GSON = new GsonBuilder()
.disableJdkUnsafe()
.setLenient()
.create();

protected static class PaintingVariantJson {
public String asset_id;
public int width;
public int height;

public Pair<String, String> getAsset() {
String[] parts = asset_id.split(":");
return new Pair<>(parts[0], parts[1]);
}
}

@Override
public boolean load(LayeredResourcePacks resourcePacks) {
for (LayeredResourcePacks.Entry data : resourcePacks.getAllEntries("data")) {
try (Stream<Path> namespaces = Files.list(data.getPath())) {
namespaces.forEach(ns -> {
String namespace = String.valueOf(ns.getFileName());
Path paintingVariants = ns.resolve("painting_variant");
try (Stream<Path> paintingVariantStream = Files.walk(paintingVariants)) {
paintingVariantStream
.filter(p -> Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS))
.forEach(paintingVariant -> {
if (paintingVariant.toString().endsWith(".json")) {
String paintingVariantName = getPaintingVariantName(paintingVariants.relativize(paintingVariant));
String resourceLocation = namespace + ":" + paintingVariantName;

if (!PaintingEntity.containsPainting(resourceLocation)) {
try (Reader f = Files.newBufferedReader(paintingVariant)) {
PaintingVariantJson json = GSON.fromJson(f, PaintingVariantJson.class);
Texture paintingTexture = new Texture();
Pair<String, String> asset = json.getAsset();
if (!ResourcePackLoader.loadResources(
ResourcePackTextureLoader.singletonLoader(json.asset_id, new SimpleTexture("assets/" + asset.thing1 + "/textures/painting/" + asset.thing2, paintingTexture)))
) {
Log.warnf("Failed to load painting texture: %s", json.asset_id);
}
PaintingEntity.registerPainting(resourceLocation, new PaintingEntity.Painting(paintingTexture, json.width, json.height));
} catch (IOException ignored) {
Log.warnf("Failed to load painting variant: %s", paintingVariantName);
}
}
}
});
} catch (IOException ignored) {
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}

return false;
}

private static String getPaintingVariantName(Path paintingVariant) {
ArrayList<String> path = new ArrayList<>();
paintingVariant.iterator().forEachRemaining(p -> path.add(String.valueOf(p)));

String out = String.join("/", path);
if (out.toLowerCase().endsWith(".json")) {
out = out.substring(0, out.length() - ".json".length());
}
return out;
}
}

0 comments on commit 2cb9b7e

Please sign in to comment.