Problème de mise à jour d'une table de craft personnalisée



  • Bonjour à tous !

    J'ai suivi le tuto pour créer une table de craft personnalisée. J'en ai fait une de 5x5.
    Toutefois, le tuto est fait pour la 1.10.2. J'ai donc fait de mon mieux pour adapter le code en 1.12.2. J'ai réussi à corrigé pas mal de soucis mais un dernier demeure.

    Lorsque l'on place les items dans la grille de la table de craft, si le craft ne correspond à rien rien ne s'affiche dans le slot de résultat. Tout est normal jusque là.
    Si un craft est valide, le résultat s'affiche. On peut prendre ce résultat, ça consomme bien les ingrédients, bref parfait.
    En revanche, si un craft est reconnu et que l'on enlève un ingrédient, le résultat reste (alors qu'il devrait disparaître) et si on a la bonne idée de prendre ce résultat qui ne dervait pas être là, ça crash :

    ---- Minecraft Crash Report ----
    // This doesn't make any sense!
    
    Time: 2/2/19 8:15 PM
    Description: Updating screen events
    
    java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    	at java.util.ArrayList.rangeCheck(ArrayList.java:657)
    	at java.util.ArrayList.set(ArrayList.java:448)
    	at net.minecraft.util.NonNullList.set(NonNullList.java:57)
    	at fr.dofuscraft.dofuscraftcore.crafting_manager.DCCraftingManager.getRemainingItems(DCCraftingManager.java:196)
    	at fr.dofuscraft.dofuscraftcore.gui.slots.DCCraftingResultSlot.onTake(DCCraftingResultSlot.java:82)
    	at net.minecraft.inventory.Container.slotClick(Container.java:328)
    	at net.minecraft.client.multiplayer.PlayerControllerMP.windowClick(PlayerControllerMP.java:610)
    	at net.minecraft.client.gui.inventory.GuiContainer.handleMouseClick(GuiContainer.java:693)
    	at net.minecraft.client.gui.inventory.GuiContainer.mouseClicked(GuiContainer.java:430)
    	at net.minecraft.client.gui.GuiScreen.handleMouseInput(GuiScreen.java:611)
    	at net.minecraft.client.gui.GuiScreen.handleInput(GuiScreen.java:576)
    	at net.minecraft.client.Minecraft.runTick(Minecraft.java:1884)
    	at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1186)
    	at net.minecraft.client.Minecraft.run(Minecraft.java:441)
    	at net.minecraft.client.main.Main.main(Main.java:118)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
    	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97)
    	at GradleStart.main(GradleStart.java:25)
    
    
    A detailed walkthrough of the error, its code path and all known details is as follows:
    ---------------------------------------------------------------------------------------
    
    -- Head --
    Thread: Client thread
    Stacktrace:
    	at java.util.ArrayList.rangeCheck(ArrayList.java:657)
    	at java.util.ArrayList.set(ArrayList.java:448)
    	at net.minecraft.util.NonNullList.set(NonNullList.java:57)
    	at fr.dofuscraft.dofuscraftcore.crafting_manager.DCCraftingManager.getRemainingItems(DCCraftingManager.java:196)
    	at fr.dofuscraft.dofuscraftcore.gui.slots.DCCraftingResultSlot.onTake(DCCraftingResultSlot.java:82)
    	at net.minecraft.inventory.Container.slotClick(Container.java:328)
    	at net.minecraft.client.multiplayer.PlayerControllerMP.windowClick(PlayerControllerMP.java:610)
    	at net.minecraft.client.gui.inventory.GuiContainer.handleMouseClick(GuiContainer.java:693)
    	at net.minecraft.client.gui.inventory.GuiContainer.mouseClicked(GuiContainer.java:430)
    	at net.minecraft.client.gui.GuiScreen.handleMouseInput(GuiScreen.java:611)
    	at net.minecraft.client.gui.GuiScreen.handleInput(GuiScreen.java:576)
    
    -- Affected screen --
    Details:
    	Screen name: fr.dofuscraft.dofuscraftcore.gui.GuiDCCraftingTable
    
    -- Affected level --
    Details:
    	Level name: MpServer
    	All players: 1 total; [EntityPlayerSP['MysteriousDevs'/83, l='MpServer', x=-773.30, y=6.38, z=499.01]]
    	Chunk stats: MultiplayerChunkCache: 600, 600
    	Level seed: 0
    	Level generator: ID 01 - flat, ver 0. Features enabled: false
    	Level generator options: 
    	Level spawn location: World: (-760,4,508), Chunk: (at 8,0,12 in -48,31; contains blocks -768,0,496 to -753,255,511), Region: (-2,0; contains chunks -64,0 to -33,31, blocks -1024,0,0 to -513,255,511)
    	Level time: 126827 game time, 126827 day time
    	Level dimension: 0
    	Level storage version: 0x00000 - Unknown?
    	Level weather: Rain time: 0 (now: false), thunder time: 0 (now: false)
    	Level game mode: Game mode: creative (ID 1). Hardcore: false. Cheats: false
    	Forced entities: 37 total; [EntityChicken['Chicken'/64, l='MpServer', x=-700.74, y=4.00, z=481.12], EntityPig['Pig'/66, l='MpServer', x=-699.60, y=4.00, z=504.54], EntityChicken['Chicken'/67, l='MpServer', x=-697.92, y=4.00, z=506.17], EntityPig['Pig'/21, l='MpServer', x=-828.27, y=4.00, z=430.64], EntityCow['Cow'/22, l='MpServer', x=-819.41, y=4.00, z=494.13], EntityCow['Cow'/23, l='MpServer', x=-817.18, y=4.00, z=510.55], EntityPig['Pig'/24, l='MpServer', x=-811.18, y=4.00, z=434.80], EntityPig['Pig'/25, l='MpServer', x=-812.64, y=4.00, z=440.26], EntityPig['Pig'/26, l='MpServer', x=-806.82, y=4.00, z=444.20], EntityCow['Cow'/27, l='MpServer', x=-798.85, y=4.00, z=440.31], EntityCow['Cow'/28, l='MpServer', x=-801.82, y=4.00, z=468.78], EntityCow['Cow'/29, l='MpServer', x=-802.19, y=4.00, z=476.17], EntityCow['Cow'/30, l='MpServer', x=-806.56, y=4.00, z=470.18], EntityCow['Cow'/31, l='MpServer', x=-811.80, y=4.00, z=488.68], EntitySheep['Sheep'/32, l='MpServer', x=-814.38, y=4.00, z=505.32], EntityPig['Pig'/36, l='MpServer', x=-774.27, y=4.00, z=554.25], EntityCow['Cow'/37, l='MpServer', x=-753.78, y=4.00, z=577.46], EntityChicken['Chicken'/39, l='MpServer', x=-737.69, y=4.00, z=429.85], EntityPig['Pig'/40, l='MpServer', x=-738.55, y=4.00, z=555.31], EntityChicken['Chicken'/41, l='MpServer', x=-725.93, y=4.00, z=429.91], EntityChicken['Chicken'/42, l='MpServer', x=-735.59, y=4.00, z=428.81], EntityPig['Pig'/45, l='MpServer', x=-729.33, y=4.00, z=489.19], EntityChicken['Chicken'/46, l='MpServer', x=-734.15, y=4.00, z=542.54], EntityItem['item.item.egg'/47, l='MpServer', x=-733.71, y=4.00, z=543.02], EntityChicken['Chicken'/48, l='MpServer', x=-715.81, y=4.00, z=442.42], EntityCow['Cow'/50, l='MpServer', x=-711.14, y=4.00, z=471.73], EntityCow['Cow'/51, l='MpServer', x=-705.21, y=4.00, z=468.60], EntityItem['item.item.egg'/52, l='MpServer', x=-710.07, y=4.00, z=492.82], EntityCow['Cow'/53, l='MpServer', x=-710.69, y=4.00, z=498.75], EntityCow['Cow'/54, l='MpServer', x=-723.25, y=4.00, z=487.85], EntityCow['Cow'/55, l='MpServer', x=-717.38, y=4.00, z=500.77], EntityCow['Cow'/56, l='MpServer', x=-705.35, y=4.00, z=499.01], EntitySheep['Sheep'/57, l='MpServer', x=-712.84, y=4.00, z=514.80], EntityCow['Cow'/58, l='MpServer', x=-708.45, y=4.00, z=523.78], EntityPlayerSP['MysteriousDevs'/83, l='MpServer', x=-773.30, y=6.38, z=499.01], EntityCow['Cow'/61, l='MpServer', x=-700.67, y=4.00, z=473.80], EntityCow['Cow'/62, l='MpServer', x=-694.19, y=4.00, z=474.55]]
    	Retry entities: 0 total; []
    	Server brand: fml,forge
    	Server type: Integrated singleplayer server
    Stacktrace:
    	at net.minecraft.client.multiplayer.WorldClient.addWorldInfoToCrashReport(WorldClient.java:461)
    	at net.minecraft.client.Minecraft.addGraphicsAndWorldToCrashReport(Minecraft.java:2886)
    	at net.minecraft.client.Minecraft.run(Minecraft.java:462)
    	at net.minecraft.client.main.Main.main(Main.java:118)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
    	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97)
    	at GradleStart.main(GradleStart.java:25)
    

    Je pense que ça viens du container, mais où... ça reste un mystère.

    Container :

    public class DCCraftingTableContainer extends Container
    {
        /** Largeur du craft */
        public static final int craftWidth = 5;
        /** Hauteur du craft */
        public static final int craftHeigth = 5;
    
        /** Inventaire contenant le craft */
        private InventoryCrafting craftMatrix = new InventoryCrafting(this, craftWidth, craftHeigth);
        /** Inventaire contenant le résultat du craft */
        private InventoryCraftResult craftResult = new InventoryCraftResult();
    
        private final World worldObj;
        private final BlockPos pos;
        private final EntityPlayer player;
    
        public DCCraftingTableContainer(InventoryPlayer invPlayer, World world, BlockPos pos)
        {
            this.worldObj = world;
            this.pos = pos;
            this.player = invPlayer.player;
    
            //Ajout du slot pour le résultat
            this.addSlotToContainer(new DCCraftingResultSlot(invPlayer.player, craftMatrix, craftResult, 0, 172, 76));
    
            int startX = 16; //Position x ou les slots de craft commencent à être dessinés
            int startY = 9; //Position y ou les slots de craft commencent à être dessinés
            //Ajout des slots de craft
            for (int y = 0; y < craftHeigth; ++y)
            {
                for(int x = 0; x < craftWidth; ++x)
                {
                    this.addSlotToContainer(new Slot(craftMatrix, x + y * craftWidth, startX + x * 18, startY + y * 18));
                }
            }
    
            startX = 25; //Position x ou les slots de l'inventaire commencent à être dessinés
            startY = 108; //Position y ou les slots de l'inventaire commencent à être dessinés
            //Ajout des slots de l'inventaire du joueur
            for (int y = 0; y < 3; ++y)
            {
                for(int x = 0; x < 9; ++x)
                {
                    this.addSlotToContainer(new Slot(invPlayer, x + y * 9 + 9, startX + x * 18, startY + y * 18));
                }
            }
            startY = 166; //Position y ou les slots de la hotbar commencent à être dessinés
            //Ajout des slots de la hotbar
            for (int x = 0; x < 9; ++x)
            {
                this.addSlotToContainer(new Slot(invPlayer, x, startX + x * 18, startY));
            }
        }
    
        /**
         * Appelé quand la matrice (les slots de craft) change
         */
        @Override
        public void onCraftMatrixChanged(IInventory iiventory)
        {
    
    
            //On met le résultat du craft dans le slot de résultat
            if(DCCraftingManager.getInstance().findMatchingRecipe(craftMatrix, worldObj) != null)
            {
                craftResult.setInventorySlotContents(0, DCCraftingManager.getInstance().findMatchingRecipe(craftMatrix, worldObj));
            }
    
    
    
    
    
        }
    
        /**
         * Retourne true si le joueur peut interagir avec ce gui, en général on teste la distance par rapport au joueur dans cette fonction
         */
        @Override
        public boolean canInteractWith(EntityPlayer player)
        {
            return this.worldObj.getBlockState(this.pos).getBlock() != ModBlocks.dofuscraft_crafting_table ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
        }
    
        /**
         * Appelé quand le container est fermé
         */
        @Override
        public void onContainerClosed(EntityPlayer player)
        {
    
    
            super.onContainerClosed(player);
    
            if (!this.worldObj.isRemote)
            {
                this.clearContainer(player, this.worldObj, this.craftMatrix);
            }
    
        }
    
        /**
         * Cette fonction est appelée lors du shift+clic (je vous conseille de la laisser comme tel, elle s'adaptera en fonction de la taille de votre craft)
         * EDIT 11/01/16 Le contenu de cette fonction a été modifié via notepad++ et n'a pas été testé, si vous avez un problème rapportez le moi
         */
        @Override
        public ItemStack transferStackInSlot(EntityPlayer player, int slotId)
        {
            ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = this.inventorySlots.get(slotId);
    
            if (slot != null && slot.getHasStack())
            {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
    
                if (slotId == 0)
                {
                    itemstack1.getItem().onCreated(itemstack1, this.worldObj, player);
    
                    if (!this.mergeItemStack(itemstack1, 26, 62, true))
                    {
                        return ItemStack.EMPTY;
                    }
    
                    slot.onSlotChange(itemstack1, itemstack);
                }
                else if (slotId >= 26 && slotId < 53)
                {
                    if (!this.mergeItemStack(itemstack1, 53, 62, false))
                    {
                        return ItemStack.EMPTY;
                    }
                }
                else if (slotId >= 53 && slotId < 62)
                {
                    if (!this.mergeItemStack(itemstack1, 26, 53, false))
                    {
                        return ItemStack.EMPTY;
                    }
                }
                else if (!this.mergeItemStack(itemstack1, 26, 62, false))
                {
                    return ItemStack.EMPTY;
                }
    
                if (itemstack1.isEmpty())
                {
                    slot.putStack(ItemStack.EMPTY);
                }
                else
                {
                    slot.onSlotChanged();
                }
    
                if (itemstack1.getCount() == itemstack.getCount())
                {
                    return ItemStack.EMPTY;
                }
    
                ItemStack itemstack2 = slot.onTake(player, itemstack1);
    
               /* if (slotId == 0)
                {
                    player.dropItem(itemstack2, false);
                }*/
            }
    
            return itemstack;
        }
    
        /**
         * Appelé quand on double clic sur un slot :
         * Called to determine if the current slot is valid for the stack merging (double-click) code. The stack passed in
         * is null for the initial slot that was double-clicked.
         */
        public boolean canMergeSlot(ItemStack stack, Slot slotIn)
        {
            return slotIn.inventory != this.craftResult && super.canMergeSlot(stack, slotIn);
        }
    
    
    }
    

    Merci d'avance !

    Jerem'



  • @Jerem_Tech a dit dans Problème de mise à jour d'une table de craft personnalisée :

    at fr.dofuscraft.dofuscraftcore.crafting_manager.DCCraftingManager.getRemainingItems(DCCraftingManager.java:196)

    Donc il nous faut la class DCCraftingManager



  • La voici 🙂

    public class DCCraftingManager
    {
        private static final DCCraftingManager INSTANCE = new DCCraftingManager();
    
        public static DCCraftingManager getInstance()
        {
            return INSTANCE;
        }
    
        /** La liste des recettes */
        private final List<IRecipe> recipes = Lists.<IRecipe>newArrayList();
    
        private DCCraftingManager()
        {
            addRecipe(new ItemStack(ModItems.bouftou_spit), "XXXXX", "XXXXX", "XXXXX", "XXXXX", "XXXXX", 'X', Items.APPLE);
        }
    
        /**
         * Adds a shaped recipe to the games recipe list.
         */
        public DCShapedRecipes addRecipe(ItemStack result, Object... recipeComponents)
        {
            String s = "";
            int i = 0;
            int j = 0;
            int k = 0;
            if( recipeComponents[i] instanceof String[] )
            {
                String[] astring = (String[]) ((String[]) recipeComponents[i++]);
                for ( int l = 0; l < astring.length; ++l )
                {
                    String s2 = astring[l];
                    ++k;
                    j = s2.length();
                    s = s + s2;
                }
            }
            else
            {
                while ( recipeComponents[i] instanceof String )
                {
                    String s1 = (String) recipeComponents[i++];
                    ++k;
                    j = s1.length();
                    s = s + s1;
                }
            }
            Character character;
            Map<Character, Object> components = Maps.<Character, Object>newHashMap();
            Object in;
            for ( ; i < recipeComponents.length; i += 2 )
            {
                in = recipeComponents[i + 1];
                Object component = null;
                character = (Character) recipeComponents[i];
                if( in instanceof Item )
                {
                    component = new ItemStack((Item) recipeComponents[i + 1]);
                }
                else if( in instanceof Block )
                {
                    component = new ItemStack((Block) recipeComponents[i + 1], 1, 32767);
                }
                else if( in instanceof ItemStack )
                {
                    component = (ItemStack) recipeComponents[i + 1];
                }
                else if( in instanceof String )
                {
                    component = (String) in;
                }
                else
                {
                    throw new IllegalArgumentException("Invalid shaped recipe: unknown type " + in.getClass().getName() + "!");
                }
                components.put(character, component);
            }
            Object[] aitemstack = new Object[j * k];
            char key;
            Object component;
            for ( int i1 = 0; i1 < j * k; ++i1 )
            {
                key = s.charAt(i1);
                if( components.containsKey(Character.valueOf(key)) )
                {
                    component = components.get(Character.valueOf(key));
                    if( component instanceof ItemStack )
                    {
                        aitemstack[i1] = ((ItemStack) component).copy();
                    }
                    else
                    {
                        aitemstack[i1] = component;
                    }
                }
                else
                {
                    aitemstack[i1] = null;
                }
            }
            DCShapedRecipes shapedrecipes = new DCShapedRecipes(j, k, aitemstack, result);
            System.out.println(aitemstack);
            this.recipes.add(shapedrecipes);
            return shapedrecipes;
        }
    
    
        /**
         * Adds a shapeless crafting recipe to the the game.
         */
        public void addShapelessRecipe(ItemStack result, Object... recipeComponents)
        {
            List list = Lists.newArrayList();
            for (Object component : recipeComponents) //Pour chaque composant de la recette
            {
                if (component instanceof ItemStack)
                {
                    list.add(((ItemStack)component).copy());
                }
                else if (component instanceof Item)
                {
                    list.add(new ItemStack((Item)component));
                }
                else if(component instanceof Block)
                {
                    list.add(new ItemStack((Block)component));
                }
                else if(component instanceof String) //Pour l'ore dictionnary
                {
                    list.add(component);
                }
                else throw new IllegalArgumentException("Invalid shapeless recipe: unknown type " + component.getClass().getName() + "!");
            }
            this.recipes.add(new DCShapelessRecipes(result, list));
        }
    
        /**
         * Adds an IRecipe to the list of crafting recipes.
         */
        public void addRecipe(IRecipe recipe)
        {
            this.recipes.add(recipe);
        }
    
        /**
         * Retourne le résultat de la recette ou null si il n'y en a aucun
         */
        @Nullable
        public ItemStack findMatchingRecipe(InventoryCrafting craftMatrix, World worldIn)
        {
            for (IRecipe irecipe : this.recipes) //Pour chaque recette
            {
                if (irecipe.matches(craftMatrix, worldIn)) //Si elle correspond à la matrice actuelle
                {
                    return irecipe.getCraftingResult(craftMatrix); //On donne son résultat
                }
            }
            return null;
        }
    
        /**
         * Retourne les items retants après un craft
         */
        public NonNullList<ItemStack> getRemainingItems(InventoryCrafting craftMatrix, World worldIn)
        {
            for (IRecipe irecipe : this.recipes) //Pour chaque recette
            {
                if (irecipe.matches(craftMatrix, worldIn)) //Si elle correspond à la matrice actuelle
                {
                    return irecipe.getRemainingItems(craftMatrix); //On retourne les items restants
                }
            }
            NonNullList<ItemStack> aitemstack = NonNullList.create();
            for (int i = 0; i < craftMatrix.getSizeInventory(); ++i)
            {
                aitemstack.set(i, craftMatrix.getStackInSlot(i));
            }
            return aitemstack; //Si ça ne correspond à aucune recette, on retourne tous les items qui sont présents dans la matrice
        }
    
        public List<IRecipe> getRecipeList()
        {
            return this.recipes;
        }
    }
    

    Jerem'


  • Moddeurs confirmés Rédacteurs Administrateurs

    @Jerem_Tech a dit dans Problème de mise à jour d'une table de craft personnalisée :

    NonNullList<ItemStack> aitemstack = NonNullList.create();

    Cette liste a une taille de 0, il faudrait l'initialiser avec une taille identique à craftMatrix.getSizeInventory()



  • Cela corrige effectivement le crash, mais le problème est toujours là :

    Ici, le craft est de remplir la grille de pommes. Si on en enlève une, le résultat reste et le craft fonctionne quand même.
    Capture.PNG

    Voici ce que j'ai mis pour la liste. Je suis obligé de remplir avec un ItemStack donc j'ai mis ça :

            NonNullList<ItemStack> aitemstack = NonNullList.withSize(craftMatrix.getSizeInventory(), new ItemStack(Blocks.AIR));
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    Tu peux utiliser ItemStack.EMPTY

    Essaies de remplacer le return null de la fonction findMatchingRecipe par return ItemStack.EMPTY

    De façon général, tout ce qui touche au ItemStack ne doit plus avoir de null en 1.12.2.
    Ton problème vient surement d'un check quelque part qui ne passe pas à cause du null / ItemStack.EMPTY penses donc à tout vérifier.



  • Effectivement ça venais de ça.
    En tout cas merci de l'info, c'est bon à savoir !

    Merci beaucoup !

    Jerem'


Log in to reply