1.12.2 Inventaire multi fonction ( IItemHandler vs IInventory )



  • Bonjour, je viens ici pour plusieurs questions, en vous remerciant d'avance pour votre aide et surtout votre soutien encore valable pour la 1.12.2 alors que forge bloque systématiquement tout sujet concernant une version inférieur à la 1.14.4 ( ce qui est ... plutôt débile et ce n'est pas mes mots ... ) bref ! ( le support officiel peut ne pas être fourni mais empêcher la communauté d'échanger je trouve cela ... ).

    Pour commencer, je travaille sur un petit mod qui rajoute de simples fonctions sans prétention, tel que, un système de téléportation basé sur le bedLocation(), ou encore un inventaire similaire au enderchest mais incluant des fonctionnalités supplémentaire et c'est là mon souci :

    1: Est-il possible de revoir toutes les fonctions lié à IIventory pour les basculer sur IItemHandler ? ( pour détail mon inventaire inclue un inventaire de 104 slots + une table de craft et un four )
    2: Je sais déjà qu'il me faut employer le NBTtagCompound pour enregistrer l'inventaire de mon objet, je souhaiterais également le lié au personnage et non à l'objet ( tous comme le ender chest ) mais je ne sais pas trop comment procéder !
    3: Dernier souci, comment inclure mon four à tout ceci, sachant que le four utilise IIventory et un TileEntity alors que je passe par un objet unique ?

    package com.kporal.mcplus.items.kitbag;
    
    import com.kporal.mcplus.container.CraftResultInventory;
    import com.kporal.mcplus.container.CraftResultSlot;
    import com.kporal.mcplus.container.FuelFurnaceSlot;
    import com.kporal.mcplus.container.OutputFurnaceSlot;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.inventory.Container;
    import net.minecraft.inventory.IContainerListener;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.inventory.InventoryCraftResult;
    import net.minecraft.inventory.InventoryCrafting;
    import net.minecraft.inventory.Slot;
    import net.minecraft.inventory.SlotCrafting;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import net.minecraftforge.items.IItemHandler;
    import net.minecraftforge.items.SlotItemHandler;
    
    public class KitbagContainer extends Container {
        
    	//public IItemHandler inventory;
        public EntityPlayer player;
        public World world;
        public InventoryCrafting craftMatrix = new InventoryCrafting( this, 3, 3 ); // Workbench slots
        public InventoryCraftResult craftResult = new InventoryCraftResult(); // Workbench result slot
        private int xPos = 5, yPos = 5, iid = 0, iRows = 8, iLines = 13, nSlots = iRows * iLines, startSlot = 10; // int for IItemHandler
        private int cookTime, totalCookTime, furnaceBurnTime, currentItemBurnTime; // Furnace #DATAS
        
        //public CraftResultInventory test = new CraftResultInventory();
        
    	public KitbagContainer( IItemHandler i, EntityPlayer p ) {
    		
    		//inventory = i;
    		player = p;
    		world = p.world;
    		
    		// CraftBench
    	    addSlotToContainer( new SlotCrafting( p, craftMatrix, craftResult, 0, 167, 170 ));
    	    //addSlotToContainer( new CraftResultSlot( p, craftMatrix, test, 0, 167, 170 ));
    
            for (int y = 0; y < 3; ++y)
            	for (int x = 0; x < 3; ++x)
            		addSlotToContainer( new Slot( craftMatrix, x + y * 3, 185 + x * 18, 152 + y * 18 ));
    		
            // Inventory
    		for( int y = 0; y < iRows; ++y ) {
    			for( int x = 0; x < iLines; ++x ) {
    				addSlotToContainer( new SlotItemHandler( i, iid, xPos + x * 18, yPos + y * 18 ));
    				iid++;
    			}
    		}
    		
    		// Furnace slots
    		addSlotToContainer( new SlotItemHandler( i, iid, 221, 209 )); iid++;
    		addSlotToContainer( new FuelFurnaceSlot( i, iid, 185, 209 )); iid++;
    		addSlotToContainer( new OutputFurnaceSlot( p, i, iid, 167, 209 ));
    		
    		yPos = 152;
    		
    		// Player inventory
    		for( int y = 0; y < 3; ++y )
    			for( int x = 0; x < 9; ++x )
    				addSlotToContainer( new Slot( p.inventory, x + y * 9 + 9, xPos + x * 18, yPos + y * 18 ));
    		
    		// Player hotbar
    		for( int x = 0; x < 9; ++x )
    			addSlotToContainer( new Slot( p.inventory, x, xPos + x * 18, 209 ));
    	}
    
    	//### WORKBENCH
    	
    	// public void onCraftMatrixChanged( IInventory i ) {
    	public void onCraftMatrixChanged( IItemHandler i ) {
    		slotChangedCraftingGrid( world, player, craftMatrix, craftResult );
    	}
    
    	public void onContainerClosed( EntityPlayer p ) {
    		super.onContainerClosed( p );
    		if( !world.isRemote )
    			clearContainer( p, world, craftMatrix );
    	}
    
    	//### FURNACE
    	
    	//### OVERALL
    	@Override
    	public ItemStack transferStackInSlot( EntityPlayer playerIn, int index ) {
            
    		ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = inventorySlots.get(index);
    
            if( slot != null && slot.getHasStack() ) {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                
                if( index == 0 ) {
                    itemstack1.getItem().onCreated(itemstack1, world, playerIn);
    
                    if( !this.mergeItemStack(itemstack1, 0 + startSlot, nSlots + startSlot, false ))
                    	return ItemStack.EMPTY;
    
                    slot.onSlotChange( itemstack1, itemstack );
                }
                
                else if( index < nSlots + startSlot )
                    if( !mergeItemStack( itemstack1, nSlots + startSlot, inventorySlots.size(), true ))
                    	return ItemStack.EMPTY;
                
                else if( !mergeItemStack( itemstack1, 0 + startSlot, nSlots + startSlot, 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( playerIn, itemstack1 );
    
                if( index == 0 ) playerIn.dropItem( itemstack2, false );
            }
    
            return itemstack;
    	}
    	
    	@Override
    	public boolean canInteractWith( EntityPlayer p ) { return true; }
    	
    }
    

    kitbag

    PS: je précise, dans l'état actuel des choses, mon mod fonctionne sans souci ( le four n'étant pas encore inclue ... ) et ayant un bug de duplication sur le SHIFT click sur les slot de craft ( normal car superposition des ID des slots qui sont en conflit entre IItemHandler et IIventory ! d'ou m'as demande n°1

    Merci d'avance de toute l'aide apporter 🙂



  • Bon j'ai déjà régler mon problème concernant la question 1 !

    @SubscribeEvent
    public void onCraftGridChange( PlayerContainerEvent.Open e ) {
    	Container c = e.getContainer();
    	EntityPlayer p = e.getEntityPlayer();
    	World w = p.world;
    		
    	if( c instanceof KitbagContainer && !w.isRemote ) {
    		NonNullList<ItemStack> stackList = NonNullList.<ItemStack>withSize( 9, ItemStack.EMPTY );
    		int id = 0;
    		for( int i = 105; i < 113; i++ ) {
    			stackList.set( id, c.getSlot( i ).getStack() );
    			id++;
    		}
    			    
    		EntityPlayerMP pmp = ( EntityPlayerMP ) p;
    		ItemStack is = simulateRecipes( c, stackList, w, pmp );
    		stackList.clear(); // Do not forget to clear ;)
    	}
    }
    	
    private ItemStack simulateRecipes( Container c, NonNullList<ItemStack> s, World w, EntityPlayerMP p ) {
    	ItemStack is = ItemStack.EMPTY;
    	if( !w.isRemote ) {
    		InventoryCrafting m = new InventoryCrafting( c, 3, 3 );
    		for( int i = 0; i < m.getSizeInventory(); i++ ) {
    			m.setInventorySlotContents( i, s.get( i ));
    		}
    		IRecipe ir = CraftingManager.findMatchingRecipe( m, w );
    		if( ir != null && ( ir.isDynamic() || !w.getGameRules().getBoolean( "doLimitedCrafting" ) || p.getRecipeBook().isUnlocked( ir ))) {
    			is = ir.getCraftingResult( m );
    		}
    		m.clear();
    			
    		c.getInventory().set( 104, is );
    		p.connection.sendPacket( new SPacketSetSlot( c.windowId, 104, is ));
    	}
    	return is;
    }
    

    C'est pas le top, mais grâce à ça je peux exclusivement utiliser mon IItemHandler ( ItemStackHandler ) sans problème vue que je simule le craft ( et c'est bien plus rapide que de me retaper 100% des class de craft ... ) bref ! Mon problème est donc changer ... oui car comme indiquer j'utilise PlayerContainerEvent ... ce qui ... ne me permet absolument pas de gérer mon inventaire correctement, nouvelle question donc, de quel manière je dois procéder ?

    Je suppose qu'il me faut créer mon propre Listener ? mais alors là je n'ai absolument aucune idée comment procéder car c'est littéralement la première fois que je dois faire ça, donc si quelqu'un pourrait m'aiguiller ? voir même donner des exemples ?


  • Moddeurs confirmés Rédacteurs Administrateurs

    Bonjour,

    Concernant le point 2 pour sauvegarder les données en les liant au joueur, il faut passer par une capability : https://www.minecraftforgefrance.fr/topic/4817/les-capabilities?_=1579706317665



  • Oui, je le sais déjà, par contre merci pour le liens, cela m'aidera sans doute, mon inventaire est sauvegarder de cette manière :

    package com.kporal.mcplus.items.kitbag;
    
    import net.minecraft.nbt.NBTBase;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.common.capabilities.ICapabilitySerializable;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.ItemStackHandler;
    
    public class KitbagProvider implements ICapabilityProvider, ICapabilitySerializable<NBTTagCompound> {
    	
    	private final ItemStackHandler inventory;
    	
    	public KitbagProvider() {
    		inventory = new ItemStackHandler( 117 ); // 107 to 117
    	}
    	
    	@Override
    	public NBTTagCompound serializeNBT() {
    		return inventory.serializeNBT();
    	}
    
    	public void deserializeNBT( NBTTagCompound nbt ) {
    		inventory.deserializeNBT( nbt );
    	}
    
    	@Override
    	public boolean hasCapability( Capability<?> capability, EnumFacing facing ) {
    		if( capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public <T> T getCapability( Capability<T> capability, EnumFacing facing ) {
    		if( capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ) {
    			return (T) inventory; 
    		}
    		return null;
    	}
    	
    }
    

    Et cela fonctionne bien, par contre la ou cela me pose souci c'est que ce n'est pas l'effet que je veux, je m'explique : actuellement l'inventaire en question est sauvegarder dans l'item, hors je veux que celui-ci soit sauvegarder comme si c'étais un enderchest ( que chaque item ouvre le même inventaire et non un inventaire unique lié à chaque item ), je crois savoir que l'enderchest est sauvegarder dans le joueur directement, de quel manière je pourrait reproduire cela ?
    Genre : j'enregistre un NBTag au joueur ( par exemple lorsqu'il spawn / respawn en vérifiant si celui-ci existe déjà ou non ), puis dans mon item je charge le NBTag lié au joueur et non celui de l'item ? je en sais pas trop comment procéder même si je pense avoir une bonne idée de base.


  • Moddeurs confirmés Rédacteurs Administrateurs

    Tu attaches comment ta capability actuellement ?



  • Actuellement via mon item et je pense que c'est là mon souci, car au lieu d'attacher la capability au joueur puis d'y faire appel via l'item je fais sa :

    package com.kporal.mcplus.items;
    
    import com.kporal.mcplus.Main;
    import com.kporal.mcplus.items.kitbag.KitbagProvider;
    
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.EntityLivingBase;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.ActionResult;
    import net.minecraft.util.EnumActionResult;
    import net.minecraft.util.EnumHand;
    import net.minecraft.world.World;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    
    public class BookMysteries extends Item {
    	
    	public BookMysteries() {
    		
    		this.setRegistryName( "bookmysteries" );
    		this.setTranslationKey( "bookmysteries" );
    		this.setCreativeTab( Main.mcptab );
    		this.setMaxStackSize( 1 );
    		
    	}
    
    	public ActionResult<ItemStack> onItemRightClick( World w, EntityPlayer p, EnumHand e ) {
    		if( !w.isRemote ) {
    			p.openGui( Main.instance, 0, w, e.ordinal(), -1, -1 );
    		}
    		
    		return new ActionResult<ItemStack>( EnumActionResult.PASS, p.getHeldItemMainhand() );
    	}
    
    	public void onPlayerStoppedUsing( ItemStack stack, World worldIn, EntityLivingBase entityLiving, int timeLeft ) {}
    	
    	@Override
    	public ICapabilityProvider initCapabilities( ItemStack item, NBTTagCompound nbt ) {
    		if( item.getItem() == Main.bookmysteries ) {
    			return new KitbagProvider();
    		}
    		return null;
    	}
    	
    }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    Yep c'est ça, si tu veux le même comportement que l'ender chest il faut l'attacher au joueur.



  • Bon la possibilité qui me viens à l'esprit pour attacher la capability au joueur est d'utiliser les event PlayerEvent.Clone et EntityJoinWorldEvent, par contre après via l'item je ne sais pas comment procéder pour ouvrir la capability lié au joueur .. et vue l'heure je verrais sa demain 😄


  • Moddeurs confirmés Rédacteurs Administrateurs

    Dans la fonction onItemRightClick tu as le joueur en argument, tu peux depuis ce dernier obtenir la capa :

    if(p.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null)) {
                   KitbagProvider cap = event.player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
    

    Et pour attacher la capability il fau utiliser AttachCapabilitiesEvent<Entity>.



  • Bon j'ai tenter de créer ma propre capability etc etc et ... elle fonctionne ( si on peux dire ça ) mais le résultat est juste pas du tout celui attendu ! ( bref en gros j'ai merder quelque pars sans doute ) le souci étant que cela me fait modifier beaucoup de chose dans mes autres classes tout en implémentant le code nécessaire à la création de la capability, utilisant par défaut CapabilityItemHandler.ITEM_HANDLER_CAPABILITY pour l'inventaire de mon item, je me suis dis, pourquoi pas tenté de faire :
    VoidStorageCapability

    package com.kporal.mcplus.capabilities;
    
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.CapabilityInject;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.IItemHandler;
    
    public class VoidStorageCapability extends CapabilityItemHandler {
    
    	@CapabilityInject(IItemHandler.class)
        public static Capability<IItemHandler> VOID_STORAGE_CAPABILITY = null;
    	
    }
    

    VoidStorageProvider

    package com.kporal.mcplus.capabilities;
    
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.common.capabilities.ICapabilitySerializable;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.ItemStackHandler;
    
    public class VoidStorageProvider implements ICapabilityProvider, ICapabilitySerializable<NBTTagCompound> {
    
    	private final ItemStackHandler inventory;
    	
    	public VoidStorageProvider() {
    		inventory = new ItemStackHandler( 117 );
    	}
    	
    	@Override
    	public NBTTagCompound serializeNBT() {
    		return inventory.serializeNBT();
    	}
    
    	@Override
    	public void deserializeNBT( NBTTagCompound nbt ) {
    		inventory.deserializeNBT( nbt );
    	}
    
    	@Override
    	public boolean hasCapability( Capability<?> capability, EnumFacing facing ) {
    		if( capability == VoidStorageCapability.VOID_STORAGE_CAPABILITY ) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public <T> T getCapability( Capability<T> capability, EnumFacing facing ) {
    		if( capability == VoidStorageCapability.VOID_STORAGE_CAPABILITY ) {
    			return (T) inventory; 
    		}
    		return null;
    	}
    }
    

    BookMysteries

    package com.kporal.mcplus.items;
    
    import com.kporal.mcplus.Main;
    import com.kporal.mcplus.capabilities.VoidStorageCapability;
    import com.kporal.mcplus.items.kitbag.KitbagProvider;
    
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.EntityLivingBase;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.ActionResult;
    import net.minecraft.util.EnumActionResult;
    import net.minecraft.util.EnumHand;
    import net.minecraft.world.World;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.IItemHandler;
    
    public class BookMysteries extends Item {
    	
    	public BookMysteries() {
    		
    		this.setRegistryName( "bookmysteries" );
    		this.setTranslationKey( "bookmysteries" );
    		this.setCreativeTab( Main.mcptab );
    		this.setMaxStackSize( 1 );
    		
    	}
    
    	public ActionResult<ItemStack> onItemRightClick( World w, EntityPlayer p, EnumHand e ) {
    		if( !w.isRemote ) {
    			p.openGui( Main.instance, 0, w, e.ordinal(), -1, -1 );
    			if( p.hasCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null )) {
    				
    				IItemHandler cap = p.getCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null );
    				IItemHandler own = p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null );
    				
    				for( int i = 0; i < own.getSlots(); i++ ) {
    					own.insertItem( i, cap.getStackInSlot( i ), false );
    				}
    				
    			}
    		}
    		return new ActionResult<ItemStack>( EnumActionResult.PASS, p.getHeldItemMainhand() );
    	}
    
    	public void onPlayerStoppedUsing( ItemStack stack, World worldIn, EntityLivingBase entityLiving, int timeLeft ) {}
    	
    	@Override
    	public ICapabilityProvider initCapabilities( ItemStack item, NBTTagCompound nbt ) {
    		return new KitbagProvider();
    	}
    }
    

    Alors le but est de créer une copie de l'inventaire de mon item ( au niveau code ) pour faciliter tous les échange que je ferais dessus via le Gui ( qui inclura le workbench et un furnace ... ).
    Bref Le résultat précédent est le même que celui que j'obtiens ici ( avec quelques erreurs en moins cependant ! ), en somme, j'ai une loop ( qui fais crash le jeux ) :

    at com.kporal.mcplus.items.kitbag.KitbagProvider.serializeNBT(KitbagProvider.java:23)
    at com.kporal.mcplus.items.kitbag.KitbagProvider.serializeNBT(KitbagProvider.java:1)
    at net.minecraftforge.common.capabilities.CapabilityDispatcher.serializeNBT(CapabilityDispatcher.java:123)
    at net.minecraft.item.ItemStack.writeToNBT(ItemStack.java:262)
    

    Mais je crois savoir ou est mon erreur ...



  • Bon bah mon souci viens de là ( je suppose ) :

    @SubscribeEvent
    	public void addCapability( AttachCapabilitiesEvent<Entity> event ) {
    		//System.out.println( "test debug coucou" );
    		if( event.getObject() instanceof EntityPlayer ) {
    			//System.out.println( "test debug coucou playerentity" );
    			EntityPlayer p = ( EntityPlayer ) event.getObject();
    			if( !p.world.isRemote ) {
    
    				if( !p.hasCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null )) {
    					//p.getCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null );
    					//event.addCapability( new ResourceLocation( Main.MODID, "voidstorage" ), new VoidStorageProvider() );
    					System.out.println( Main.NAME + " :: Capability > voidstorage added for " + p.getName() );
    				}
    			}
    		}
    	}
    

    Pourquoi ? bah simplement car mon 3e message de debug ne s'affiche "jamais" ... donc forte chance que VoidStorageCapability.VOID_STORAGE_CAPABILITY doit posé problème, sauf que ... je n'ai aucune erreur ... j'ai simplement répliquer CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, qui s'enregistre lui même, donc là je suis perdu lol ...


  • Moddeurs confirmés Rédacteurs Administrateurs

    Perso je n'ai jamais mit de check dans cette event, j'ajoute la capa au joueur à chaque fois que l'event est appelé.



  • Ok, je vaid tester ça alors; ce qui devrais me donner :

    @SubscribeEvent
    	public void addCapability( AttachCapabilitiesEvent<Entity> event ) {
    		if( event.getObject() instanceof EntityPlayer ) {
    			event.addCapability( new ResourceLocation( Main.MODID, "voidstorage" ), new VoidStorageProvider() );
    		}
    	}
    

    Par contre je ne suis aps certain concernant mon ResourceLocation, je vais tester cela.



  • Bon la capability est clairement instancier maintenant, du coup merci !
    Par contre, je garde la loop qui fait crash le jeux et je suppose que cela viens d'ici mais ... aucune certitude :

    public ActionResult<ItemStack> onItemRightClick( World w, EntityPlayer p, EnumHand e ) {
    		if( !w.isRemote ) {
    			p.openGui( Main.instance, 0, w, e.ordinal(), -1, -1 );
    			if( p.hasCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null )) {
    				
    				IItemHandler cap = p.getCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null );
    				IItemHandler own = p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null );
    				
    				for( int i = 0; i < own.getSlots(); i++ ) {
    					own.insertItem( i, cap.getStackInSlot( i ), false );
    				}
    			}
    		}
    		return new ActionResult<ItemStack>( EnumActionResult.PASS, p.getHeldItemMainhand() );
    	}
    
    	public void onPlayerStoppedUsing( ItemStack stack, World worldIn, EntityLivingBase entityLiving, int timeLeft ) {}
    	
    	@Override
    	public ICapabilityProvider initCapabilities( ItemStack item, NBTTagCompound nbt ) {
    		return new KitbagProvider();
    	}
    
    package com.kporal.mcplus.capabilities;
    
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.common.capabilities.ICapabilitySerializable;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.ItemStackHandler;
    
    public class VoidStorageProvider implements ICapabilityProvider, ICapabilitySerializable<NBTTagCompound> {
    
    	private final ItemStackHandler voidStorageContainer;
    	
    	public VoidStorageProvider() {
    		voidStorageContainer = new ItemStackHandler( 117 );
    	}
    	
    	@Override
    	public NBTTagCompound serializeNBT() {
    		return voidStorageContainer.serializeNBT();
    	}
    
    	@Override
    	public void deserializeNBT( NBTTagCompound nbt ) {
    		voidStorageContainer.deserializeNBT( nbt );
    	}
    
    	@Override
    	public boolean hasCapability( Capability<?> capability, EnumFacing facing ) {
    		if( capability == VoidStorageCapability.VOID_STORAGE_CAPABILITY ) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public <T> T getCapability( Capability<T> capability, EnumFacing facing ) {
    		if( capability == VoidStorageCapability.VOID_STORAGE_CAPABILITY ) {
    			return (T) voidStorageContainer; 
    		}
    		return null;
    	}
    }
    
    package com.kporal.mcplus.items.kitbag;
    
    import net.minecraft.nbt.NBTBase;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.CapabilityInject;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.common.capabilities.ICapabilitySerializable;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.ItemStackHandler;
    
    public class KitbagProvider implements ICapabilityProvider, ICapabilitySerializable<NBTTagCompound> {
    	
    	private final ItemStackHandler inventory;
    	
    	public KitbagProvider() {
    		inventory = new ItemStackHandler( 117 );
    	}
    	
    	@Override
    	public NBTTagCompound serializeNBT() {
    		return inventory.serializeNBT();
    	}
    
    	@Override
    	public void deserializeNBT( NBTTagCompound nbt ) {
    		inventory.deserializeNBT( nbt );
    	}
    
    	@Override
    	public boolean hasCapability( Capability<?> capability, EnumFacing facing ) {
    		if( capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public <T> T getCapability( Capability<T> capability, EnumFacing facing ) {
    		if( capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ) {
    			return (T) inventory; 
    		}
    		return null;
    	}
    }
    

    La loop étant uniquement composé de :

    at net.minecraft.item.ItemStack.writeToNBT(ItemStack.java:262)
    at net.minecraftforge.items.ItemStackHandler.serializeNBT(ItemStackHandler.java:183)
    at com.kporal.mcplus.items.kitbag.KitbagProvider.serializeNBT(KitbagProvider.java:23)
    at com.kporal.mcplus.items.kitbag.KitbagProvider.serializeNBT(KitbagProvider.java:1)
    

    Mais ... après relecture de moi même en écrivant, chaque Capability dois bien avoir sa propre interface ? car si oui la loop est normal vue que :

    package com.kporal.mcplus.capabilities;
    
    import net.minecraft.item.ItemStack;
    import net.minecraft.nbt.NBTBase;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.nbt.NBTTagList;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.CapabilityInject;
    import net.minecraftforge.common.capabilities.CapabilityManager;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.IItemHandler;
    import net.minecraftforge.items.IItemHandlerModifiable;
    import net.minecraftforge.items.ItemStackHandler;
    
    public class VoidStorageCapability extends CapabilityItemHandler {
    
    	@CapabilityInject(IItemHandler.class)
        public static Capability<IItemHandler> VOID_STORAGE_CAPABILITY = null;
    	
    	public static void register()
        {
            CapabilityManager.INSTANCE.register(IItemHandler.class, new Capability.IStorage<IItemHandler>()
            {
                @Override
                public NBTBase writeNBT(Capability<IItemHandler> capability, IItemHandler instance, EnumFacing side)
                {
                    NBTTagList nbtTagList = new NBTTagList();
                    int size = instance.getSlots();
                    for (int i = 0; i < size; i++)
                    {
                        ItemStack stack = instance.getStackInSlot(i);
                        if (!stack.isEmpty())
                        {
                            NBTTagCompound itemTag = new NBTTagCompound();
                            itemTag.setInteger("Slot", i);
                            stack.writeToNBT(itemTag);
                            nbtTagList.appendTag(itemTag);
                        }
                    }
                    return nbtTagList;
                }
    
                @Override
                public void readNBT(Capability<IItemHandler> capability, IItemHandler instance, EnumFacing side, NBTBase base)
                {
                    if (!(instance instanceof IItemHandlerModifiable))
                        throw new RuntimeException("IItemHandler instance does not implement IItemHandlerModifiable");
                    IItemHandlerModifiable itemHandlerModifiable = (IItemHandlerModifiable) instance;
                    NBTTagList tagList = (NBTTagList) base;
                    for (int i = 0; i < tagList.tagCount(); i++)
                    {
                        NBTTagCompound itemTags = tagList.getCompoundTagAt(i);
                        int j = itemTags.getInteger("Slot");
    
                        if (j >= 0 && j < instance.getSlots())
                        {
                            itemHandlerModifiable.setStackInSlot(j, new ItemStack(itemTags));
                        }
                    }
                }
            }, ItemStackHandler::new);
        }
    }
    

    Ce qui expliquerais tout !



  • Ok ok j'ai faux sur toute la ligne, j'ai simplement modifier mon item en supprimant sont initCapabilities sans motifier le code restant et en utilisant simplement :

    package com.kporal.mcplus.items.kitbag;
    
    import com.kporal.mcplus.capabilities.VoidStorageCapability;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.common.network.IGuiHandler;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.IItemHandler;
    
    public class KitbagGuiHandler implements IGuiHandler {
    
    	@Override
    	public Object getServerGuiElement( int ID, EntityPlayer p, World w, int x, int y, int z ) {
    		//return new KitbagContainer( (IItemHandler) p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    		return new KitbagContainer(( IItemHandler ) p.getCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null ), p );
    	}
    
    	@Override
    	public Object getClientGuiElement( int ID, EntityPlayer p, World w, int x, int y, int z ) {
    		//return new KitbagGui( (IItemHandler) p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    		return new KitbagGui(( IItemHandler ) p.getCapability( VoidStorageCapability.VOID_STORAGE_CAPABILITY, null ), p );
    	}
    }
    

    Je n'ai plus de crash, ni de loop, par contre je suis bien censé ouvrir VoidStorageCapability.VOID_STORAGE_CAPABILITY mais ... il me duplique l'inventaire du joueur et non le voidStorageContainer = new ItemStackHandler( 117 );, des idées d'où j'ai faux ?


  • Moddeurs confirmés Rédacteurs Administrateurs

    Tu peux envoyer la classe KitbagContainer ?



  • KitbagContainer

    package com.kporal.mcplus.items.kitbag;
    
    import com.kporal.mcplus.container.FuelFurnaceSlot;
    import com.kporal.mcplus.container.OutputFurnaceSlot;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.inventory.Container;
    import net.minecraft.inventory.IContainerListener;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.inventory.InventoryCraftResult;
    import net.minecraft.inventory.InventoryCrafting;
    import net.minecraft.inventory.Slot;
    import net.minecraft.inventory.SlotCrafting;
    import net.minecraft.item.ItemStack;
    import net.minecraft.util.NonNullList;
    import net.minecraft.world.World;
    import net.minecraftforge.items.IItemHandler;
    import net.minecraftforge.items.SlotItemHandler;
    
    public class KitbagContainer extends Container {
        
        public EntityPlayer player;
        public World world;
        private int xPos = 5, yPos = 5, iid = 0, iRows = 8, iLines = 13, nSlots = iRows * iLines;
        
    	public KitbagContainer( IItemHandler i, EntityPlayer p ) {
    		
    		player = p;
    		world = p.world;
    		
            // Container inventory :: 0 > 103
    		for( int y = 0; y < iRows; ++y ) {
    			for( int x = 0; x < iLines; ++x ) {
    				addSlotToContainer( new SlotItemHandler( i, iid, xPos + x * 18, yPos + y * 18 ));
    				iid++;
    			}
    		}
    		
    		// Workbench slots :: 104 > 113
    		addSlotToContainer( new SlotItemHandler( i, iid, 167, 170 )); iid++;
            for (int y = 0; y < 3; ++y) {
            	for (int x = 0; x < 3; ++x) {
            		addSlotToContainer( new SlotItemHandler( i, iid, 185 + x * 18, 152 + y * 18 ));
            		iid++;
            	}
            }
    		
    		// Furnace slots :: 114 > 116
    		addSlotToContainer( new SlotItemHandler( i, iid, 221, 209 )); iid++;
    		addSlotToContainer( new FuelFurnaceSlot( i, iid, 185, 209 )); iid++;
    		addSlotToContainer( new OutputFurnaceSlot( p, i, iid, 167, 209 ));
    		
    		yPos = 152;
    		
    		// Player inventory
    		for( int y = 0; y < 3; ++y ) {
    			for( int x = 0; x < 9; ++x ) {
    				addSlotToContainer( new Slot( p.inventory, x + y * 9 + 9, xPos + x * 18, yPos + y * 18 ));
    			}
    		}
    		
    		// Player hotbar
    		for( int x = 0; x < 9; ++x ) {
    			addSlotToContainer( new Slot( p.inventory, x, xPos + x * 18, 209 ));
    		}
    	}
    	
    	@Override
    	public ItemStack transferStackInSlot( EntityPlayer playerIn, int index ) {
            
    		ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = inventorySlots.get(index);
    
            if( slot != null && slot.getHasStack() ) {
                
            	ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                
                if( index == 104 ) {
                    itemstack1.getItem().onCreated(itemstack1, world, playerIn);
                    
                    if( !this.mergeItemStack(itemstack1, 0, nSlots, false )) {
                    	return ItemStack.EMPTY;
                    }
    
                    slot.onSlotChange( itemstack1, itemstack );
                }
                
                else if( index < nSlots ) {
                    if( !mergeItemStack( itemstack1, nSlots, inventorySlots.size(), true )) {
                    	return ItemStack.EMPTY;
                    }
                }
                
                else if( !mergeItemStack( itemstack1, 0, nSlots, 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( playerIn, itemstack1 );
    
                if( index == 104 ) {
                	playerIn.dropItem( itemstack2, false );
                }
            }
    
            return itemstack;
    	}
    	
    	@Override
    	public boolean canInteractWith( EntityPlayer p ) {
    		return true;
    	}
    }
    


  • Ce qui donne en jeux :
    inventory



  • Ok je reviens à la charge car j'ai ... progressé ? ( hum lol ou pas ), j'ai supprimer tous le contenu superflu, utilisant ni plus ni moins que le code de base que j'utilisai pour instancier mon item, après des heures de test j'ai décider de modifier mon point de vue et donc de procéder comme ceci :

    EventsHandler.java

    @SubscribeEvent
    	public void addCapability( AttachCapabilitiesEvent<Entity> event ) {
    		if( event.getObject() instanceof EntityPlayer ) {
    			event.addCapability( new ResourceLocation( Main.MODID, "voidStorage" ), new KitbagProvider() );
    			System.out.println( Main.NAME + " :: Capability > voidStorage added for ..." );
    		}
    	}
    

    KitbagGuiHandler

    package com.kporal.mcplus.items.kitbag;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.entity.player.EntityPlayerMP;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.common.network.IGuiHandler;
    import net.minecraftforge.items.CapabilityItemHandler;
    import net.minecraftforge.items.IItemHandler;
    
    public class KitbagGuiHandler implements IGuiHandler {
    
    	@Override
    	public Object getServerGuiElement( int ID, EntityPlayer p, World w, int x, int y, int z ) {
    		//return new KitbagContainer( (IItemHandler) p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    		IItemHandler iii = ( IItemHandler ) p.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null );
    		System.out.println( "MSDEBUG<SERVER> :: " + iii.getSlots() + " " + iii.toString() );
    		return new KitbagContainer(( IItemHandler ) p.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    	}
    
    	@Override
    	public Object getClientGuiElement( int ID, EntityPlayer p, World w, int x, int y, int z ) {
    		//return new KitbagGui( (IItemHandler) p.getHeldItemMainhand().getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    		IItemHandler iii = ( IItemHandler ) p.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null );
    		System.out.println( "MSDEBUG<CLIENT> :: " + iii.getSlots() + " " + iii.toString() );
    		return new KitbagGui(( IItemHandler ) p.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null ), p );
    	}
    }
    

    Je n'ai rien modifier d'autre, le reste du code pointe sur CapabilityItemHandler.ITEM_HANDLER_CAPABILITY car pourquoi créer une nouvelle capability alors que celle-ci est déjà toute prête !

    BREF, point important :

    [13:52:24] [Server thread/INFO] [STDOUT]: [com.kporal.mcplus.items.kitbag.KitbagGuiHandler:getServerGuiElement:17]: MSDEBUG<SERVER> :: 41 net.minecraftforge.items.wrapper.PlayerInvWrapper@42179e3b
    [13:52:24] [main/INFO] [STDOUT]: [com.kporal.mcplus.items.kitbag.KitbagGuiHandler:getClientGuiElement:25]: MSDEBUG<CLIENT> :: 41 net.minecraftforge.items.wrapper.PlayerInvWrapper@3ac9e8b8
    

    Euh oui, cela ne pointe pas du tout sur la capability mais sur le player inventory ....... ... ..... !
    Des idées ?



  • Désoler pour le double post ! mais là ... je viens simplement de Reset mon world ( encore une fois ) mais cette fois-ci en supprimant simplement mon AttachCapabilitiesEvent<Entity> et .. il s'avère que le résultat est exactement le même, ce qui peux signifier que ma capability initiale n'est simplement à aucun moment attacher au joueur ! Je vais faire d'autres test pour voir ce qu'il se passe 😕


Log in to reply