pala M-grinder-3: BE dediee + GUI + jauge fuel (diagnostic deplace bloc)

This commit is contained in:
Anaïs Saraiva
2026-10-19 03:18:29 +02:00
parent 41f4ff8f0a
commit baf29d5c11
7 changed files with 163 additions and 12 deletions
+6
View File
@@ -557,6 +557,12 @@ avant M4 (TODO:crafts-machines).
20F/5C/1B/1L recalcules, 4 rotations, lave source exigee) + diagnostic clic droit sur le 20F/5C/1B/1L recalcules, 4 rotations, lave source exigee) + diagnostic clic droit sur le
coeur. GUI + tetes + modifieurs : M-grinder-3. VERIFIE : build SUCCESSFUL, boot Done, coeur. GUI + tetes + modifieurs : M-grinder-3. VERIFIE : build SUCCESSFUL, boot Done,
0 erreur. UNVERIFIED : orientation exacte du B (tableau wiki ambigu). 0 erreur. UNVERIFIED : orientation exacte du B (tableau wiki ambigu).
- M-grinder-3 LIVRE 2026-10-19 ~03:20 : BE dediee PalaGrinderBlockEntity (inventaire 9 slots,
jauge fuel 0-100 en lingots paladium, persistee) + GUI DispenserMenu + coeur avec ticker +
diagnostic deplace dans useWithoutItem (le callback UseBlockCallback ne doit pas renvoyer
SUCCESS sinon la GUI ne s'ouvre pas — lecon). Tetes + modifieurs : M-grinder-4 (pas de
textures legacy pour les tetes). VERIFIE : build SUCCESSFUL, boot Done, 0 erreur.
UNVERIFIED en jeu (GUI + fuel).
- Client/mod : boucle visuelle OPERATIONNELLE 2026-10-19 (Xvfb :99 + runClient SDL x11 + - Client/mod : boucle visuelle OPERATIONNELLE 2026-10-19 (Xvfb :99 + runClient SDL x11 +
captures Java Robot + pilotage xdotool + vision_analyze) : menu, Select World, monde New World captures Java Robot + pilotage xdotool + vision_analyze) : menu, Select World, monde New World
(creatif, cheats), /give, pose de bloc, inventaire, F3+T. Screens : scratch vis*.png. (creatif, cheats), /give, pose de bloc, inventaire, F3+T. Screens : scratch vis*.png.
@@ -1,5 +1,6 @@
package fr.surviepote.pala; package fr.surviepote.pala;
import fr.surviepote.pala.machine.PalaGrinderBlockEntity;
import fr.surviepote.pala.machine.PalaMachineBlockEntity; import fr.surviepote.pala.machine.PalaMachineBlockEntity;
import java.util.Set; import java.util.Set;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
@@ -14,11 +15,16 @@ public final class PalaBlockEntities {
} }
public static BlockEntityType<PalaMachineBlockEntity> MACHINE; public static BlockEntityType<PalaMachineBlockEntity> MACHINE;
public static BlockEntityType<PalaGrinderBlockEntity> GRINDER;
public static void register() { public static void register() {
MACHINE = Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, MACHINE = Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE,
Identifier.fromNamespaceAndPath("pala", "machine"), Identifier.fromNamespaceAndPath("pala", "machine"),
new BlockEntityType<>(PalaMachineBlockEntity::new, new BlockEntityType<>(PalaMachineBlockEntity::new,
Set.of(PalaBlocks.PALADIUM_CRUSHER, PalaBlocks.PALADIUM_FURNACE))); Set.of(PalaBlocks.PALADIUM_CRUSHER, PalaBlocks.PALADIUM_FURNACE)));
GRINDER = Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE,
Identifier.fromNamespaceAndPath("pala", "grinder"),
new BlockEntityType<>(PalaGrinderBlockEntity::new,
Set.of(PalaBlocks.GRINDER_BLOCK)));
} }
} }
@@ -1,5 +1,6 @@
package fr.surviepote.pala; package fr.surviepote.pala;
import fr.surviepote.pala.machine.PalaGrinderBlock;
import fr.surviepote.pala.machine.PalaMachineBlock; import fr.surviepote.pala.machine.PalaMachineBlock;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
@@ -34,8 +35,8 @@ public final class PalaBlocks {
public static final Block AMETHYST_ORE = register("amethyst_ore", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_ore")).strength(3.0F, 5.0F).sound(SoundType.STONE).requiresCorrectToolForDrops())); public static final Block AMETHYST_ORE = register("amethyst_ore", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_ore")).strength(3.0F, 5.0F).sound(SoundType.STONE).requiresCorrectToolForDrops()));
public static final Block AMETHYST_ORE_BLOCK = register("amethyst_ore_block", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_ore_block")).strength(5.0F, 8.0F).sound(SoundType.METAL).requiresCorrectToolForDrops())); public static final Block AMETHYST_ORE_BLOCK = register("amethyst_ore_block", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_ore_block")).strength(5.0F, 8.0F).sound(SoundType.METAL).requiresCorrectToolForDrops()));
// M-grinder-1 (wiki grinder §2) : 1 block + 5 casing + 20 frame + 1 lave (26 blocs). // M-grinder-1 (wiki grinder §2) : 1 block + 5 casing + 20 frame + 1 lave (26 blocs).
// Crafts M-grinder-2 ; multibloc + GUI M-grinder-2/3. // M-grinder-3 : coeur avec BE + GUI (PalaGrinderBlock).
public static final Block GRINDER_BLOCK = register("grinder_block", new Block(BlockBehaviour.Properties.of().setId(blockId("grinder_block")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops())); public static final Block GRINDER_BLOCK = register("grinder_block", new PalaGrinderBlock(BlockBehaviour.Properties.of().setId(blockId("grinder_block")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops()));
public static final Block GRINDER_CASING = register("grinder_casing", new Block(BlockBehaviour.Properties.of().setId(blockId("grinder_casing")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops())); public static final Block GRINDER_CASING = register("grinder_casing", new Block(BlockBehaviour.Properties.of().setId(blockId("grinder_casing")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops()));
public static final Block GRINDER_FRAME = register("grinder_frame", new Block(BlockBehaviour.Properties.of().setId(blockId("grinder_frame")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops())); public static final Block GRINDER_FRAME = register("grinder_frame", new Block(BlockBehaviour.Properties.of().setId(blockId("grinder_frame")).strength(5.0F, 10.0F).sound(SoundType.METAL).requiresCorrectToolForDrops()));
public static final Block AMETHYST_SPIKE = register("amethyst_spike", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_spike")).strength(1.0F, 10.0F).sound(SoundType.GRAVEL))); public static final Block AMETHYST_SPIKE = register("amethyst_spike", new Block(BlockBehaviour.Properties.of().setId(blockId("amethyst_spike")).strength(1.0F, 10.0F).sound(SoundType.GRAVEL)));
@@ -26,7 +26,6 @@ import net.fabricmc.fabric.api.event.player.UseItemCallback;
import fr.surviepote.pala.PalaBlocks; import fr.surviepote.pala.PalaBlocks;
import fr.surviepote.pala.PalaItems; import fr.surviepote.pala.PalaItems;
import fr.surviepote.pala.machine.PalaGrinder;
// Portage des procedures "clic droit" MCreator : // Portage des procedures "clic droit" MCreator :
// - batons : ProcedureHealStick/ HyperJumpStick/ SpeedStick/ StickOfGod/ StrenghStickRightClickedInAir // - batons : ProcedureHealStick/ HyperJumpStick/ SpeedStick/ StickOfGod/ StrenghStickRightClickedInAir
@@ -138,15 +137,10 @@ public final class PalaItemUseEvents {
ItemStack stack = player.getItemInHand(hand); ItemStack stack = player.getItemInHand(hand);
Item item = stack.isEmpty() ? null : stack.getItem(); Item item = stack.isEmpty() ? null : stack.getItem();
// --- Grinder : clic droit sur le coeur -> etat du multibloc (M-grinder-2). // --- Grinder : le coeur (PalaGrinderBlock) gere lui-meme le clic droit
// GUI + crafts en M-grinder-3 ; ici diagnostic seul (ne casse rien). // (diagnostic PalaGrinder.isFormed + ouverture GUI). Rien a faire ici : PASS
if (target.getBlock() == PalaBlocks.GRINDER_BLOCK) { // pour laisser useWithoutItem du bloc s'executer (un SUCCESS du callback
boolean formed = PalaGrinder.isFormed(sl, pos); // annulerait l'ouverture de la GUI).
sp.sendSystemMessage(net.minecraft.network.chat.Component.literal(formed
? "§6[Grinder] §aStructure complete (20 frames, 5 casings, lave)."
: "§6[Grinder] §cStructure incomplete (attendu : 3x3x3, voir wiki)."));
return InteractionResult.SUCCESS;
}
// --- Semis sur farmland (graine en main, dessus libre) --- // --- Semis sur farmland (graine en main, dessus libre) ---
if (target.getBlock() == Blocks.FARMLAND && item != null) { if (target.getBlock() == Blocks.FARMLAND && item != null) {
@@ -0,0 +1,59 @@
package fr.surviepote.pala.machine;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
// M-grinder-3 : bloc coeur du multibloc (avec BE persistee + GUI). Le diagnostic de
// structure (PalaGrinder.isFormed via UseBlockCallback) reste actif en parallele :
// clic droit = message d'etat + ouverture GUI.
public class PalaGrinderBlock extends Block implements EntityBlock {
public PalaGrinderBlock(Properties properties) {
super(properties);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new PalaGrinderBlockEntity(pos, state);
}
@Override
@SuppressWarnings("unchecked")
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state,
BlockEntityType<T> type) {
if (level instanceof net.minecraft.server.level.ServerLevel) {
return (lvl, pos, blockState, blockEntity) -> {
if (blockEntity instanceof PalaGrinderBlockEntity grinder) {
grinder.serverTick();
}
};
}
return null;
}
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos,
Player player, BlockHitResult hit) {
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof MenuProvider provider) {
if (player instanceof ServerPlayer sp
&& !PalaGrinder.isFormed((net.minecraft.server.level.ServerLevel) level, pos)) {
sp.sendSystemMessage(Component.literal(
"§6[Grinder] §7Structure incomplete : la forge ne fonctionnera pas."));
}
player.openMenu(provider);
}
return InteractionResult.SUCCESS;
}
}
@@ -0,0 +1,85 @@
package fr.surviepote.pala.machine;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.DispenserMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import fr.surviepote.pala.PalaBlockEntities;
import fr.surviepote.pala.PalaItems;
// M-grinder-3 (wiki grinder §3) : block entity du coeur. GUI = menu vanilla Dispenser
// (9 slots, utilises : 0 socket, 1 pattern, 2 combustible, 3 sortie ; 4-8 reserves pour
// l'assemblage tete+stick en M-grinder-4).
// Jauge 0-100 alimentee en lingots paladium (1 lingot = +10, UNVERIFIED : wiki dit "6
// paladium minimum pour une tete" sans echelle de jauge). Tetes + modifieurs en
// M-grinder-4 (pas de textures legacy pour les tetes : aucun placeholder cree).
public class PalaGrinderBlockEntity extends BlockEntity implements MenuProvider {
private static final int FUEL_PER_INGOT = 10;
private static final int FUEL_COOLDOWN_TICKS = 20;
private final SimpleContainer inventory = new SimpleContainer(9);
private int fuel;
private int fuelCooldown;
public PalaGrinderBlockEntity(BlockPos pos, BlockState state) {
super(PalaBlockEntities.GRINDER, pos, state);
}
public int fuel() {
return fuel;
}
public void serverTick() {
boolean changed = false;
if (fuelCooldown > 0) {
fuelCooldown--;
changed = true;
} else if (fuel < 100) {
ItemStack combustible = inventory.getItem(2);
if (!combustible.isEmpty() && combustible.is(PalaItems.PALADIUM_INGOT)) {
combustible.shrink(1);
fuel = Math.min(100, fuel + FUEL_PER_INGOT);
fuelCooldown = FUEL_COOLDOWN_TICKS;
changed = true;
}
}
if (changed) {
setChanged();
}
}
@Override
protected void saveAdditional(ValueOutput output) {
super.saveAdditional(output);
inventory.storeAsItemList(output.list("Items", ItemStack.CODEC));
output.putInt("Fuel", fuel);
}
@Override
protected void loadAdditional(ValueInput input) {
super.loadAdditional(input);
inventory.fromItemList(input.listOrEmpty("Items", ItemStack.CODEC));
fuel = input.getIntOr("Fuel", 0);
}
@Override
public Component getDisplayName() {
return Component.literal("Grinder (" + fuel + "/100)");
}
@Override
public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) {
return new DispenserMenu(containerId, playerInventory, inventory);
}
}
Binary file not shown.