Generalized machine replacement

This commit is contained in:
2025-08-16 16:03:24 +02:00
parent 188ab3ffe3
commit ed463a49e0
12 changed files with 101 additions and 65 deletions

View File

@@ -1,18 +1,14 @@
package com.imbgt.ibg;
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.util.FootprintSpec;
import com.imbgt.ibg.util.Footprints;
import com.gregtechceu.gtceu.api.machine.MachineDefinition;
import com.gregtechceu.gtceu.api.registry.GTRegistries;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.server.ServerStartingEvent;
@@ -52,16 +48,7 @@ public class IBG {
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
private void commonSetup(final FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
Footprints.register(new ResourceLocation("gtceu", "lv_lathe"),
FootprintSpec.builder()
.addPart(-1, 0, 0)
.masterOutline(Shapes.box(0, 0, 0, 1, 14. / 16., 1))
.partOutline(Shapes.box(0, 0, 0, 1, 14. / 16., 1))
.build());
});
}
private void commonSetup(final FMLCommonSetupEvent event) {}
@SubscribeEvent
public void onServerStarting(ServerStartingEvent event) {}
@@ -72,14 +59,17 @@ public class IBG {
@SubscribeEvent
public static void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
var latheDef = GTRegistries.MACHINES.get(
new ResourceLocation("gtceu", "lv_lathe"));
@SuppressWarnings({ "unchecked", "rawtypes" })
BlockEntityRendererProvider<BlockEntity> provider = (BlockEntityRendererProvider) (ctx -> new AnimatedBlockRenderer<>(
ctx));
for (MachineDefinition def : GTRegistries.MACHINES) {
if (!MachineSets.matches(def.getId())) {
continue;
}
BlockEntityRenderers.register(def.getBlockEntityType(),
ctx -> new AnimatedBlockRenderer(ctx));
}
BlockEntityRenderers.register(latheDef.getBlockEntityType(), provider);
});
}
}

View File

@@ -0,0 +1,51 @@
package com.imbgt.ibg.block;
import com.imbgt.ibg.util.FootprintSpec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.shapes.Shapes;
import java.util.List;
public final class MachineSets {
public static final String NS = "gtceu";
public record Definition(String suffix, FootprintSpec spec) {
public boolean matches(ResourceLocation id) {
return id.getNamespace().equals(NS) && id.getPath().endsWith("_" + suffix);
}
}
public static final List<Definition> DEFINITIONS = List.of(
new Definition(
"lathe",
FootprintSpec.builder()
.addPart(-1, 0, 0)
.masterOutline(Shapes.box(0, 0, 0, 1, 14.0 / 16.0, 1))
.partOutline(Shapes.box(0, 0, 0, 1, 14.0 / 16.0, 1))
.build()));
private MachineSets() {}
/** Does this machine belong to any configured family? */
public static 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) {
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) {
return DEFINITIONS.stream().filter(f -> f.matches(id)).map(Definition::suffix).findFirst()
.orElseGet(() -> {
var p = id.getPath();
int i = p.indexOf('_');
return i >= 0 ? p.substring(i + 1) : p;
});
}
}

View File

@@ -1,6 +1,9 @@
package com.imbgt.ibg.block.custom;
import com.imbgt.ibg.block.MachineSets;
import com.imbgt.ibg.block.entity.PartBE;
import com.imbgt.ibg.util.FootprintSpec;
import com.imbgt.ibg.util.Footprints;
import com.gregtechceu.gtceu.api.block.MetaMachineBlock;
import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity;
@@ -179,7 +182,7 @@ public class PartBlock extends Block implements EntityBlock {
Direction facing = masterState.getValue(rot.property);
// Validate against the full footprint
FootprintSpec spec = Footprints.get(mm.getDefinition().getId());
FootprintSpec spec = MachineSets.getSpec(mm.getDefinition().getId());
if (spec == null) return;
boolean isExpected = Footprints.partPositions(master, facing, spec).contains(pos);

View File

@@ -1,6 +1,9 @@
package com.imbgt.ibg.block.entity.client;
import com.imbgt.ibg.IBG;
import com.imbgt.ibg.block.MachineSets;
import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity;
import net.minecraft.resources.ResourceLocation;
@@ -9,18 +12,29 @@ import software.bernie.geckolib.model.GeoModel;
public class AnimatedBlockModel<T extends GeoAnimatable> extends GeoModel<T> {
@Override
public ResourceLocation getModelResource(T animatable) {
return new ResourceLocation(IBG.MOD_ID, "geo/animated_block.geo.json");
private String keyFrom(T animatable) {
if (animatable instanceof MetaMachineBlockEntity mme) {
var id = mme.getMetaMachine().getDefinition().getId();
return MachineSets.assetKeyFor(id);
}
return "unknown";
}
@Override
public ResourceLocation getTextureResource(T animatable) {
return new ResourceLocation(IBG.MOD_ID, "textures/block/animated_block.png");
public ResourceLocation getModelResource(T anim) {
String key = keyFrom(anim);
return new ResourceLocation(IBG.MOD_ID, "geo/" + key + ".geo.json");
}
@Override
public ResourceLocation getAnimationResource(T animatable) {
return new ResourceLocation(IBG.MOD_ID, "animations/animated_block.animation.json");
public ResourceLocation getTextureResource(T anim) {
String key = keyFrom(anim);
return new ResourceLocation(IBG.MOD_ID, "textures/block/" + key + ".png");
}
@Override
public ResourceLocation getAnimationResource(T anim) {
String key = keyFrom(anim);
return new ResourceLocation(IBG.MOD_ID, "animations/" + key + ".animation.json");
}
}

View File

@@ -1,5 +1,7 @@
package com.imbgt.ibg.mixin;
import com.imbgt.ibg.block.MachineSets;
import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity;
import com.gregtechceu.gtceu.api.capability.IWorkable;
import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
@@ -41,8 +43,7 @@ public abstract class MetaMachineBlockEntityGeoMixin implements GeoBlockEntity {
MetaMachine machine = this.getMetaMachine();
// Only animate the lathe
var defId = machine.getDefinition().getId();
if (!"gtceu".equals(defId.getNamespace()) || !"lv_lathe".equals(defId.getPath())) {
if (!MachineSets.matches(machine.getDefinition().getId())) {
state.getController().forceAnimationReset();
return PlayState.STOP;
}

View File

@@ -1,5 +1,6 @@
package com.imbgt.ibg.mixin;
import com.imbgt.ibg.block.MachineSets;
import com.imbgt.ibg.block.ModBlocks;
import com.imbgt.ibg.block.entity.PartBE;
import com.imbgt.ibg.util.Footprints;
@@ -40,25 +41,24 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
@Inject(method = "getRenderShape", at = @At("HEAD"), cancellable = true)
private void ibg$forceAnimatedRender(BlockState state, CallbackInfoReturnable<RenderShape> cir) {
if (getDefinition().getId().toString().equals("gtceu:lv_lathe")) {
if (MachineSets.matches(this.getDefinition().getId())) {
cir.setReturnValue(RenderShape.ENTITYBLOCK_ANIMATED);
}
}
@Override
public VoxelShape getOcclusionShape(BlockState state, BlockGetter level, BlockPos pos) {
if (getDefinition().getId().toString().equals("gtceu:lv_lathe")) {
if (MachineSets.matches(this.getDefinition().getId())) {
return Shapes.empty(); // equivalent to Properties.noOcclusion()
}
return super.getOcclusionShape(state, level, pos);
}
@Inject(method = "getStateForPlacement", at = @At("HEAD"), cancellable = true)
private void ibg$latheFootprintCheck(BlockPlaceContext ctx,
CallbackInfoReturnable<BlockState> cir) {
MetaMachineBlock self = (MetaMachineBlock) (Object) this;
var id = self.getDefinition().getId();
if (!("gtceu".equals(id.getNamespace()) && "lv_lathe".equals(id.getPath())))
private void ibg$footprintCheck(BlockPlaceContext ctx,
CallbackInfoReturnable<BlockState> cir) {
var spec = MachineSets.getSpec(this.getDefinition().getId());
if (spec == null)
return;
Level level = ctx.getLevel();
@@ -67,9 +67,6 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
// Determine facing like MetaMachineBlock does:
Direction facing = ctx.getHorizontalDirection().getOpposite();
var spec = Footprints.get(self.getDefinition().getId());
if (spec == null)
return;
var partPositions = Footprints.partPositions(base, facing, spec);
for (BlockPos p : partPositions) {
if (!level.getBlockState(p).canBeReplaced()) {
@@ -83,8 +80,7 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
private void ibg$placePart(BlockState st, Level lvl, BlockPos pos, BlockState old, boolean moved, CallbackInfo ci) {
if (lvl.isClientSide)
return;
var id = getDefinition().getId();
var spec = Footprints.get(id);
var spec = MachineSets.getSpec(this.getDefinition().getId());
if (spec == null)
return;
var rot = ((IMachineBlock) (Object) this).getRotationState();
@@ -105,8 +101,7 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
CallbackInfo ci) {
if (lvl.isClientSide || st.getBlock() == newState.getBlock())
return;
var id = getDefinition().getId();
var spec = com.imbgt.ibg.util.Footprints.get(id);
var spec = MachineSets.getSpec(this.getDefinition().getId());
if (spec == null)
return;
var rot = ((IMachineBlock) (Object) this).getRotationState();
@@ -122,7 +117,7 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
@Inject(method = "getShape", at = @At("HEAD"), cancellable = true)
private void ibg$combinedOutline(BlockState state, BlockGetter level, BlockPos pos,
CollisionContext ctx, CallbackInfoReturnable<VoxelShape> cir) {
var spec = com.imbgt.ibg.util.Footprints.get(getDefinition().getId());
var spec = MachineSets.getSpec(this.getDefinition().getId());
if (spec == null)
return;
var rot = ((IMachineBlock) (Object) this).getRotationState();
@@ -130,7 +125,6 @@ public abstract class MetaMachineBlockMixin extends AppearanceBlock {
return;
var facing = state.getValue(rot.property);
var shape = Footprints.combinedOutline(facing, spec);
// var shape = Footprints.rotateOutline(spec.masterOutline(), facing);
cir.setReturnValue(shape);
}
}

View File

@@ -2,34 +2,19 @@ package com.imbgt.ibg.util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Registry + helpers to compute world positions and a continuous outline shape.
*/
public final class Footprints {
private static final Map<ResourceLocation, FootprintSpec> REG = new HashMap<>();
private Footprints() {}
/** Register or replace a footprint for a machine id. Call during setup. */
public static void register(ResourceLocation machineId, FootprintSpec spec) {
REG.put(machineId, spec);
}
/** @return null when no footprint registered. */
public static FootprintSpec get(ResourceLocation machineId) {
return REG.get(machineId);
}
/** All part world positions for a given master and facing. */
public static List<BlockPos> partPositions(BlockPos master, Direction facing, FootprintSpec spec) {
return spec.parts().stream()

View File

@@ -1,4 +1,2 @@
{
"item.ibg.lathe": "Lathe",
"block.ibg.animated_block": "Animated Block"
}

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B