Jump to content

Capabilities, how to save to disk?


robertx555

Recommended Posts

Took me a while to get a working capability but now i don't see how i'm supposed to save them to disk. Here is my capability file, it's all registered and it works, just doesn't save 

 


public class Entity_Data
{   
       
    @CapabilityInject(DataInterface.class)
    public static final Capability<DataInterface> Data = null;

    public interface DataInterface {   
    	
        void setLevel(int value);
        int getLevel();
        
    }

    
    public static class EventHandler
    {
        @SubscribeEvent
        public void onEntityConstruct(AttachCapabilitiesEvent evt) 
        {
            evt.addCapability(new ResourceLocation(Ref.MODID, "Data"), new ICapabilitySerializable<NBTTagCompound>()
            {
                DataInterface inst = Data.getDefaultInstance();
                                
                
                @Override
                public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
                    return capability == Data;
                }

                @Override
                public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
                    return capability == Data ? Data.<T>cast(inst) : null;
                }
                
                @Override
                public NBTTagCompound serializeNBT() {             	               	
                    return (NBTTagCompound)Data.getStorage().writeNBT(Data, inst, null);
                }

                @Override
                public void deserializeNBT(NBTTagCompound nbt) {
                    Data.getStorage().readNBT(Data, inst, null, nbt);
                }
                
                
                
            });
        }	

	

       
    }

    
    public static class Storage implements IStorage<DataInterface>
    {
        @Override
        public NBTBase writeNBT(Capability<DataInterface> capability, DataInterface instance, EnumFacing side)
        {        	  	
        	NBTTagCompound nbt = new NBTTagCompound();
        	
        	nbt.setInteger("level", instance.getLevel());
        	
            return nbt;
        }

        @Override
        public void readNBT(Capability<DataInterface> capability, DataInterface instance, EnumFacing side, NBTBase nbt)
        {
        	
        	NBTTagCompound tag = (NBTTagCompound) nbt;
        	
        	instance.setLevel(tag.getInteger("level"));
        	
        	
        }
    }

    public static class DefaultImpl implements DataInterface
    {
        private int level = 1;
        @Override public int getLevel() { return level; }
        @Override public void setLevel(int value) { this.level = value; }
                      
        
    }

 

Also i followed a tutorial on how to make player data persist through death but it doesn't work even though the chat message is sent as a confirmation the code ran

 


	@SubscribeEvent		
	public void onPlayerClone(PlayerEvent.Clone event){
		
		if (!event.getEntityPlayer().world.isRemote) {
		
		 event.getEntityPlayer().sendMessage(new TextComponentString("clone"));
			
		 EntityPlayer player = event.getEntityPlayer();
		
		 DataInterface data = player.getCapability(Entity_Data.Data, null);	
		 		
		 DataInterface oldData = event.getOriginal().getCapability(Entity_Data.Data, null);
		
		 
		 data.setLevel(oldData.getLevel());
		 
		}
	 
	}

 

Thanks for any help!

Edited by robertx555
Link to comment
Share on other sites

2 minutes ago, diesieben07 said:
  • Don't subscribe to the bare AttachCapabilitiesEvent. In this case you want AttachCapabilitiesEvent<Entity> and check that the entity is a player.
  • Where is the data value read/written outside the nbt serialization? Which behavior makes you think it is not persisted?

 

I made a small test for it in servertickevent

 

if (MAIN.player.hasCapability(Entity_Data.Data, null)) {
			
			DataInterface data = MAIN.player.getCapability(Entity_Data.Data, null);			
			
			data.setLevel(data.getLevel() +1);			
					
			MAIN.player.sendMessage( new TextComponentString(data.getLevel()+ " "));

 

Basically an increment every few ticks. I keep seeing increasing numbers.. until i leave game or die. It goes like 1,2,3,4 "i die" 1, 2 ,3 you get the idea. So either i have to save the data somehow or i messed something up with the compatibility

 

Link to comment
Share on other sites

26 minutes ago, diesieben07 said:
  • That is the client player. The client does not save any data. If you want to modify the data, you must do it on the server. The fact that you are accessing this from the server thread only makes things worse, since you are now reaching across logical sides, which causes even more issues.
  • You can't just store a static reference to the player like that. The player object will change when you switch worlds, etc. Just use Minecraft::player directly if you need the client player.

How would i set the player data on the server? 

 

btw i uploaded to github in case it helps 

https://github.com/RobertSkalko/Minecraft-Forge-Singleplayer-MMORPG-like-mod

Link to comment
Share on other sites

Whoa i think i solved it! Thanks!

 

@SubscribeEvent
	public  void onTickCalcStats(TickEvent.PlayerTickEvent event) { 
		
		
		if (event.phase == Phase.END ) {
			
			tick++;
		
		if (tick > 100 && event.player != null && event.side.isServer()) {			
			
			MAIN.player = event.player;
			
			EntityPlayer player = event.player;
						
			getStats();
			
			if (player.hasCapability(Entity_Data.Data, null)) {
			
			DataInterface data = player.getCapability(Entity_Data.Data, null);			
			
			data.setLevel(data.getLevel() +1);			
					
			player.sendMessage( new TextComponentString(data.getLevel()+ " "));
									
			}
			IAttributeInstance health = player.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH);
		    health.setBaseValue(20);	
		    
			tick = 0;
		}
		}
	}
	

 

You said i'm supposed to get player from event.. well servertickevent has no player but TickEvent.PlayerTickEvent does! I changed it and it suddenly magically worked! It saves on death and on quitting game! That answered another question, seems i don't have to call any other saving methods

 

I'm gonna go and remove MAIN.player and update all the stuff.. xD

Edited by robertx555
Link to comment
Share on other sites

i know but things are easier to balance if i only care about 1 player.. for example say i want to spawn random mobs around a player. It becomes more difficult to balance when multiple players are around. 1 player is lvl 100 the other is lvl 1, i would have to make it so both players can play somehow.. which would mean many changes

 

didn't learn that yet, i'll try gitignore, kept hearing about it but now i see why it's useful

 

 

Link to comment
Share on other sites

I know that at least. Btw managed to gitignore build and eclipse folders so here's the new one 

 

https://github.com/RobertSkalko/MMORPG-Mod

 

Now i'm gonna see if i can use capabilities to save NBTTagCompound, i have like 20 stats so having 20 getter and setter functions seem like a disaster.  Anyway it's nearly midnight so i'll do it tomorrow 

 

Thanks for the help! I won't need help anymore soon, got a lot of things to work on now! 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
    • Remove Instant Massive Structures Mod from your server     Add new crash-reports with sites like https://paste.ee/  
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.