Jump to content

[1.15.1] Holding an item and left click in air


Recommended Posts

Posted (edited)

I want to make an item that can shoot a fireball when left click, but I can't figure out how to make it.

Here is the code.

Please tell me in detail what to do.

package arknights.item;

import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.potion.Effect;
import net.minecraft.potion.EffectInstance;
import net.minecraft.stats.Stats;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import org.apache.commons.lang3.tuple.Pair;

import java.util.*;

import static net.minecraft.potion.Effects.*;

public class PureOriginiums extends Item {
    List<Pair<EffectInstance, Float>> effects = new ArrayList<>();
    String playerName = null;

    public PureOriginiums(Properties p_i48476_1_) {
        super(p_i48476_1_);
    }
    
    @Override
    public UseAction getUseAction(ItemStack stack) {
        return UseAction.EAT;
    }

    @Override
    public int getUseDuration(ItemStack stack) {
        return 32;
    }

    //public static final Food PUREORIGINIUMS = (new Food.Builder()).hunger(10).saturation(0.3F).effect(new EffectInstance(Effects.SPEED, 400, 255), 1.0F).build();
    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
        this.effects.clear();
        this.playerName = playerIn.getScoreboardName();
        ItemStack itemstack = playerIn.getHeldItem(handIn);
        playerIn.setActiveHand(handIn);
        return ActionResult.func_226249_b_(itemstack);
    }

    @Override
    public ItemStack onItemUseFinish(ItemStack stack, World worldIn, LivingEntity entityLiving) {
        //String playerName = entityLiving.getScoreboardName()
        int effectId = (int)(1+Math.random()*(10-1+1));
        return onOriginniumsEaten(worldIn, stack, (PlayerEntity) entityLiving);
    }

    public ItemStack onOriginniumsEaten(World p_213357_1_, ItemStack p_213357_2_, PlayerEntity playerEntity) {
        playerEntity.getFoodStats().addStats(20,20);
        playerEntity.addStat(Stats.ITEM_USED.get(p_213357_2_.getItem()));
        p_213357_1_.playSound(null, playerEntity.func_226277_ct_(), playerEntity.func_226278_cu_(), playerEntity.func_226281_cx_(), playerEntity.getEatSound(p_213357_2_), SoundCategory.NEUTRAL, 1.0F, 1.0F + (p_213357_1_.rand.nextFloat() - p_213357_1_.rand.nextFloat()) * 0.4F);
        this.effectsList();
        applyFoodEffects(p_213357_2_, p_213357_1_, playerEntity);
        //playerEntity.setHealth(20.0F);
        //playerEntity.addPotionEffect(new EffectInstance(Effects.SPEED, 600, 10));
        if ( !(playerEntity).abilities.isCreativeMode) {
            p_213357_2_.shrink(1);
        }
        return p_213357_2_;
    }

    private void applyFoodEffects(ItemStack p_213349_1_, World p_213349_2_, LivingEntity p_213349_3_) {
        for(Pair<EffectInstance, Float> pair : this.effects) {
            if (!p_213349_2_.isRemote && pair.getLeft() != null && p_213349_2_.rand.nextFloat() < pair.getRight()) {
                p_213349_3_.addPotionEffect(new EffectInstance(pair.getLeft()));
            }
        }
    }

    void effectsList(){
        if( /*this.playerName == "Dev" || */this.playerName.regionMatches(0, "Dr", 0, 2)){
            addEffectToList(SPEED, 600, 10);
            addEffectToList(HASTE, 600, 255);
            addEffectToList(STRENGTH, 200, 10);
            addEffectToList(JUMP_BOOST, 600, 2);
            addEffectToList(RESISTANCE, 600, 3);
            addEffectToList(FIRE_RESISTANCE, 600, 2);
            addEffectToList(WATER_BREATHING, 600, 1);
            addEffectToList(NIGHT_VISION, 600, 1);
            addEffectToList(DOLPHINS_GRACE, 600, 1);
        } else {
            int random1,random2,random3;
            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(SPEED, random2, random3);
                    break;
                case 2:
                    addEffectToList(SLOWNESS, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(HASTE, random2, random3);
                    break;
                case 2:
                    addEffectToList(MINING_FATIGUE, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*2);
            switch(random1){
                case 1:
                    addEffectToList(STRENGTH, random2, random3);
                    break;
                case 2:
                    addEffectToList(WEAKNESS, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*5);
            switch(random1){
                case 1:
                    addEffectToList(JUMP_BOOST, random2, random3);
                    break;
                    default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(NAUSEA, random2, 2);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*3);
            switch(random1){
                case 1:
                    addEffectToList(RESISTANCE, random2, random3);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(FIRE_RESISTANCE, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(WATER_BREATHING, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(BLINDNESS, random2, 1);
                    break;
                case 2:
                    addEffectToList(NIGHT_VISION, random2, 1);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(SLOW_FALLING, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(DOLPHINS_GRACE, random2, 1);
                    break;
                default: break;
            }

            addEffectToList(WITHER, 800, 2);
        }

    }

    void addEffectToList(Effect effect, int time, int level){
        this.effects.add(Pair.of(new EffectInstance(effect, time, level), 1.0F));
    }
}

Simple introduction to this item:

It can be eaten when right click just like common food, but when you left click, it will become a wand which can shoot fire ball.

If your player name begins with "Dr" you will get good effects, or you will get some random effects and you may probably die because of wither.

 

Thanks for your help : )

Edited by NGYF
Posted
22 hours ago, diesieben07 said:

You can use PlayerInteractEvent.LeftClickEmpty.

Thanks for your help, but may I ask you to tell me how to use it in detail?

Actually I have read some posts about it in the forum and try to make an event handler.

 

Should I use PlayerInteractEvent.LeftClickEmpty in this way?

public class LeftClickEventHandler {
	@SubscribeEvent
	public ActionResult<ItemStack> leftClick(LeftClickEmpty event) {
		//spawn a fireball
	}

}

 

It is said that I should use pakets to notify the server. What should I do? I have read the forge documents, but I don't know what to do and I can't find any example in the forum. So could you please give me an example about it?

Posted
22 hours ago, diesieben07 said:

Yes, the empty left click is not automatically sent to the server, so you can only receive that event on the client.

To make it spawn entities, you need to send a packet to the server and then spawn the entity there.

Thank you.

But I'm still a bit confused about handling packets.

There are two classes called MyMessage and EntityPlayerMP. I think I should replace EntityPlayerMP with my leftclick class.But if it is right, what does MyMessage refer to?

I will appreciate it if you can tell me how to handle packets properly.?

Posted
On 1/18/2020 at 10:10 PM, diesieben07 said:

Did you even read the linked documentation?

Yes, but maybe I miss something...

I'm sorry.

Thanks for your patience, I will try it myself.

Posted
On 1/17/2020 at 6:24 PM, diesieben07 said:

Yes, the empty left click is not automatically sent to the server, so you can only receive that event on the client.

To make it spawn entities, you need to send a packet to the server and then spawn the entity there.

Sorry to bother you again.

I try to send packets to server when I left click the item, but it throws an error.

Here is the error:

Spoiler

Description: Unexpected error

java.lang.ExceptionInInitializerError: null
    at arknights.item.BaseItem.emptyLeftClick(BaseItem.java:21) ~[classes/:?] {re:classloading}
    at net.minecraftforge.eventbus.EventBus.doCastFilter(EventBus.java:212) ~[eventbus-2.0.0-milestone.1-service.jar:?] {}
    at net.minecraftforge.eventbus.EventBus.lambda$addListener$11(EventBus.java:204) ~[eventbus-2.0.0-milestone.1-service.jar:?] {}
    at net.minecraftforge.eventbus.EventBus.post(EventBus.java:258) ~[eventbus-2.0.0-milestone.1-service.jar:?] {}
    at net.minecraftforge.common.ForgeHooks.onEmptyLeftClick(ForgeHooks.java:795) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading}
    at net.minecraft.client.Minecraft.clickMouse(Minecraft.java:1181) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
    at net.minecraft.client.Minecraft.processKeyBinds(Minecraft.java:1476) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
    at net.minecraft.client.Minecraft.runTick(Minecraft.java:1313) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
    at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:862) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
    at net.minecraft.client.Minecraft.run(Minecraft.java:520) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
    at net.minecraft.client.main.Main.main(SourceFile:202) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {re:classloading,pl:runtimedistcleaner:A}
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_231] {}
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_231] {}
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_231] {}
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_231] {}
    at net.minecraftforge.userdev.FMLUserdevClientLaunchProvider.lambda$launchService$0(FMLUserdevClientLaunchProvider.java:55) ~[forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {}
    at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37) [modlauncher-5.0.0-milestone.4.jar:?] {}
    at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:54) [modlauncher-5.0.0-milestone.4.jar:?] {}
    at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:72) [modlauncher-5.0.0-milestone.4.jar:?] {}
    at cpw.mods.modlauncher.Launcher.run(Launcher.java:81) [modlauncher-5.0.0-milestone.4.jar:?] {}
    at cpw.mods.modlauncher.Launcher.main(Launcher.java:65) [modlauncher-5.0.0-milestone.4.jar:?] {}
    at net.minecraftforge.userdev.LaunchTesting.main(LaunchTesting.java:101) [forge-1.15.1-30.0.30_mapped_snapshot_20190719-1.14.3.jar:?] {}
Caused by: java.lang.IllegalArgumentException: Registration of network channels is locked
    at net.minecraftforge.fml.network.NetworkRegistry.createInstance(NetworkRegistry.java:130) ~[?:?] {re:classloading}
    at net.minecraftforge.fml.network.NetworkRegistry.access$000(NetworkRegistry.java:49) ~[?:?] {re:classloading}
    at net.minecraftforge.fml.network.NetworkRegistry$ChannelBuilder.createNetworkInstance(NetworkRegistry.java:400) ~[?:?] {re:classloading}
    at net.minecraftforge.fml.network.NetworkRegistry$ChannelBuilder.simpleChannel(NetworkRegistry.java:409) ~[?:?] {re:classloading}
    at arknights.network.PacketHandler.<clinit>(PacketHandler.java:28) ~[?:?] {re:classloading}
    ... 22 more

Here is my code:

Spoiler

BaseItem.java (I made this class so that I can make some wands or something else may use leftclick easily.)


package arknights.item;

import arknights.network.PacketHandler;
import arknights.network.packets.LeftClickPKT;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;

public class BaseItem extends Item {

    public BaseItem(Properties p_i48487_1_) {
        super(p_i48487_1_);
        MinecraftForge.EVENT_BUS.addListener(this::emptyLeftClick);
    }

    public void emptyLeftClick(PlayerInteractEvent.LeftClickEmpty event){
        PacketHandler.sendToServer(new LeftClickPKT());
    }

    public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack){

    }
}

PureOriginiums.java (The only change is method "leftclick", I spawn an arrow for test.)


package arknights.item;

import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.AbstractArrowEntity;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.item.*;
import net.minecraft.potion.Effect;
import net.minecraft.potion.EffectInstance;
import net.minecraft.stats.Stats;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import org.apache.commons.lang3.tuple.Pair;

import java.util.*;

import static net.minecraft.potion.Effects.*;

public class PureOriginiums extends BaseItem {
    List<Pair<EffectInstance, Float>> effects = new ArrayList<>();
    String playerName = null;

    public PureOriginiums(Properties p_i48476_1_) {
        super(p_i48476_1_);
    }

    @Override
    public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack){
        AbstractArrowEntity abstractarrowentity = new ArrowEntity(worldIn, livingEntity);
        abstractarrowentity.setNoGravity(true);
        abstractarrowentity.shoot(livingEntity, livingEntity.rotationPitch, livingEntity.rotationYaw, 0.0F, 0.1F * 3.0F, 1.0F);
    }

    @Override
    public UseAction getUseAction(ItemStack stack) {
        return UseAction.EAT;
    }

    @Override
    public int getUseDuration(ItemStack stack) {
        return 32;
    }

    //public static final Food PUREORIGINIUMS = (new Food.Builder()).hunger(10).saturation(0.3F).effect(new EffectInstance(Effects.SPEED, 400, 255), 1.0F).build();
    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
        this.effects.clear();
        this.playerName = playerIn.getScoreboardName();
        ItemStack itemstack = playerIn.getHeldItem(handIn);
        playerIn.setActiveHand(handIn);
        return ActionResult.func_226249_b_(itemstack);
    }

    @Override
    public ItemStack onItemUseFinish(ItemStack stack, World worldIn, LivingEntity entityLiving) {
        //String playerName = entityLiving.getScoreboardName()
        int effectId = (int)(1+Math.random()*(10-1+1));
        return onOriginniumsEaten(worldIn, stack, (PlayerEntity) entityLiving);
    }

    public ItemStack onOriginniumsEaten(World p_213357_1_, ItemStack p_213357_2_, PlayerEntity playerEntity) {
        playerEntity.getFoodStats().addStats(20,20);
        playerEntity.addStat(Stats.ITEM_USED.get(p_213357_2_.getItem()));
        p_213357_1_.playSound(null, playerEntity.func_226277_ct_(), playerEntity.func_226278_cu_(), playerEntity.func_226281_cx_(), playerEntity.getEatSound(p_213357_2_), SoundCategory.NEUTRAL, 1.0F, 1.0F + (p_213357_1_.rand.nextFloat() - p_213357_1_.rand.nextFloat()) * 0.4F);
        this.effectsList();
        applyFoodEffects(p_213357_2_, p_213357_1_, playerEntity);
        //playerEntity.setHealth(20.0F);
        //playerEntity.addPotionEffect(new EffectInstance(Effects.SPEED, 600, 10));
        if ( !(playerEntity).abilities.isCreativeMode) {
            p_213357_2_.shrink(1);
        }
        return p_213357_2_;
    }

    private void applyFoodEffects(ItemStack p_213349_1_, World p_213349_2_, LivingEntity p_213349_3_) {
        for(Pair<EffectInstance, Float> pair : this.effects) {
            if (!p_213349_2_.isRemote && pair.getLeft() != null && p_213349_2_.rand.nextFloat() < pair.getRight()) {
                p_213349_3_.addPotionEffect(new EffectInstance(pair.getLeft()));
            }
        }
    }

    void effectsList(){
        if( /*this.playerName == "Dev" || */this.playerName.regionMatches(0, "Dr", 0, 2)){
            addEffectToList(SPEED, 600, 10);
            addEffectToList(HASTE, 600, 255);
            addEffectToList(STRENGTH, 200, 10);
            addEffectToList(JUMP_BOOST, 600, 2);
            addEffectToList(RESISTANCE, 600, 3);
            addEffectToList(FIRE_RESISTANCE, 600, 2);
            addEffectToList(WATER_BREATHING, 600, 1);
            addEffectToList(NIGHT_VISION, 600, 1);
            addEffectToList(DOLPHINS_GRACE, 600, 1);
        } else {
            int random1,random2,random3;
            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(SPEED, random2, random3);
                    break;
                case 2:
                    addEffectToList(SLOWNESS, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(HASTE, random2, random3);
                    break;
                case 2:
                    addEffectToList(MINING_FATIGUE, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*2);
            switch(random1){
                case 1:
                    addEffectToList(STRENGTH, random2, random3);
                    break;
                case 2:
                    addEffectToList(WEAKNESS, random2, random3);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*5);
            switch(random1){
                case 1:
                    addEffectToList(JUMP_BOOST, random2, random3);
                    break;
                    default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(NAUSEA, random2, 2);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            random3 = (int)(1+Math.random()*3);
            switch(random1){
                case 1:
                    addEffectToList(RESISTANCE, random2, random3);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(FIRE_RESISTANCE, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(WATER_BREATHING, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(BLINDNESS, random2, 1);
                    break;
                case 2:
                    addEffectToList(NIGHT_VISION, random2, 1);
                    break;default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(SLOW_FALLING, random2, 1);
                    break;
                default: break;
            }

            random1 = (int)(1+Math.random()*2);
            random2 = (int)(100+Math.random()*1000);
            //random3 = (int)(1+Math.random()*10);
            switch(random1){
                case 1:
                    addEffectToList(DOLPHINS_GRACE, random2, 1);
                    break;
                default: break;
            }

            addEffectToList(WITHER, 800, 2);
        }

    }

    void addEffectToList(Effect effect, int time, int level){
        this.effects.add(Pair.of(new EffectInstance(effect, time, level), 1.0F));
    }
}

LeftClickPacket.java


package arknights.network.packets;

import arknights.item.BaseItem;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;

import java.util.function.Supplier;

public class LeftClickPacket {
    public static void encode(LeftClickPacket msg, PacketBuffer buf){
    }

    public static LeftClickPacket decode(PacketBuffer buf){
        return new LeftClickPacket();
    }

    public static class Handler {
        public static void handle(LeftClickPacket msg, Supplier<NetworkEvent.Context> ctx){
            ctx.get().enqueueWork(() -> {
                PlayerEntity player = ctx.get().getSender();
                ItemStack item = player.getHeldItemMainhand();
                if(!item.isEmpty() && (item.getItem() instanceof BaseItem)){
                    ((BaseItem) item.getItem()).leftClick(player, player.getEntityWorld(), item);
                }
            });
            ctx.get().setPacketHandled(true);
        }
    }
}

PacketHandler.java


package arknights.network;

import arknights.Arknights;
import arknights.network.packets.LeftClickPacket;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;

import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;

public final class PacketHandler {
    private static final String PROTOCOL_VERSION = Integer.toString(1);

    private static final SimpleChannel HANDLER = NetworkRegistry.ChannelBuilder
            .named(new ResourceLocation(Arknights.MODID, "main_channel"))
            .clientAcceptedVersions(PROTOCOL_VERSION::equals)
            .serverAcceptedVersions(PROTOCOL_VERSION::equals)
            .networkProtocolVersion(() -> PROTOCOL_VERSION)
            .simpleChannel();
    private static int index;

    public static void register(){
        registerMessage(LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
    }

    private static <MSG> void registerMessage(Class<MSG> type, BiConsumer<MSG, PacketBuffer> encoder,  Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> consumer){
        HANDLER.registerMessage(index++, type, encoder, decoder, consumer);
    }

    public static void sendToServer(Object msg){
        HANDLER.sendToServer(msg);
    }

    public static void sendTo(Object msg, ServerPlayerEntity player){
        if(!(player instanceof FakePlayer)){
            HANDLER.sendTo(msg, player.connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
        }
    }
}

Please tell me how to fix it. Thanks.

Posted
7 hours ago, diesieben07 said:

Network channels must be registered during FMLCommonSetupEvent. Not at some random time during some random static initializer.

Thank you!

Maybe I will complete it today!

Posted
7 hours ago, diesieben07 said:

Network channels must be registered during FMLCommonSetupEvent. Not at some random time during some random static initializer.

Sorry...

There is still a strange problem...

 

I add this to my main class, and I think it work.

FMLJavaModLoadingContext.get().getModEventBus().addListener(PacketHandler::register);

But it still throws an error like this:

[08:57:50] [Server thread/ERROR] [ne.mi.fm.ne.si.IndexedMessageCodec/SIMPLENET]: Received empty payload on channel fml:handshake

 

The game will not exit, but there is nothing when I left click my item.

 

Maybe I make some stupid mistakes...

Posted (edited)
45 minutes ago, diesieben07 said:

Show more of your code.

ok.

Arknights.java

package arknights;

import arknights.network.PacketHandler;
import arknights.network.packets.LeftClickPacket;
import arknights.registry.BlockList;
import arknights.registry.ItemHandler;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.*;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.stream.Collectors;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(Arknights.MODID)

public class Arknights
{
    public static final String MODID = "arknights";
    // Directly reference a log4j logger.
    private static final Logger LOGGER = LogManager.getLogger();

    public static final ItemGroup ARKNIGHTS = new ItemGroup("arknights") {
        @Override
        public ItemStack createIcon() {
            return new ItemStack(ItemHandler.PUREORIGINIUMS);
        }
    };

    //Registry Lists
    private static final BlockList BLOCKLIST = new BlockList();
    private static final ItemHandler ITEMLIST = new ItemHandler();

    //public static final Block ORIGINIUMS_ORE = new Block(Block.Properties.create(Material.GLASS).hardnessAndResistance(3.0F, 3.0F)).setRegistryName(MODID+":originiums_ore");
    //public static final BlockItem ORIGINIUMS_ORE_ITEM = (BlockItem) new BlockItem(ORIGINIUMS_ORE, new Item.Properties().group(ARKNIGHTS)).setRegistryName(MODID+":originiums_ore");

    //public static final Item PUREORIGINIUMS = new PureOriginiums(new Item.Properties().group(ARKNIGHTS)).setRegistryName(MODID+":pure_originiums");

    public Arknights() {
        // Register the setup method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        // Register the enqueueIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
        // Register the processIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
        // Register the doClientStuff method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(PacketHandler::register);

        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);
    }

    private void setup(final FMLCommonSetupEvent event)
    {
        //PacketHandler.HANDLER.registerMessage(PacketHandler.index++, LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
        // some preinit code
        LOGGER.info("HELLO FROM PREINIT");
        LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
    }

    private void doClientStuff(final FMLClientSetupEvent event) {
        // do something that can only be done on the client
        LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().gameSettings);
    }

    private void enqueueIMC(final InterModEnqueueEvent event)
    {
        // some example code to dispatch IMC to another mod
        InterModComms.sendTo("examplemod", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";});
    }

    private void processIMC(final InterModProcessEvent event)
    {
        // some example code to receive and process InterModComms from other mods
        LOGGER.info("Got IMC {}", event.getIMCStream().
                map(m->m.getMessageSupplier().get()).
                collect(Collectors.toList()));
    }
    // You can use SubscribeEvent and let the Event Bus discover methods to call
    @SubscribeEvent
    public void onServerStarting(FMLServerStartingEvent event) {
        // do something when the server starts
        LOGGER.info("HELLO from server starting");
    }

    // You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD
    // Event bus for receiving Registry Events)
    @Mod.EventBusSubscriber(modid = Arknights.MODID, bus=Mod.EventBusSubscriber.Bus.MOD)
    public static class RegistryEvents {
        @SubscribeEvent
        public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) {
            // register a new block here
            for(Block block : BLOCKLIST.blockList){
                blockRegistryEvent.getRegistry().register(block);
            }

            LOGGER.info("HELLO from Register Block");
        }

        @SubscribeEvent
        public static void onItemsRegistry(final RegistryEvent.Register<Item> itemRegisterEvent) {
            for(Item item : BLOCKLIST.blockItemsList){
                itemRegisterEvent.getRegistry().register(item);
            }
            //MinecraftForge.EVENT_BUS.addListener(ItemHandler::register);
            ItemHandler.register(itemRegisterEvent);
            /*
            for (Item item : ITEMLIST.itemList){
                itemRegisterEvent.getRegistry().register(item);
            }*/
        }
    }
}

 

Nothing has changed in other code.

Thanks.

Edited by NGYF
Posted
Just now, diesieben07 said:

Then you are still registering your network channel in a static initializer.

Maybe I need an example... The former code reference ProjectE, and it use the static initializer. And the documentation is static too.

I try to register it in a not static initializer (maybe in a wrong way), and it doesn't work. When I left click, nothing has happened.

 

By the way, the thrown error appears when I join the world, and when I delete the packet registry, it still appears. 

Here is the code:

PacketHandler.java


package arknights.network;

import arknights.network.packets.LeftClickPacket;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;

public final class PacketHandler {
    private static final String PROTOCOL_VERSION = Integer.toString(1);



    public SimpleChannel HANDLER = NetworkRegistry.newSimpleChannel(
            new ResourceLocation("corruption","main")
            ,() -> PROTOCOL_VERSION
            , PROTOCOL_VERSION::equals
            , PROTOCOL_VERSION::equals);

    int id = 0;
    public void register(){
        HANDLER.registerMessage(id++, LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
    }
}

 

Arknights.java

Here is the whole class.

Spoiler

package arknights;

import arknights.network.PacketHandler;
import arknights.network.packets.LeftClickPacket;
import arknights.registry.BlockList;
import arknights.registry.ItemHandler;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.*;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.stream.Collectors;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(Arknights.MODID)

public class Arknights
{
    public static final String MODID = "arknights";
    // Directly reference a log4j logger.
    private static final Logger LOGGER = LogManager.getLogger();

    public static final ItemGroup ARKNIGHTS = new ItemGroup("arknights") {
        @Override
        public ItemStack createIcon() {
            return new ItemStack(ItemHandler.PUREORIGINIUMS);
        }
    };

    public static final PacketHandler PACKETHANDLER = new PacketHandler();

    //Registry Lists
    private static final BlockList BLOCKLIST = new BlockList();

    //public static final Block ORIGINIUMS_ORE = new Block(Block.Properties.create(Material.GLASS).hardnessAndResistance(3.0F, 3.0F)).setRegistryName(MODID+":originiums_ore");
    //public static final BlockItem ORIGINIUMS_ORE_ITEM = (BlockItem) new BlockItem(ORIGINIUMS_ORE, new Item.Properties().group(ARKNIGHTS)).setRegistryName(MODID+":originiums_ore");

    //public static final Item PUREORIGINIUMS = new PureOriginiums(new Item.Properties().group(ARKNIGHTS)).setRegistryName(MODID+":pure_originiums");

    public Arknights() {
        // Register the setup method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        // Register the enqueueIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
        // Register the processIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
        // Register the doClientStuff method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
        //FMLJavaModLoadingContext.get().getModEventBus().addListener(PacketHandler::register);
        PACKETHANDLER.register();
        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);
    }

    private void setup(final FMLCommonSetupEvent event)
    {
        //PacketHandler.HANDLER.registerMessage(PacketHandler.index++, LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
        // some preinit code
        LOGGER.info("HELLO FROM PREINIT");
        LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
    }

    private void doClientStuff(final FMLClientSetupEvent event) {
        // do something that can only be done on the client
        LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().gameSettings);
    }

    private void enqueueIMC(final InterModEnqueueEvent event)
    {
        // some example code to dispatch IMC to another mod
        InterModComms.sendTo("examplemod", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";});
    }

    private void processIMC(final InterModProcessEvent event)
    {
        // some example code to receive and process InterModComms from other mods
        LOGGER.info("Got IMC {}", event.getIMCStream().
                map(m->m.getMessageSupplier().get()).
                collect(Collectors.toList()));
    }
    // You can use SubscribeEvent and let the Event Bus discover methods to call
    @SubscribeEvent
    public void onServerStarting(FMLServerStartingEvent event) {
        // do something when the server starts
        LOGGER.info("HELLO from server starting");
    }

    // You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD
    // Event bus for receiving Registry Events)
    @Mod.EventBusSubscriber(modid = Arknights.MODID, bus=Mod.EventBusSubscriber.Bus.MOD)
    public static class RegistryEvents {
        @SubscribeEvent
        public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) {
            // register a new block here
            for(Block block : BLOCKLIST.blockList){
                blockRegistryEvent.getRegistry().register(block);
            }

            LOGGER.info("HELLO from Register Block");
        }

        @SubscribeEvent
        public static void onItemsRegistry(final RegistryEvent.Register<Item> itemRegisterEvent) {
            for(Item item : BLOCKLIST.blockItemsList){
                itemRegisterEvent.getRegistry().register(item);
            }
            //MinecraftForge.EVENT_BUS.addListener(ItemHandler::register);
            ItemHandler.register(itemRegisterEvent);
            /*
            for (Item item : ITEMLIST.itemList){
                itemRegisterEvent.getRegistry().register(item);
            }*/
        }
    }
}

I think there is something not so relevant, so I provide a simple one.

public class Arknights
{
    //something

    //code I add
    public static final PacketHandler PACKETHANDLER = new PacketHandler();

    public Arknights() {
        // Register methods for modloading
       
        //code I add
        PACKETHANDLER.register();

        // Register ourselves for server and other game events we are interested in
    }

 

BaseItem.java

package arknights.item;

import arknights.Arknights;
import arknights.network.PacketHandler;
import arknights.network.packets.LeftClickPacket;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;

public class BaseItem extends Item {

    public BaseItem(Properties p_i48487_1_) {
        super(p_i48487_1_);
        MinecraftForge.EVENT_BUS.addListener(this::emptyLeftClick);
    }

    public void emptyLeftClick(PlayerInteractEvent.LeftClickEmpty event){
        Arknights.PACKETHANDLER.HANDLER.sendToServer(new LeftClickPacket());
    }

    public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack){

    }
}

 

Posted
4 minutes ago, diesieben07 said:

I don't know how this is so hard to understand.

The registration of your network channel must happen in FMLCommonSetupEvent. You are still not doing that. Now you are calling newSimpleChannel from the constructor of PacketHandler, which you call from the constructor of Arknights. This is not in FMLCommonSetupEvent.

private void setup(final FMLCommonSetupEvent event)
{
    PacketHandler.register();
}

Should I do it just like this? (The method is in Arknights.java)

I'm new to modding...

And the problem becomes more and more complicated...

I test the mod with out packet handler but it still tells me "Received empty payload on channel fml:handshake".

I also test the method leftclick in my item. I add "System.out.print("A"); " to the method, and when I left click, an "A" prints to the terminal. Does it means the packet is succesfully sent? If so, why it doesn't spawn an arrow? Could you tell me how to spawn entities properly?

 

Posted
9 minutes ago, diesieben07 said:

Post the complete debug.log.

 

How would it? Printing "A" to the console does not tell you anything about the state of your packet.

I upload the log.

Here is one part of the log, it appears when I join the game. It starts at line 16620.

[22一月2020 19:05:17.222] [Server thread/INFO] [net.minecraft.server.MinecraftServer/]: Dev加入了游戏
[22一月2020 19:05:17.344] [Render thread/DEBUG] [net.minecraftforge.fml.network.FMLLoginWrapper/FMLHANDSHAKE]: Recieved login wrapper packet event for channel fml:handshake with index -1
[22一月2020 19:05:17.344] [Render thread/ERROR] [net.minecraftforge.fml.network.simple.IndexedMessageCodec/SIMPLENET]: Received empty payload on channel fml:handshake
[22一月2020 19:05:18.760] [Server thread/INFO] [net.minecraft.server.integrated.IntegratedServer/]: Saving and pausing game...
[22一月2020 19:05:18.985] [Render thread/INFO] [net.minecraft.advancements.AdvancementList/]: Loaded 12 advancements
[22一月2020 19:05:19.007] [Server thread/INFO] [net.minecraft.server.MinecraftServer/]: Saving chunks for level 'RhodesIsland'/minecraft:overworld
[22一月2020 19:05:19.683] [Server thread/DEBUG] [net.minecraftforge.fml.FMLWorldPersistenceHook/WP]: Gathering id map for writing to world save RhodesIsland
[22一月2020 19:05:19.881] [Server thread/DEBUG] [net.minecraftforge.fml.network.FMLLoginWrapper/FMLHANDSHAKE]: Recieved login wrapper packet event for channel fml:handshake with index -1
[22一月2020 19:05:19.881] [Server thread/ERROR] [net.minecraftforge.fml.network.simple.IndexedMessageCodec/SIMPLENET]: Received empty payload on channel fml:handshake

 

The item will send a packet to server when it is left clicked.

The method is in BaseItem.java

public void emptyLeftClick(PlayerInteractEvent.LeftClickEmpty event){
        PacketHandler.HANDLER.sendToServer(new LeftClickPacket());
    }

 

And "leftclick" method will be called like this:

LeftClickPacket.java

package arknights.network.packets;

import arknights.item.BaseItem;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;

import java.util.function.Supplier;

public class LeftClickPacket {
    public static void encode(LeftClickPacket msg, PacketBuffer buf){
    }

    public static LeftClickPacket decode(PacketBuffer buf){
        return new LeftClickPacket();
    }

    public static class Handler {
        public static void handle(LeftClickPacket msg, Supplier<NetworkEvent.Context> ctx){
            ctx.get().enqueueWork(() -> {
                PlayerEntity player = ctx.get().getSender();
                ItemStack item = player.getHeldItemMainhand();
                if(!item.isEmpty() && (item.getItem() instanceof BaseItem)){
                    ((BaseItem) item.getItem()).leftClick(player, player.getEntityWorld(), item);
                }
            });
            ctx.get().setPacketHandled(true);
        }
    }
}

leftClick method (inside my item class):

public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack){
        System.out.print("A");

    }

Does it mean the packet is successfully sent?

Posted

A comment, if I may:

1 hour ago, diesieben07 said:

The registration of your network channel must happen in FMLCommonSetupEvent. You are still not doing that. Now you are calling newSimpleChannel from the constructor of PacketHandler, which you call from the constructor of Arknights. This is not in FMLCommonSetupEvent.

The problem in your code is that you construct your SimpleChannel at the wrong time. NetworkRegistry::newSimpleChannel should be called from your FMLCommonSetupEvent function, but instead you call it when the class Arknights is constructed -- a long time before FMLCommonSetupEvent will be called.

To fix this, here are the adjustments:
 

Spoiler

@Mod(Arknights.MODID)
public class Arknights
{
    // ...other code and stuff
    private void setup(final FMLCommonSetupEvent event)
    {
        PacketHandler.register(); // this should be, for now, the ONLY code referencing PacketHandler in this class
    }
	// ...other code and stuff
}

public class PacketHandler {
    private static final String PROTOCOL_VERSION = Integer.toString(1);

    public static SimpleChannel HANDLER = NetworkRegistry.newSimpleChannel( // change to static
            new ResourceLocation("arknights", "main"), // use modid in resourcelocation, to be unique in case other mods use corruption as modid
           	() -> PROTOCOL_VERSION,
            PROTOCOL_VERSION::equals, 
            PROTOCOL_VERSION::equals);

    private static int id = 0; // change to private static (more to hide unneeded variables)
    public static void register() { // change to static
        HANDLER.registerMessage(id++, LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
    }
}

 

And the explanations:

Spoiler

ProjectE and other mods work with the static initialization method of registering SimpleChannel beacuse the first time they reference their PacketHandler class is in FMLCommonSetupEvent.

See, the JVM loads classes lazily -- classes only get loaded (and the static code in them only get called) if and only when another class calls them.

So, when the JVM loads your PacketHandler class, it sees the static initialization of SimpleChannel and it will call NetworkRegistry::newSimpleChannel.

This is safe, because if the first reference to PacketHandler is during FMLCommonSetupEvent, then the static code in PacketHandler -- such as the call to NetworkRegistry::newSimpleChannel -- also runs during FMLCommonSetupEvent. This is how ProjectE and many other mods do this.

Yes, there are other ways to register your SimpleChannel -- like putting your NetworkRegistry::newSimpleChannel call inside of register() -- but this is, in my opinion, the easiest to read and write. (Plus, most tutorials will likely use this method, because it just works.)

 

Posted
27 minutes ago, sciwhiz12 said:

A comment, if I may:

The problem in your code is that you construct your SimpleChannel at the wrong time. NetworkRegistry::newSimpleChannel should be called from your FMLCommonSetupEvent function, but instead you call it when the class Arknights is constructed -- a long time before FMLCommonSetupEvent

To fix this, here are the adjustments:
 

  Hide contents


@Mod(Arknights.MODID)
public class Arknights
{
    // ...other code and stuff
    private void setup(final FMLCommonSetupEvent event)
    {
        PacketHandler.register(); // this should be, for now, the ONLY code referencing PacketHandler in this class
    }
	// ...other code and stuff
}


public class PacketHandler {
    private static final String PROTOCOL_VERSION = Integer.toString(1);

    public static SimpleChannel HANDLER = NetworkRegistry.newSimpleChannel( // change to static
            new ResourceLocation("arknights", "main"), // use modid in resourcelocation, to be unique in case other mods use corruption as modid
           	() -> PROTOCOL_VERSION,
            PROTOCOL_VERSION::equals, 
            PROTOCOL_VERSION::equals);

    private static int id = 0; // change to private static (more to hide unneeded variables)
    public static void register() { // change to static
        HANDLER.registerMessage(id++, LeftClickPacket.class, LeftClickPacket::encode, LeftClickPacket::decode, LeftClickPacket.Handler::handle);
    }
}

 

And the explanations:

  Hide contents

ProjectE and other mods work with the static initialization method of registering SimpleChannel beacuse the first time they reference their PacketHandler class is in FMLCommonSetupEvent.

See, the JVM loads classes lazily -- classes only get loaded (and the static code in them only get called) if and only when another class calls them.

So, when the JVM loads your PacketHandler class, it sees the static initialization of SimpleChannel and it will call NetworkRegistry::newSimpleChannel.

This is safe, because if the first reference to PacketHandler is during FMLCommonSetupEvent, then the static code in PacketHandler -- such as the call to NetworkRegistry::newSimpleChannel -- also runs during FMLCommonSetupEvent. This is how ProjectE and many other mods do this.

Yes, there are other ways to register your SimpleChannel -- like putting your NetworkRegistry::newSimpleChannel call inside of register() -- but this is, in my opinion, the easiest to read and write. (Plus, most tutorials will likely use this method, because it just works.)

Thank you for your patience! It helps me a lot.

 

 

Posted
17 minutes ago, NGYF said:

Thank you for your patience! It helps me a lot.

You're welcome!

And another thing which I noticed;

You are registering your listener for PlayerInteractEvent.LeftClickEmpty in your BaseItem class. This is a problem: if you create multiple instances of BaseItem, you are registering your listener multiple times, which means that your code will send multiple packets for the same event.

To fix this, I recommend moving that code out of your BaseItem class, and into another class -- either a dedicated EventListener class, or even just inside your Arknights mod class:

Spoiler


@Mod(Arknights.MODID)
public class Arknights
{
    // ...other code
    @Mod.EventBusSubscriber(modid = Arknights.MODID, bus = Bus.MOD)
    public static class EventListener
    {
        @SubscribeEvent
        public static void emptyLeftClick(PlayerInteractEvent.LeftClickEmpty event)
        {
            PacketHandler.HANDLER.sendToServer(new LeftClickPacket());
        }
    }
    // ...other code
}

public class BaseItem extends Item {

    public BaseItem(Properties props) {
        super(props);
    }

    public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack) {}
}

 

This fixes the problem, and gives a cleaner way to add more event listeners in the future.

Posted
2 minutes ago, sciwhiz12 said:

You're welcome!

And another thing which I noticed;

You are registering your listener for PlayerInteractEvent.LeftClickEmpty in your BaseItem class. This is a problem: if you create multiple instances of BaseItem, you are registering your listener multiple times, which means that your code will send multiple packets for the same event.

To fix this, I recommend moving that code out of your BaseItem class, and into another class -- either a dedicated EventListener class, or even just inside your Arknights mod class:

  Hide contents



@Mod(Arknights.MODID)
public class Arknights
{
    // ...other code
    @Mod.EventBusSubscriber(modid = Arknights.MODID, bus = Bus.MOD)
    public static class EventListener
    {
        @SubscribeEvent
        public static void emptyLeftClick(PlayerInteractEvent.LeftClickEmpty event)
        {
            PacketHandler.HANDLER.sendToServer(new LeftClickPacket());
        }
    }
    // ...other code
}


public class BaseItem extends Item {

    public BaseItem(Properties props) {
        super(props);
    }

    public void leftClick(LivingEntity livingEntity, World worldIn, ItemStack stack) {}
}

 

This fixes the problem, and gives a cleaner way to add more event listeners in the future.

Thank you! That's useful!

Posted

Holy shit!

I make an very stupid mistake...

I forget to add entity to world! That's why I can't find the arrow.

 

I'm so stupid...

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



×
×
  • Create New...

Important Information

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