我们本次在模组中实现客户端向服务器发送数据的功能。
演示效果
演示效果
演示效果
1.新建packet包,包中新建PacketHandler类:
PacketHandler.java
package com.joy187.mcjoygun.packet;
import com.joy187.mcjoygun.Main;
import com.joy187.mcjoygun.utils.SerializableUtil;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.INetHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLEventChannel;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
public class PacketHandler {
// public static final String[] CHANNELS = {"testmsg", "levelupclasses"};
// public static FMLEventChannel initChannel,otherChannel;
public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(Main.MODID);
static int id = 0;
public static void init() {
PacketHandler handler = new PacketHandler();
//注册该数据包类
INSTANCE.registerMessage(MessageRangeAttackHandler.class, MessageRangeAttack.class, id++, Side.SERVER);
MinecraftForge.EVENT_BUS.register(handler);
}
}
在项目主类Main中的preInit类中添加PacketHandler
的初始化函数:
Main.java
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
PacketHandler.init();
//RegistryHandler.preInitRegistries(event);
}
2.packet包中新建一个MessageRangeAttack类:
MessageRangeAttack.java
package com.joy187.mcjoygun.packet;
import com.google.common.collect.Maps;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import java.util.Map;
public class MessageRangeAttack implements IMessage {
public RangeAttackState mode;
//定义几个可以枚举的攻击状态,之后会用到
public enum RangeAttackState{、
UPKEY(1),
BLISTERING(2),
STORM(3);
private final byte data;
public static RangeAttackState getState(byte data){
return stateMap.get(data);
}
private static final Map<Byte,RangeAttackState> stateMap = Maps.newHashMap();
static {
for (RangeAttackState value : values())
{
stateMap.put(value.data, value);
}
}
RangeAttackState(int value){
data = (byte)value;
}
public byte getData() {
return data;
}
}
public MessageRangeAttack(){};
public MessageRangeAttack(RangeAttackState mode){
this.mode = mode;
}
@Override
public void fromBytes(ByteBuf buf) {
this.mode = RangeAttackState.getState(buf.readByte());
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeByte(this.mode.getData());
}
}
同时新建一个MessageRangeAttackHandler类,作为上面那个类的管理器:
MessageRangeAttackHandler.java
package com.joy187.mcjoygun.packet;
import com.joy187.mcjoygun.items.ToolXuanFeng;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
public class MessageRangeAttackHandler implements IMessageHandler<MessageRangeAttack,IMessage> {
@Override
public IMessage onMessage(MessageRangeAttack message, MessageContext ctx) {
if(ctx.getServerHandler() == null) return null;
EntityPlayerMP entityPlayer = ctx.getServerHandler().player;
if(entityPlayer == null) return null;
entityPlayer.getServerWorld().addScheduledTask(() -> {
ItemStack stack = entityPlayer.getHeldItem(EnumHand.MAIN_HAND);
//检查玩家手上是否拿着特定的武器,如果持有该武器就可以向服务器发送数据包
if (!stack.isEmpty() && stack.getItem() instanceof ToolXuanFeng) {
//输出yes
System.out.println("yes");
((ToolXuanFeng) stack.getItem()).doRangeAttack(stack, entityPlayer, message.mode);
}
});
return null;
}
}
3.我们在KeyboardManager中给这个武器绑定两个键位事件:
KeyboardManager.java
@Mod.EventBusSubscriber
public class KeyboardManager {
public static void init() {
for (KeyBinding key:
ClientProxy.KEY_BINDINGS) {
ClientRegistry.registerKeyBinding(key);
}
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public static void onKeyPressed(InputEvent.KeyInputEvent event) {
//按键1按下就向服务器发送一个包,攻击状态为UPKEY
if (ClientProxy.KEY1.isPressed()) {
PacketHandler.INSTANCE.sendToServer(new MessageRangeAttack(MessageRangeAttack.RangeAttackState.UPKEY));
}
//按键2按下就向服务器发送一个包,攻击状态为STORM
if(ClientProxy.KEY2.isPressed()){
PacketHandler.INSTANCE.sendToServer(new MessageRangeAttack(MessageRangeAttack.RangeAttackState.STORM));
}
}
}
在项目主类中添加键位管理的初始化函数:
Main.java
@EventHandler
public void init(FMLInitializationEvent event)
{
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
//添加键位管理的注册函数
if (!proxy.isServer())
{
KeyboardManager.init();
}
}
4.准备一个武器类ToolXuanFeng
,对范围攻击状态进行定义:
ToolXuanFeng.java
package com.joy187.mcjoygun.items;
import com.joy187.mcjoygun.Main;
import com.joy187.mcjoygun.init.ItemInit;
import com.joy187.mcjoygun.packet.MessageRangeAttack;
import com.joy187.mcjoygun.packet.PacketHandler;
import com.joy187.mcjoygun.utils.IhasModel;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Enchantments;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import java.util.EnumSet;
public class ToolXuanFeng extends ItemAxe implements IhasModel {
public ToolXuanFeng(String name, CreativeTabs tab, ToolMaterial material) {
super(material,34.0F,-3.3F);
setUnlocalizedName(name);
setRegistryName(name);
setCreativeTab(tab);
ItemInit.ITEMS.add(this);
}
//该武器的范围攻击函数
public void doRangeAttack(ItemStack item, EntityLivingBase entity, MessageRangeAttack.RangeAttackState mode) {
//函数被调用时输出okokok
System.out.println("okokok");
switch(mode) {
//当攻击状态为UPKEY时,就释放大爆炸
case UPKEY: {
entity.world.createExplosion(entity, entity.posX, entity.posY, entity.posZ, (float) (4.0D + entity.getRNG().nextDouble() * 1.5D * 1), true);
break;
}
//当攻击状态为STORM时,就产生雷鸣
case STORM:{
entity.world.addWeatherEffect(new EntityLightningBolt(entity.world, entity.posX, entity.posY, entity.posZ, true));
//entity.world.setLastLightningBolt(2);
break;
}
}
}
@Override
public void registerModels() {
Main.proxy.registerItemRenderer(this, 0, "inventory");
}
}
在ItemInit中注册该武器:
ItemInit.java
public static final ItemAxe FENBAOCHUI = new ToolXuanFeng("xuanfengaxe", Main.ITEM_TAB, MATERIAL_XUANFENG);