Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

Entity#capabilities field is null on servers


PlanetTeamSpeak
 Share

Recommended Posts

I made a capability for an extended reach which works great on singleplayer, but on servers/multiplayer it doesn't work at all as the capability returned using EntityPlayer#getCapability(Capability, EnumFacing) returns null. After using some basic reflection I found out this is probably because the Entity#capabilities field is null, even though this is not the case on singleplayer.

CommonEventHandler.java (registered on both the client and the server):

package com.ptsmods.morecommands.miscellaneous;

import com.ptsmods.morecommands.miscellaneous.Reference.LogType;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;

public class CommonEventHandler extends EventHandler {

	public CommonEventHandler() {}

	@SubscribeEvent
	public void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
		if (event.getObject() instanceof EntityPlayer) Reference.print(LogType.INFO, "Attaching capability to player");
		if (!event.getCapabilities().containsKey(new ResourceLocation(Reference.MOD_ID, "reach")) && event.getObject() instanceof EntityPlayer) event.addCapability(new ResourceLocation(Reference.MOD_ID, "reach"), new ReachProvider());
	}

	@SubscribeEvent
	public void onPlayerClone(PlayerEvent.Clone event) {
		Reference.print(LogType.INFO, "Changed world, cloning reach capability.", event.getOriginal().getCapability(ReachProvider.reachCap, null).get(), FMLCommonHandler.instance().getSide(), Reference.isSingleplayer());
		event.getEntityPlayer().getCapability(ReachProvider.reachCap, null).set(FMLCommonHandler.instance().getSide() == Side.SERVER || Reference.isSingleplayer() ? (EntityPlayerMP) event.getEntityPlayer() : null, event.getOriginal().getCapability(ReachProvider.reachCap, null).get());
	}

}

IReach.java:

package com.ptsmods.morecommands.miscellaneous;

import javax.annotation.Nullable;

import net.minecraft.entity.player.EntityPlayerMP;

public interface IReach {

	public float get();

	public void set(float reach);

	public void set(@Nullable EntityPlayerMP player, float reach);

}

Reach.java:

package com.ptsmods.morecommands.miscellaneous;

import javax.annotation.Nullable;

import com.ptsmods.morecommands.net.ServerReachUpdatePacket;

import net.minecraft.entity.player.EntityPlayerMP;

public class Reach implements IReach {

	private float reach = 5;

	public Reach() {}

	@Override
	public float get() {
		return reach;
	}

	@Override
	public void set(float reach) {
		set(null, reach);
	}

	@Override
	public void set(@Nullable EntityPlayerMP player, float reach) {
		this.reach = reach < 1 ? 1F : reach;
		if (player != null) Reference.netWrapper.sendTo(new ServerReachUpdatePacket(reach), player);
	}

}

ReachStorage.java:

package com.ptsmods.morecommands.miscellaneous;

import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTPrimitive;
import net.minecraft.nbt.NBTTagFloat;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.Capability.IStorage;

public class ReachStorage implements IStorage<IReach> {

	public ReachStorage() {}

	@Override
	public NBTBase writeNBT(Capability<IReach> capability, IReach instance, EnumFacing side) {
		return new NBTTagFloat(instance.get());
	}

	@Override
	public void readNBT(Capability<IReach> capability, IReach instance, EnumFacing side, NBTBase nbt) {
		instance.set(null, ((NBTPrimitive) nbt).getFloat());
	}

}

ReachProvider.java:

package com.ptsmods.morecommands.miscellaneous;

import net.minecraft.nbt.NBTBase;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;

public class ReachProvider implements ICapabilitySerializable<NBTBase> {

	@CapabilityInject(IReach.class)
	public static final Capability<IReach>	reachCap	= null;
	private IReach							instance	= reachCap.getDefaultInstance();

	public ReachProvider() {}

	@Override
	public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
		return capability == reachCap;
	}

	@Override
	public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
		return capability == reachCap ? reachCap.<T>cast(instance) : null;
	}

	@Override
	public NBTBase serializeNBT() {
		return reachCap.getStorage().writeNBT(reachCap, instance, null);
	}

	@Override
	public void deserializeNBT(NBTBase nbt) {
		reachCap.getStorage().readNBT(reachCap, instance, null, nbt);
	}

}

And the capability is registered on the client in the preInit method and on the server in the serverStart method using the following line:

CapabilityManager.INSTANCE.register(IReach.class, new ReachStorage(), () -> new Reach());

Altough in the serverStart event it first checks to make sure it's not singleplayer.

Am I doing something wrong is this a collection of some internal problems? (Most likely the former)

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.

Guest
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.

 Share



×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.