diff --git a/.gitignore b/.gitignore index cf326b8..2de2800 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ src/generated/resources/.cache/ *.DS_Store .factorypath +run-data diff --git a/models/lathe.bbmodel b/models/lathe.bbmodel new file mode 100644 index 0000000..15ecdf6 --- /dev/null +++ b/models/lathe.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"4.10","model_format":"animated_entity_model","box_uv":true},"name":"lathe","model_identifier":"","visible_box":[4,3.5,1.25],"variable_placeholders":"","variable_placeholder_buttons":[],"timeline_setups":[],"unhandled_root_fields":{},"geckolib_modid":"ibg","geckolib_model_type":"Block","geckolib_filepath_cache":{"model":"/home/jika/Projects/gt/ibg/src/main/resources/assets/ibg/geo/lathe.geo.json","animation":"/home/jika/Projects/gt/ibg/src/main/resources/assets/ibg/animations/lathe.animation.json","display":"/home/jika/Documents/mc/animated_block/models/block/animated_block.json"},"resolution":{"width":128,"height":128},"elements":[{"name":"cube","box_uv":true,"rescale":false,"locked":false,"light_emission":0,"render_order":"default","allow_mirror_modeling":true,"from":[6,7,-1],"to":[8,18,1],"autouv":0,"color":6,"rotation":[90,90,0],"origin":[7,18,0],"uv_offset":[0,30],"faces":{"north":{"uv":[2,32,4,43],"texture":0},"east":{"uv":[0,32,2,43],"texture":0},"south":{"uv":[6,32,8,43],"texture":0},"west":{"uv":[4,32,6,43],"texture":0},"up":{"uv":[4,32,2,30],"texture":0},"down":{"uv":[6,30,4,32],"texture":0}},"type":"cube","uuid":"7141d37a-992c-8b3d-c86d-1dd3baa85c78"},{"name":"cube","box_uv":false,"rescale":false,"locked":false,"light_emission":0,"render_order":"default","allow_mirror_modeling":true,"from":[-24,0,-8],"to":[8,14,8],"autouv":0,"color":2,"origin":[-7,0,-7],"faces":{"north":{"uv":[16,16,48,30],"texture":0},"east":{"uv":[0,16,16,30],"texture":0},"south":{"uv":[64,16,96,30],"texture":0},"west":{"uv":[48,16,64,30],"texture":0},"up":{"uv":[48,16,16,0],"texture":0},"down":{"uv":[80,0,48,16],"texture":0}},"type":"cube","uuid":"937f44ad-7716-a358-b30f-6835d5d06ef6"}],"outliner":[{"name":"bone","origin":[-7,6,0],"color":0,"uuid":"428f1f9e-e4b2-7c5c-065b-40b7286eed4a","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"selected":false,"children":["937f44ad-7716-a358-b30f-6835d5d06ef6"]},{"name":"bone2","origin":[-17,18,0],"color":0,"uuid":"bcfb751a-5b73-7ffc-1692-1a4a99ecaaa0","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"selected":false,"children":["7141d37a-992c-8b3d-c86d-1dd3baa85c78"]}],"textures":[{"path":"/home/jika/Projects/gt/ibg/src/main/resources/assets/ibg/textures/block/lathe_overlay.png","name":"lathe_overlay.png","folder":"block","namespace":"","id":"0","group":"","width":128,"height":128,"uv_width":128,"uv_height":128,"particle":true,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","render_mode":"default","render_sides":"auto","pbr_channel":"color","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":true,"uuid":"0940fe30-d3a9-4a87-ed7b-9acbdb7bea56","relative_path":"../src/main/resources/assets/ibg/textures/block/lathe_overlay.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABHNCSVQICAgIfAhkiAAAAAFzUkdCAK7OHOkAAAMdSURBVHhe7Zs9SkNBFEZfQFBIbwIRURTcgr2LcAluxlhoZZUV2LmIYJ1GEPxBIRHbFFaaJ76ghUXehZmRc9Lfmfm+Ofnmvkxepwp+riePH8EhQuWj4UWoPlp8NTrtRMfIWR9efA3A4f5WFg3ju+eqBmDQ62eZ/2U2rQRAAMJfoiz0fk8aXrwJ4BHgEZDzKxyc2wQIGGgPsDDPI8AjwCMgkCK5Sz0CAjvgEeAR4O8A9gD2APYAgWMkd6k9QGAH7AHsAewB7AHsAbwODhwjuUs7R9NhaAP7k5OsGi5vzkPzrx2/heqjxRt7Z+E+LLKGLwAOe5utxhjPXqsagJ1+t1V9tOhhOq9qALq7262Gmt8/VTUA64ODVvXRoveX20oAAi4KQMC85v8AJoAJ4BHgEWAPEA/T1UewB1jds18V9gBBAxflPgX4FOBjoI+B/g4Qz9IWI9gDtDDtZ4k9QNBAewB/CbQJtAn0MigepO1HyH4X0Cy9ecu3edv2v7/02H5LWJXLq0gBYG18o3b5f4DmXr+5X2/uyXNHFHNb0qkWgHReFzmTABS5LekWJQDpvC5yJgEoclvSLUoA0nld5EwCUOS2pFuUAKTzusiZBKDIbUm3KAFI53WRMwlAkduSblFZX0tKJ9OZ/nJAAOBsCIAAwB2AyzcBBADuAFy+CSAAcAfg8k0AAYA7AJdvAggA3AG4fBNAAOAOwOWbAAIAdwAu3wQQALgDcPkmgADAHYDLNwEEAO4AXL4JIABwB+DyTQABgDsAl28CCADcAbh8E0AA4A7A5ZsAAgB3AC7fBBAAuANw+SaAAMAdgMs3AQQA7gBcvgkgAHAH4PJNAAGAOwCXbwIIANwBuHwTQADgDsDlmwACAHcALt8EEAC4A3D5JoAAwB2AyzcBBADuAFy+CSAAcAfg8k0AAYA7AJdvAggA3AG4fBNAAOAOwOWbAAIAdwAu3wQQALgDcPkmgADAHYDLNwEEAO4AXL4JIABwB+DyTQABgDsAl28CCADcAbh8E0AA4A7A5ZsAAgB3AC7fBBAAuANw+SaAAMAdgMs3AeAAfAJCWyqfkCdYUQAAAABJRU5ErkJggg=="},{"path":"/home/jika/Projects/gt/ibg/src/main/resources/assets/ibg/textures/block/lathe.png","name":"lathe.png","folder":"block","namespace":"","id":"1","group":"","width":128,"height":128,"uv_width":128,"uv_height":128,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","render_mode":"default","render_sides":"auto","pbr_channel":"color","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":true,"uuid":"3707482b-6125-b672-1035-e8b10449f811","relative_path":"../src/main/resources/assets/ibg/textures/block/lathe.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABHNCSVQICAgIfAhkiAAAAAFzUkdCAK7OHOkAAALTSURBVHhe7ZihUWQBFATZqhOEgCeUC4IQSAYQoE4RAY4o0CSAQ5ADFJ8q1InWPb3m19Yf0zO9T+zprM90A6dp+uDPEmBcggRIgPEGxvG7AAkw3sA4fhcgAcYbGMfvAiTAeAPj+F2ABBhvYBy/C5AA4w2M43cBEmC8gXH8LkACjDcwjt8FSIDxBsbxuwAJMN7AOH4XIAHGGxjH7wIkwHgD4/hdgAQYb2AcvwuQAD8NPL++fX4/H28fju9PjzfJMSDH78gJMLD2fxBPf99vj1/+xev18frfy/3x/HP1cTzPL++6BGI3EkA8LkFLANKSOJMA4nEJWgKQlsSZBBCPS9ASgLQkziSAeFyClgCkJXEmAcTjErQEIC2JM/3NKx6XoCUAaUmcSQDxuAQtAUhL4kwCiMclaAlAWhJnEkA8LkFLANKSOJMA4nEJWgKQlsSZBBCPS9ASgLQkziSAeFyClgCkJXEmAcTjErQEIC2JMwkgHpegJQBpSZxJAPG4BC0BSEviTAKIxyVoCUBaEmcSQDwuQUsA0pI4kwDicQlaApCWxJkEEI9L0BKAtCTOJIB4XIKWAKQlcSYBxOMStAQgLYkzCSAel6AlAGlJnEkA8bgELQFIS+JMAojHJWgJQFoSZxJAPC5BSwDSkjiTAOJxCVoCkJbEmQQQj0vQEoC0JM4kgHhcgpYApCVxJgHE4xK0BCAtiTMJIB6XoCUAaUmcSQDxuAQtAUhL4kwCiMclaAlAWhJnEkA8LkFLANKSOJMA4nEJWgKQlsSZBBCPS9ASgLQkziSAeFyClgCkJXEmAcTjErQEIC2JMwkgHpegJQBpSZxJAPG4BC0BSEviTAKIxyVoCUBaEmcSQDwuQUsA0pI4kwDicQlaApCWxJkEEI9L0BKAtCTOJIB4XIKWAKQlcSYBxOMStAQgLYkzCSAel6AlAGlJnEkA8bgELQFIS+JMAojHJWhfrQJmgRuLWtwAAAAASUVORK5CYII="}],"animations":[{"uuid":"d0f5e957-f0c8-cd4c-fb8d-7dffc499601d","name":"idle","loop":"loop","override":false,"length":0.25,"snapping":24,"selected":false,"saved":true,"path":"/home/jika/Documents/mc/animated_block/animations/animated_block.animation.json","anim_time_update":"","blend_weight":"","start_delay":"","loop_delay":"","animators":{"bcfb751a-5b73-7ffc-1692-1a4a99ecaaa0":{"name":"bone2","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":"0","y":"0","z":"0"}],"uuid":"ea9857fb-0989-8369-5216-46906cd0487c","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":"180","y":"\n","z":"0"}],"uuid":"420400a2-62af-f264-0c52-d49a02e47d88","time":0.125,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":"360","y":"0","z":"0"}],"uuid":"434a4408-8e86-a447-9aaa-066fed113dd1","time":0.25,"color":-1,"interpolation":"linear"}]}}}]} \ No newline at end of file diff --git a/src/generated/resources/assets/ibg/textures/block/ev_lathe.png b/src/generated/resources/assets/ibg/textures/block/ev_lathe.png new file mode 100644 index 0000000..33ae955 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/ev_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/hv_lathe.png b/src/generated/resources/assets/ibg/textures/block/hv_lathe.png new file mode 100644 index 0000000..2714d7b Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/hv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/iv_lathe.png b/src/generated/resources/assets/ibg/textures/block/iv_lathe.png new file mode 100644 index 0000000..fe0352e Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/iv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/luv_lathe.png b/src/generated/resources/assets/ibg/textures/block/luv_lathe.png new file mode 100644 index 0000000..1fedb08 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/luv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/lv_lathe.png b/src/generated/resources/assets/ibg/textures/block/lv_lathe.png new file mode 100644 index 0000000..d92544f Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/lv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/max_lathe.png b/src/generated/resources/assets/ibg/textures/block/max_lathe.png new file mode 100644 index 0000000..73d7657 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/max_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/mv_lathe.png b/src/generated/resources/assets/ibg/textures/block/mv_lathe.png new file mode 100644 index 0000000..723162a Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/mv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/opv_lathe.png b/src/generated/resources/assets/ibg/textures/block/opv_lathe.png new file mode 100644 index 0000000..ad9730c Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/opv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/uev_lathe.png b/src/generated/resources/assets/ibg/textures/block/uev_lathe.png new file mode 100644 index 0000000..65ff33b Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/uev_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/uhv_lathe.png b/src/generated/resources/assets/ibg/textures/block/uhv_lathe.png new file mode 100644 index 0000000..e0ab630 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/uhv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/uiv_lathe.png b/src/generated/resources/assets/ibg/textures/block/uiv_lathe.png new file mode 100644 index 0000000..dd3c101 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/uiv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/uv_lathe.png b/src/generated/resources/assets/ibg/textures/block/uv_lathe.png new file mode 100644 index 0000000..6a4b97c Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/uv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/uxv_lathe.png b/src/generated/resources/assets/ibg/textures/block/uxv_lathe.png new file mode 100644 index 0000000..1cec370 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/uxv_lathe.png differ diff --git a/src/generated/resources/assets/ibg/textures/block/zpm_lathe.png b/src/generated/resources/assets/ibg/textures/block/zpm_lathe.png new file mode 100644 index 0000000..5c762a3 Binary files /dev/null and b/src/generated/resources/assets/ibg/textures/block/zpm_lathe.png differ diff --git a/src/main/java/com/imbgt/ibg/IBG.java b/src/main/java/com/imbgt/ibg/IBG.java index 2f825ba..ff82e76 100644 --- a/src/main/java/com/imbgt/ibg/IBG.java +++ b/src/main/java/com/imbgt/ibg/IBG.java @@ -4,6 +4,7 @@ import com.imbgt.ibg.block.MachineSets; import com.imbgt.ibg.block.ModBlocks; import com.imbgt.ibg.block.entity.ModBlockEntities; import com.imbgt.ibg.block.entity.client.AnimatedBlockRenderer; +import com.imbgt.ibg.datagen.TierTextureBakeProvider; import com.gregtechceu.gtceu.api.machine.MachineDefinition; import com.gregtechceu.gtceu.api.registry.GTRegistries; @@ -11,6 +12,7 @@ import com.gregtechceu.gtceu.api.registry.GTRegistries; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -61,4 +63,15 @@ public class IBG { }); } } + + @Mod.EventBusSubscriber(modid = IBG.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) + public final class DataGenHook { + + @SubscribeEvent + public static void gather(GatherDataEvent e) { + var out = e.getGenerator().getPackOutput(); + var ef = e.getExistingFileHelper(); + e.getGenerator().addProvider(e.includeClient(), new TierTextureBakeProvider(out, ef)); + } + } } diff --git a/src/main/java/com/imbgt/ibg/block/MachineSets.java b/src/main/java/com/imbgt/ibg/block/MachineSets.java index 9e59243..de5ddae 100644 --- a/src/main/java/com/imbgt/ibg/block/MachineSets.java +++ b/src/main/java/com/imbgt/ibg/block/MachineSets.java @@ -12,7 +12,7 @@ import java.util.List; @UtilityClass public final class MachineSets { - public static final String NS = "gtceu"; + public final String NS = "gtceu"; public record Definition(String suffix, FootprintSpec spec) { @@ -21,7 +21,7 @@ public final class MachineSets { } } - public static final List DEFINITIONS = List.of( + public final List DEFINITIONS = List.of( new Definition( "lathe", FootprintSpec.builder() @@ -31,17 +31,17 @@ public final class MachineSets { .build())); /** Does this machine belong to any configured family? */ - public static boolean matches(ResourceLocation id) { + public boolean matches(ResourceLocation id) { return DEFINITIONS.stream().anyMatch(f -> f.matches(id)); } /** The footprint spec for this machine, or null. */ - public static FootprintSpec getSpec(ResourceLocation id) { + public FootprintSpec getSpec(ResourceLocation id) { return DEFINITIONS.stream().filter(f -> f.matches(id)).map(Definition::spec).findFirst().orElse(null); } /** Asset key (filename stem) for this machine, or fallback to last segment. */ - public static String assetKeyFor(ResourceLocation id) { + public String assetKeyFor(ResourceLocation id) { return DEFINITIONS.stream().filter(f -> f.matches(id)).map(Definition::suffix).findFirst() .orElseGet(() -> { var p = id.getPath(); diff --git a/src/main/java/com/imbgt/ibg/block/entity/client/AnimatedBlockModel.java b/src/main/java/com/imbgt/ibg/block/entity/client/AnimatedBlockModel.java index c3daad2..f3fd85e 100644 --- a/src/main/java/com/imbgt/ibg/block/entity/client/AnimatedBlockModel.java +++ b/src/main/java/com/imbgt/ibg/block/entity/client/AnimatedBlockModel.java @@ -28,8 +28,11 @@ public class AnimatedBlockModel extends GeoModel { @Override public ResourceLocation getTextureResource(T anim) { - String key = keyFrom(anim); - return new ResourceLocation(IBG.MOD_ID, "textures/block/" + key + ".png"); + if (anim instanceof MetaMachineBlockEntity mme) { + var id = mme.getMetaMachine().getDefinition().getId(); + return new ResourceLocation(IBG.MOD_ID, "textures/block/" + id.getPath() + ".png"); + } + return new ResourceLocation("ibg", "textures/block/fallback.png"); } @Override diff --git a/src/main/java/com/imbgt/ibg/datagen/TierTextureBakeProvider.java b/src/main/java/com/imbgt/ibg/datagen/TierTextureBakeProvider.java new file mode 100644 index 0000000..e59e29d --- /dev/null +++ b/src/main/java/com/imbgt/ibg/datagen/TierTextureBakeProvider.java @@ -0,0 +1,232 @@ +// src/main/java/com/imbgt/ibg/datagen/TierTextureBakeProvider.java +package com.imbgt.ibg.datagen; + +import com.imbgt.ibg.block.MachineSets; + +import com.gregtechceu.gtceu.api.GTValues; + +import net.minecraft.Util; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraftforge.common.data.ExistingFileHelper; + +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; +import com.google.gson.*; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.*; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import javax.imageio.ImageIO; + +public final class TierTextureBakeProvider implements DataProvider { + + private record TierTiles(BufferedImage side, BufferedImage top, BufferedImage bottom) {} + + private final PackOutput out; + private final ExistingFileHelper ef; + + public TierTextureBakeProvider(PackOutput out, ExistingFileHelper ef) { + this.out = out; + this.ef = ef; + } + + @Override + public String getName() { + return "IBG tier texture baker"; + } + + @Override + public CompletableFuture run(CachedOutput cache) { + return CompletableFuture.runAsync(() -> { + try { + for (var def : MachineSets.DEFINITIONS) { + String key = def.suffix(); + for (int tierId = GTValues.LV; tierId <= GTValues.MAX; tierId++) { + String tier = GTValues.VN[tierId].toLowerCase(Locale.ROOT); + + JsonObject geo = readJson("ibg", "geo/" + key + ".geo.json"); + + JsonObject geometry0 = geo.getAsJsonArray("minecraft:geometry").get(0).getAsJsonObject(); + JsonObject description = geometry0.getAsJsonObject("description"); + int atlasW = description.get("texture_width").getAsInt(); + int atlasH = description.get("texture_height").getAsInt(); + + BufferedImage atlas = new BufferedImage(atlasW, atlasH, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = atlas.createGraphics(); + + TierTiles tiles = loadTierTiles("gtceu", tier) + .orElseThrow( + () -> new FileNotFoundException("Missing GTCEu casing tiles for tier " + tier)); + + paintCasingFromGeo(g, tiles, geo); + + BufferedImage overlay = tryReadPng("ibg", "textures/block/" + key + ".png"); + if (overlay != null) + g.drawImage(overlay, 0, 0, null); + g.dispose(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(atlas, "PNG", baos); + byte[] bytes = baos.toByteArray(); + HashCode hash = Hashing.sha256().hashBytes(bytes); + + Path dst = out.getOutputFolder() + .resolve("assets/ibg/textures/block/" + tier + "_" + + key + ".png"); + + // No need to create directories manually; writeIfNeeded will. + cache.writeIfNeeded(dst, bytes, hash); + } + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }, Util.backgroundExecutor()); + } + + // ---------- resource helpers ---------- + private JsonObject readJson(String ns, String path) throws IOException { + try (InputStream is = open(ns, path).orElseThrow(() -> new FileNotFoundException(ns + ":" + path))) { + return JsonParser.parseReader(new InputStreamReader(is)).getAsJsonObject(); + } + } + + private BufferedImage tryReadPng(String ns, String path) throws IOException { + var opt = open(ns, path); + if (opt.isEmpty()) + return null; + try (InputStream is = opt.get()) { + return ImageIO.read(is); + } + } + + private Optional loadTierTiles(String ns, String tier) throws IOException { + String base = "textures/block/casings/voltage/" + tier + "/"; + BufferedImage side = tryReadPng(ns, base + "side.png"); + BufferedImage top = tryReadPng(ns, base + "top.png"); + BufferedImage bot = tryReadPng(ns, base + "bottom.png"); + if (side != null && top != null && bot != null) + return Optional.of(new TierTiles(side, top, bot)); + return Optional.empty(); + } + + private Optional open(String ns, String path) throws IOException { + try { + var rl = new ResourceLocation(ns, path); + var res = ef.getResource(rl, PackType.CLIENT_RESOURCES); + if (res != null) + return Optional.of(res.open()); + } catch (FileNotFoundException e) { + String cpPath = "assets/" + ns + "/" + path; + var cl = Thread.currentThread().getContextClassLoader(); + InputStream is = cl.getResourceAsStream(cpPath); + return Optional.ofNullable(is); + } + return Optional.empty(); + } + + // ---------- painting ---------- + private static void paintTile(Graphics2D g, BufferedImage tile, int x, int y, int w, int h) { + int tw0 = tile.getWidth(); + int th0 = tile.getHeight(); + for (int yy = 0; yy < h; yy += th0) { + for (int xx = 0; xx < w; xx += tw0) { + int tw = Math.min(tw0, w - xx); + int th = Math.min(th0, h - yy); + g.drawImage(tile, x + xx, y + yy, x + xx + tw, y + yy + th, 0, 0, tw, th, null); + } + } + } + + private static void paintFace(Graphics2D g, BufferedImage tile, int atlasW, int atlasH, + int u, int v, int us, int vs) { + int x0 = us >= 0 ? u : u + us; + int y0 = vs >= 0 ? v : v + vs; + int w = Math.abs(us); + int h = Math.abs(vs); + // clamp to atlas + if (x0 < 0) { + w += x0; + x0 = 0; + } + if (y0 < 0) { + h += y0; + y0 = 0; + } + if (x0 >= atlasW || y0 >= atlasH || w <= 0 || h <= 0) + return; + if (x0 + w > atlasW) + w = atlasW - x0; + if (y0 + h > atlasH) + h = atlasH - y0; + + paintTile(g, tile, x0, y0, w, h); + } + + private void paintCasingFromGeo(Graphics2D g, TierTiles tiles, JsonObject geo) { + var geos = geo.getAsJsonArray("minecraft:geometry"); + if (geos == null) + return; + + // atlas size from description + JsonObject description = geos.get(0).getAsJsonObject().getAsJsonObject("description"); + int atlasW = description.get("texture_width").getAsInt(); + int atlasH = description.get("texture_height").getAsInt(); + + for (var ge : geos) { + var bones = ge.getAsJsonObject().getAsJsonArray("bones"); + if (bones == null) + continue; + + for (var bEl : bones) { + var cubes = bEl.getAsJsonObject().getAsJsonArray("cubes"); + if (cubes == null || !bEl.getAsJsonObject().get("name").getAsString().equals("bone")) + continue; + + for (var cEl : cubes) { + var cube = cEl.getAsJsonObject(); + + if (cube.has("uv") && cube.get("uv").isJsonObject()) { + var uv = cube.getAsJsonObject("uv"); + for (var e : uv.entrySet()) { + String face = e.getKey(); // north/east/south/west/up/down + var f = e.getValue().getAsJsonObject(); + int u = f.getAsJsonArray("uv").get(0).getAsInt(); + int v = f.getAsJsonArray("uv").get(1).getAsInt(); + int us = f.getAsJsonArray("uv_size").get(0).getAsInt(); + int vs = f.getAsJsonArray("uv_size").get(1).getAsInt(); + + BufferedImage tile = switch (face) { + case "up" -> tiles.top(); + case "down" -> tiles.bottom(); + default -> tiles.side(); + }; + paintFace(g, tile, atlasW, atlasH, u, v, us, vs); + } + } else if (cube.has("uv") && cube.get("uv").isJsonArray() && cube.has("size")) { + // Better fallback: use cube sizes per face like Bedrock layout + var size = cube.getAsJsonArray("size"); + int sx = size.get(0).getAsInt(); + int sy = size.get(1).getAsInt(); + int sz = size.get(2).getAsInt(); + + int u = cube.getAsJsonArray("uv").get(0).getAsInt(); + int v = cube.getAsJsonArray("uv").get(1).getAsInt(); + + // Minimal conservative mapping: fill a sx×sy area with side tile at (u,v) + paintFace(g, tiles.side(), atlasW, atlasH, u, v, sx, sy); + } + } + } + } + } +} diff --git a/src/main/java/com/imbgt/ibg/mixin/MetaMachineBlockEntityGeoMixin.java b/src/main/java/com/imbgt/ibg/mixin/MetaMachineBlockEntityGeoMixin.java index a0da5f9..78694b7 100644 --- a/src/main/java/com/imbgt/ibg/mixin/MetaMachineBlockEntityGeoMixin.java +++ b/src/main/java/com/imbgt/ibg/mixin/MetaMachineBlockEntityGeoMixin.java @@ -8,8 +8,6 @@ import com.gregtechceu.gtceu.api.capability.IWorkable; import com.gregtechceu.gtceu.api.capability.forge.GTCapability; import com.gregtechceu.gtceu.api.machine.MetaMachine; -import net.minecraftforge.common.util.LazyOptional; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -41,16 +39,13 @@ public abstract class MetaMachineBlockEntityGeoMixin implements GeoBlockEntity { @Unique private static boolean ibg$isActuallyRunning(MetaMachine m) { - // Manually enabled? boolean enabled = MetaMachineBlockEntity.getCapability(m, GTCapability.CAPABILITY_CONTROLLABLE, null) .map(IControllable::isWorkingEnabled).orElse(true); - boolean active = MetaMachineBlockEntity.getCapability(m, GTCapability.CAPABILITY_WORKABLE, null) .map(IWorkable::isActive).orElse(false); return enabled && active; - } @Unique diff --git a/src/main/resources/assets/ibg/blockstates/lathe.json b/src/main/resources/assets/ibg/blockstates/lathe.json deleted file mode 100644 index 097eecf..0000000 --- a/src/main/resources/assets/ibg/blockstates/lathe.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "ibg:block/animated_block" } - } -} diff --git a/src/main/resources/assets/ibg/geo/lathe.geo.json b/src/main/resources/assets/ibg/geo/lathe.geo.json index 7a2fccc..8089dec 100644 --- a/src/main/resources/assets/ibg/geo/lathe.geo.json +++ b/src/main/resources/assets/ibg/geo/lathe.geo.json @@ -13,17 +13,27 @@ "bones": [ { "name": "bone", - "pivot": [17, 18, 0], + "pivot": [7, 6, 0], "cubes": [ - {"origin": [-7, 1, -7], "size": [30, 12, 14], "inflate": 1, "uv": [0, 0]} + { + "origin": [-8, 0, -8], + "size": [32, 14, 16], + "uv": { + "north": {"uv": [16, 16], "uv_size": [32, 14]}, + "east": {"uv": [0, 16], "uv_size": [16, 14]}, + "south": {"uv": [64, 16], "uv_size": [32, 14]}, + "west": {"uv": [48, 16], "uv_size": [16, 14]}, + "up": {"uv": [16, 0], "uv_size": [32, 16]}, + "down": {"uv": [48, 16], "uv_size": [32, -16]} + } + } ] }, { "name": "bone2", - "parent": "bone", "pivot": [17, 18, 0], "cubes": [ - {"origin": [-8, 7, -1], "size": [2, 11, 2], "pivot": [-7, 18, 0], "rotation": [-90, -90, 0], "uv": [0, 26]} + {"origin": [-8, 7, -1], "size": [2, 11, 2], "pivot": [-7, 18, 0], "rotation": [-90, -90, 0], "uv": [0, 30]} ] } ] diff --git a/src/main/resources/assets/ibg/textures/block/lathe.png b/src/main/resources/assets/ibg/textures/block/lathe.png index 4f4350f..6f072b6 100644 Binary files a/src/main/resources/assets/ibg/textures/block/lathe.png and b/src/main/resources/assets/ibg/textures/block/lathe.png differ diff --git a/src/main/resources/assets/ibg/textures/block/lathe_overlay.png b/src/main/resources/assets/ibg/textures/block/lathe_overlay.png new file mode 100644 index 0000000..8039496 Binary files /dev/null and b/src/main/resources/assets/ibg/textures/block/lathe_overlay.png differ