diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 5624e7bd8..7dc8f070f 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -140,6 +140,9 @@ furniture: - "xxx:invalid_furniture" # Whether to hide the entity containing metadata hide-base-entity: true + # Removed collision box entity texture + removed-collision-box-entity-texture-1_20_2: true + removed-collision-box-entity-texture-1_20: false image: # Prevent players from using images set in minecraft:default font diff --git a/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png b/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png new file mode 100644 index 000000000..b6c9cade6 Binary files /dev/null and b/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png differ diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index f0193f44b..0dc67af88 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -27,6 +27,9 @@ import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -36,6 +39,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -50,6 +54,7 @@ public abstract class AbstractPackManager implements PackManager { public static final Set VANILLA_ITEM_TEXTURES = new HashSet<>(); public static final Set VANILLA_BLOCK_TEXTURES = new HashSet<>(); public static final Set VANILLA_FONT_TEXTURES = new HashSet<>(); + public static final List SHULKER_PNG = new ArrayList<>(1); private final CraftEngine plugin; private final BiConsumer eventDispatcher; @@ -85,6 +90,8 @@ public abstract class AbstractPackManager implements PackManager { loadInternalList("internal/textures/block/_list.json", VANILLA_BLOCK_TEXTURES::add); loadInternalList("internal/textures/item/_list.json", VANILLA_ITEM_TEXTURES::add); loadInternalList("internal/textures/font/_list.json", VANILLA_FONT_TEXTURES::add); + + loadInternalPng("internal/textures/entity/shulker/shulker.png", SHULKER_PNG::add); } private void loadInternalData(String path, BiConsumer callback) { @@ -118,6 +125,16 @@ public abstract class AbstractPackManager implements PackManager { } } + private void loadInternalPng(String path, Consumer callback) { + try (InputStream inputStream = this.plugin.resourceStream(path)) { + if (inputStream != null) { + callback.accept(inputStream.readAllBytes()); + } + } catch (IOException e) { + this.plugin.logger().warn("Failed to load " + path, e); + } + } + @Override public Path resourcePackPath() { return this.plugin.dataFolderPath() @@ -482,6 +499,7 @@ public abstract class AbstractPackManager implements PackManager { this.generateCustomSounds(generatedPackPath); this.generateClientLang(generatedPackPath); this.generateEquipments(generatedPackPath); + this.generateShulker(generatedPackPath); Path zipFile = resourcePackPath(); try { @@ -512,6 +530,91 @@ public abstract class AbstractPackManager implements PackManager { } } + private void generateShulker(Path generatedPackPath) { + try { + if (ConfigManager.removedCollisionBoxEntityTextureLegacy()) { + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File parentDir = shulkerFile.getParentFile(); + if (!parentDir.exists()) { + if (parentDir.mkdirs()) { + if (!shulkerFile.exists()) { + try (OutputStream out = new FileOutputStream(shulkerFile)) { + out.write(SHULKER_PNG.get(0)); + } + } else { + this.modifyShulker(shulkerFile, shulkerFile); + } + } else { + this.plugin.logger().warn("Failed to create parent directories for: " + shulkerFile.getAbsolutePath()); + } + } + } + if (ConfigManager.removedCollisionBoxEntityTexture()) { + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); + File overlaysFile = generatedPackPath.resolve("1_20_2_ce/assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + boolean modifyPackMetaFile = false; + if (!shulkerFile.exists() && packMetaFile.exists()) { + File parentDir = overlaysFile.getParentFile(); + if (parentDir.mkdirs()) { + try (OutputStream out = new FileOutputStream(overlaysFile)) { + out.write(SHULKER_PNG.get(0)); + } + modifyPackMetaFile = true; + } else { + this.plugin.logger().warn("Failed to create parent directories for: " + overlaysFile.getAbsolutePath()); + } + } else if (packMetaFile.exists()) { + this.modifyShulker(shulkerFile, overlaysFile); + modifyPackMetaFile = true; + } + if (modifyPackMetaFile) { + JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); + JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); + JsonObject entrie = new JsonObject(); + JsonObject formats = new JsonObject(); + formats.addProperty("min_inclusive", 16); + formats.addProperty("max_inclusive", 34); + entrie.add("formats", formats); + entrie.addProperty("directory", "1_20_2_ce"); + entries.add(entrie); + GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); + } + } + } catch (IOException e) { + this.plugin.logger().warn("Error creating shulker.png", e); + } + } + + private void modifyShulker(File shulkerFile, File saveFile) throws IOException { + BufferedImage originalImage = ImageIO.read(shulkerFile); + BufferedImage argbImage; + if (originalImage.getType() == BufferedImage.TYPE_INT_ARGB) { + argbImage = originalImage; + } else { + argbImage = new BufferedImage( + originalImage.getWidth(), + originalImage.getHeight(), + BufferedImage.TYPE_INT_ARGB + ); + Graphics2D g = argbImage.createGraphics(); + g.drawImage(originalImage, 0, 0, null); + g.dispose(); + } + int startX = 0; + int startY = argbImage.getHeight() - 12; + int width = 24; + int heightRegion = 12; + for (int y = startY; y < startY + heightRegion; y++) { + for (int x = startX; x < startX + width; x++) { + int pixel = argbImage.getRGB(x, y); + int transparentPixel = pixel & 0x00FFFFFF; + argbImage.setRGB(x, y, transparentPixel); + } + } + ImageIO.write(argbImage, "PNG", saveFile); + } + private void generateEquipments(Path generatedPackPath) { for (EquipmentGeneration generator : this.plugin.itemManager().equipmentsToGenerate()) { EquipmentData equipmentData = generator.modernData(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java index 46586334c..6cf57a455 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java @@ -104,6 +104,8 @@ public class ConfigManager implements Reloadable { protected boolean furniture$remove_invalid_furniture_on_chunk_load$enable; protected Set furniture$remove_invalid_furniture_on_chunk_load$list; protected boolean furniture$hide_base_entity; + protected boolean furniture$removed_collision_box_entity_texture_1_20_2; + protected boolean furniture$removed_collision_box_entity_texture_1_20; protected boolean block$sound_system$enable; protected boolean recipe$enable; @@ -260,6 +262,8 @@ public class ConfigManager implements Reloadable { furniture$remove_invalid_furniture_on_chunk_load$enable = config.getBoolean("furniture.remove-invalid-furniture-on-chunk-load.enable", false); furniture$remove_invalid_furniture_on_chunk_load$list = new HashSet<>(config.getStringList("furniture.remove-invalid-furniture-on-chunk-load.list")); furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true); + furniture$removed_collision_box_entity_texture_1_20_2 = config.getBoolean("furniture.removed-collision-box-entity-texture-1_20_2", true); + furniture$removed_collision_box_entity_texture_1_20 = config.getBoolean("furniture.removed-collision-box-entity-texture-1_20", false); // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -553,6 +557,14 @@ public class ConfigManager implements Reloadable { return instance().furniture$hide_base_entity; } + public static boolean removedCollisionBoxEntityTexture() { + return instance().furniture$removed_collision_box_entity_texture_1_20_2; + } + + public static boolean removedCollisionBoxEntityTextureLegacy() { + return instance().furniture$removed_collision_box_entity_texture_1_20; + } + public YamlDocument loadOrCreateYamlData(String fileName) { File file = new File(this.plugin.dataFolderFile(), fileName); if (!file.exists()) {