pala M3: crusher fidele legacy (fruits/luck/auto-generate) + furnace mixed fuels + gate fermier 8

This commit is contained in:
Anaïs Saraiva
2026-10-18 23:54:37 +02:00
parent 3330b5bd04
commit 610dc597fb
4 changed files with 103 additions and 15 deletions
+14 -6
View File
@@ -154,8 +154,12 @@ BreakBlockUnderCrops* portees partiellement). Fruits + graines PORTES en items.
graines/fruits, chance nugget endium (metier fermier), cuisson eggplant→lingot amethyste (wiki minerais). graines/fruits, chance nugget endium (metier fermier), cuisson eggplant→lingot amethyste (wiki minerais).
Crusher consomme : eggplants, chervil, kiwanos, orangeblues. ECART VERIFIE (grep 2026-10-18) : Crusher consomme : eggplants, chervil, kiwanos, orangeblues. ECART VERIFIE (grep 2026-10-18) :
aucun CUSTOM:Chervil dans CUSTOM_MAPPING.json (0 match) — le chervil wiki n'existe pas dans aucun CUSTOM:Chervil dans CUSTOM_MAPPING.json (0 match) — le chervil wiki n'existe pas dans
le portage (ni item ni bloc). TODO:chervil : creer l'item/plante ou mapper vers un synonyme le portage (ni item ni bloc). TODO:chervil : TRANCHE M3 (grep+legacy) : les textures chervil.png/chervils.png sont deja
(liste des fruits : egg_plant_fruit, kiwano, okami_fruit, orange_blue_fruit PORTES). utilisees par okami (seeds=fruit, VERIFIE models), aucun asset okami* n'existe, et le mapping
crusher legacy donne okami->titane = le role wiki du chervil ("donne des lingots de titane",
corpus VERIFIE). Hypothese : chervil (wiki actuel) == okami (legacy). RESTE : confirmation
visuelle en jeu (comparer chervils.png au fruit chervil du wiki) avant de clore. Raison : pas de
doublon cree sans preuve.
### 1.7 Metiers (4) ### 1.7 Metiers (4)
@@ -490,6 +494,9 @@ avant M4 (TODO:crafts-machines).
(export JAVA_HOME jdk25) pour ne plus bricoler. Raison : decouvert en testant (3 essais). (export JAVA_HOME jdk25) pour ne plus bricoler. Raison : decouvert en testant (3 essais).
- M1 LIVRE 2026-10-18 23:40 : worldgen amethyste/titane calibre wiki (size 8, trapezoid 6-10, - M1 LIVRE 2026-10-18 23:40 : worldgen amethyste/titane calibre wiki (size 8, trapezoid 6-10,
placed deep 25-40 + injection 4 biomes deep ocean), /pala orestats (scan + histo Y). placed deep 25-40 + injection 4 biomes deep ocean), /pala orestats (scan + histo Y).
VERIFIE : build SUCCESSFUL, boot Done (0.345s), config persistee ("config existante"),
0 ERROR/Exception/datapack au log. UNVERIFIED en jeu : /pala orestats (pas de joueur connecte
pendant le test) + distribution reelle sur nouveaux chunks.
- M2 LIVRE (partiel) 2026-10-18 23:45 : tooltip XP POG via composant LORE serveur - M2 LIVRE (partiel) 2026-10-18 23:45 : tooltip XP POG via composant LORE serveur
(ItemLore verifie au javap ; niveau + "XP : x / seuil" maj a chaque casse, ligne MAX au niv.25 ; (ItemLore verifie au javap ; niveau + "XP : x / seuil" maj a chaque casse, ligne MAX au niv.25 ;
conserve sur evolution). Craft POG VERIFIE dans data (pattern "#AB/C/C" = 1 pioche amethyste + conserve sur evolution). Craft POG VERIFIE dans data (pattern "#AB/C/C" = 1 pioche amethyste +
@@ -497,10 +504,11 @@ avant M4 (TODO:crafts-machines).
VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED : affichage tooltip en jeu VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED : affichage tooltip en jeu
(pas de joueur), paliers OS wiki non implementes (TODO:pog-os : seuils one-shot 11/21/26/31. (pas de joueur), paliers OS wiki non implementes (TODO:pog-os : seuils one-shot 11/21/26/31.
Raison : M2 lore d'abord, OS ensuite). Raison : M2 lore d'abord, OS ensuite).
placed deep 25-40 + injection 4 biomes deep ocean), /pala orestats (scan + histo Y). - M3 LIVRE 2026-10-18 23:51 : crusher fidele legacy (fruits->lingots : eggplant/amethyste,
VERIFIE : build SUCCESSFUL, boot Done (0.345s), config persistee ("config existante"), okami/titane, kiwano/paladium, orange_blue/nugget endium ; fuels = 5 mixed coals, creative infini,
0 ERROR/Exception/datapack au log. UNVERIFIED en jeu : /pala orestats (pas de joueur connecte conso 20 %/tick, luck 1/128, auto-generate a 1.0 ; NE cuit plus de minerais) + furnace accepte
pendant le test) + distribution reelle sur nouveaux chunks. mixed coals + gate fermier 8 a l'ouverture du crusher. VERIFIE : build SUCCESSFUL, boot Done,
0 erreur. UNVERIFIED en jeu : cycle fruit->lingot avec joueur, gate a fermier<8.
- Client/mod : ./gradlew runClient dans mods/pala/ : NON LANCE (session : pas d'affichage ; screenshots - Client/mod : ./gradlew runClient dans mods/pala/ : NON LANCE (session : pas d'affichage ; screenshots
ocular impossibles ici). TODO:runclient : 1 screenshot/feature dans mods/pala/docs/screens/ avant M10. ocular impossibles ici). TODO:runclient : 1 screenshot/feature dans mods/pala/docs/screens/ avant M10.
Raison : environnement headless, a faire sur poste avec X. Raison : environnement headless, a faire sur poste avec X.
@@ -1,7 +1,9 @@
package fr.surviepote.pala.machine; package fr.surviepote.pala.machine;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -16,6 +18,9 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import fr.surviepote.pala.PalaBlocks;
import fr.surviepote.pala.core.PalaJobs;
// Blocs machines Pala (PaladiumCrusherGUI / PaladiumFurnaceGUI, type 1 = lies au bloc). // Blocs machines Pala (PaladiumCrusherGUI / PaladiumFurnaceGUI, type 1 = lies au bloc).
// Minimum fonctionnel : bloc + block entity + inventaire 9 slots expose via // Minimum fonctionnel : bloc + block entity + inventaire 9 slots expose via
// le menu vanilla Dispenser (3x3, slots 0/1 entree+combustible, slot 2 sortie, // le menu vanilla Dispenser (3x3, slots 0/1 entree+combustible, slot 2 sortie,
@@ -49,6 +54,14 @@ public class PalaMachineBlock extends Block implements EntityBlock {
@Override @Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
// M3 (wiki crusher : "disponible a partir du niveau 8" fermier, VERIFIE).
if (!level.isClientSide() && state.is(PalaBlocks.PALADIUM_CRUSHER)
&& player instanceof ServerPlayer sp && PalaJobs.levelOf(sp, "fermier") < 8) {
sp.sendSystemMessage(Component.literal(
"§cCrusher verrouille : fermier niveau 8 requis (actuel : "
+ PalaJobs.levelOf(sp, "fermier") + ")."));
return InteractionResult.FAIL;
}
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof MenuProvider provider) { if (!level.isClientSide() && level.getBlockEntity(pos) instanceof MenuProvider provider) {
player.openMenu(provider); player.openMenu(provider);
} }
@@ -1,5 +1,7 @@
package fr.surviepote.pala.machine; package fr.surviepote.pala.machine;
import java.util.Map;
import fr.surviepote.pala.PalaBlockEntities; import fr.surviepote.pala.PalaBlockEntities;
import fr.surviepote.pala.PalaBlocks; import fr.surviepote.pala.PalaBlocks;
import fr.surviepote.pala.PalaItems; import fr.surviepote.pala.PalaItems;
@@ -11,6 +13,7 @@ import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.DispenserMenu; import net.minecraft.world.inventory.DispenserMenu;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@@ -19,16 +22,37 @@ import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.level.storage.ValueOutput;
// Block entity partagee crusher/furnace. Inventaire 9 slots (menu vanilla // Block entity partagee crusher/furnace. Inventaire 9 slots (menu vanilla
// Dispenser 3x3) : slot 0 = entree, slot 1 = combustible (charbon), // Dispenser 3x3) : slot 0 = entree, slot 1 = combustible, slot 2 = sortie.
// slot 2 = sortie. Cuisson : minerai de paladium -> lingot (le crusher //
// cuit 2x plus vite, a la place du bouton Generate du legacy : TODO). // M3 — crusher fidele au legacy (ProcedurePaladiumCrusherUpdateTick +
// ProcedurePaladiumCrusherGenerateButton, legacy-src-backup) :
// - slot 0 = fruit (eggplant->amethyste, okami->titane, kiwano->paladium,
// orange_blue->nugget endium). Le wiki actuel cite "chervil"->titane ; les
// textures chervil* sont deja utilisees par okami (fruit+seeds) et aucun
// asset okami* n'existe => equivalence chervil==okami (TODO:chervil, a
// confirmer visuellement, pas de doublon cree) ;
// - slot 1 = mixed coal (legacy : pala+creative ; wiki actuel : aussi gold,
// amethyste, titane => les 4 + creative). Creative = infini (legacy) ;
// sinon 20 % de consommer 1/tick (legacy) ;
// - "luck" += 1/128 par tick (legacy 0.0078125), gate luck < 1 ;
// - auto-generate a luck >= 1 (legacy : bouton manuel a proba luck ; a luck=1
// le succes est certain => meme resultat sans GUI custom ; ECART documente) ;
// - le crusher NE cuit plus de minerais (legacy+wiki : fruits uniquement).
// Furnace : minerais pala + combustible charbon vanilla ET mixed coals.
public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider { public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider {
private static final int COOK_TIME_FURNACE = 200; private static final int COOK_TIME_FURNACE = 200;
private static final int COOK_TIME_CRUSHER = 100; private static final double LUCK_PER_TICK = 1.0 / 128.0;
private static final Map<Item, Item> CRUSHER_RESULTS = Map.of(
PalaItems.EGG_PLANT_FRUIT, PalaItems.AMETHYST_INGOT,
PalaItems.OKAMI_FRUIT, PalaItems.TITANE_INGOT,
PalaItems.KIWANO, PalaItems.PALADIUM_INGOT,
PalaItems.ORANGE_BLUE_FRUIT, PalaItems.ENDIUM_NUGGET);
private final SimpleContainer inventory = new SimpleContainer(9); private final SimpleContainer inventory = new SimpleContainer(9);
private int progress; private int progress;
private double luck;
public PalaMachineBlockEntity(BlockPos pos, BlockState state) { public PalaMachineBlockEntity(BlockPos pos, BlockState state) {
super(PalaBlockEntities.MACHINE, pos, state); super(PalaBlockEntities.MACHINE, pos, state);
@@ -39,17 +63,52 @@ public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider
} }
public void serverTick() { public void serverTick() {
if (isCrusher()) {
crusherTick();
} else {
furnaceTick();
}
}
private void crusherTick() {
ItemStack fruit = inventory.getItem(0);
ItemStack fuel = inventory.getItem(1);
ItemStack output = inventory.getItem(2);
Item result = CRUSHER_RESULTS.get(fruit.getItem());
if (result == null || luck >= 1.0 || !isMixedFuel(fuel)) {
return;
}
boolean infinite = fuel.is(PalaItems.CREATIVE_MIXED_COAL);
if (output.isEmpty() || (output.is(result)
&& output.getCount() + 1 <= output.getMaxStackSize())) {
fruit.shrink(1);
if (!infinite && Math.random() < 0.2) {
fuel.shrink(1);
}
luck = Math.min(1.0, luck + LUCK_PER_TICK);
if (luck >= 1.0) {
if (output.isEmpty()) {
inventory.setItem(2, new ItemStack(result));
} else {
output.grow(1);
}
luck = 0.0;
}
setChanged();
}
}
private void furnaceTick() {
ItemStack input = inventory.getItem(0); ItemStack input = inventory.getItem(0);
ItemStack fuel = inventory.getItem(1); ItemStack fuel = inventory.getItem(1);
ItemStack output = inventory.getItem(2); ItemStack output = inventory.getItem(2);
ItemStack result = smeltResult(input); ItemStack result = smeltResult(input);
boolean canCook = !result.isEmpty() && isFuel(fuel) boolean canCook = !result.isEmpty() && isFurnaceFuel(fuel)
&& (output.isEmpty() || (ItemStack.isSameItemSameComponents(output, result) && (output.isEmpty() || (ItemStack.isSameItemSameComponents(output, result)
&& output.getCount() + result.getCount() <= output.getMaxStackSize())); && output.getCount() + result.getCount() <= output.getMaxStackSize()));
if (canCook) { if (canCook) {
progress++; progress++;
int target = isCrusher() ? COOK_TIME_CRUSHER : COOK_TIME_FURNACE; if (progress >= COOK_TIME_FURNACE) {
if (progress >= target) {
progress = 0; progress = 0;
input.shrink(1); input.shrink(1);
fuel.shrink(1); fuel.shrink(1);
@@ -76,8 +135,14 @@ public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
private static boolean isFuel(ItemStack stack) { private static boolean isMixedFuel(ItemStack stack) {
return stack.is(Items.COAL) || stack.is(Items.CHARCOAL); return stack.is(PalaItems.PALA_MIXED_COAL) || stack.is(PalaItems.CREATIVE_MIXED_COAL)
|| stack.is(PalaItems.AMETHYST_MIXED_COAL) || stack.is(PalaItems.TITANE_MIXED_COAL)
|| stack.is(PalaItems.GOLD_MIXED_COAL);
}
private static boolean isFurnaceFuel(ItemStack stack) {
return stack.is(Items.COAL) || stack.is(Items.CHARCOAL) || isMixedFuel(stack);
} }
@Override @Override
@@ -85,6 +150,7 @@ public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider
super.saveAdditional(output); super.saveAdditional(output);
inventory.storeAsItemList(output.list("Items", ItemStack.CODEC)); inventory.storeAsItemList(output.list("Items", ItemStack.CODEC));
output.putInt("Progress", progress); output.putInt("Progress", progress);
output.putDouble("Luck", luck);
} }
@Override @Override
@@ -92,6 +158,7 @@ public class PalaMachineBlockEntity extends BlockEntity implements MenuProvider
super.loadAdditional(input); super.loadAdditional(input);
inventory.fromItemList(input.listOrEmpty("Items", ItemStack.CODEC)); inventory.fromItemList(input.listOrEmpty("Items", ItemStack.CODEC));
progress = input.getIntOr("Progress", 0); progress = input.getIntOr("Progress", 0);
luck = input.getDoubleOr("Luck", 0.0);
} }
@Override @Override
Binary file not shown.