Jump to content

[Solved][1.11.2] Using isRemote before Minecraft.getMinecraft can still cause a crash?


Recommended Posts

Posted (edited)

In my code I am trying to stop the player from moving when they are stunned. So using PlayerTickEvent I disable some of the keys used for movement.

Here is the code:

Spoiler

    @SubscribeEvent
    public void onPlayerTick(PlayerTickEvent event)
    {
        if (event.phase == TickEvent.Phase.START)
        {
            EntityPlayer player = event.player;
            IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

            // Ensure the code within this if statement is only ran on Client
            if (player.world.isRemote)
            {
                // if this clients player is stunned, increment tickStunned and disable movement
                if (playerData.getIsStunned())
                {
                    playerData.setTicksStunned(playerData.getTicksStunned() + 1);

                    if (playerData.getTicksStunned() < playerData.getStunDuration())
                    {
                        // disable movement
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindForward.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindBack.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindLeft.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindRight.getKeyCode(), false);
                    }
                    else
                    {
                        playerData.setIsStunned(false);
                        playerData.setTicksStunned(0);
                    }
                }

                return;
            }
    }

 

 

From what I understand is even if I use world.isRemote before using Minecraft.getMinecraft() this can still cause the server to crash, but it doesn't. I did test it on a dedicated server, but I was still running the server and client on the same computer idk if that affects it.

If using Minecraft.getMinecraft() even after making sure world.isRemote can cause a crash on the server, what's the proper way to go about this? Maybe create a method in my proxy to handle this, where the ServerProxy does nothing and ClientProxy has this code?

Edited by Kriptikz
Posted

The answer is "yes it will." The reason it isn't has to do with the fact that the server isn't even loading your class, which invalidates the test. 

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Why wouldn't the server be loading the class? I do have other methods in this class I just only posted the piece I was wondering about. I also do register this for both client and server I'm pretty sure.

Here is the actual entire class:

Spoiler

public class ModEventHandler
{
    public static Field floatingTickCount = null;
    
    public ModEventHandler()
    {
        try
        {
            floatingTickCount = ReflectionHelper.findField(NetHandlerPlayServer.class, "floatingTickCount");
        } catch (Exception e)
        {
            System.out.println("Unable to find field floatingTickCount");
            e.printStackTrace();
        }
    }
    
	@SubscribeEvent
	public void onLivingEvent(LivingUpdateEvent event)
	{
		if (!event.getEntity().world.isRemote)
		{
			if (event.getEntityLiving() instanceof EntityLiving)
			{
				EntityLiving entity = (EntityLiving) event.getEntityLiving();
				IMobData mobData = MobDataProvider.getMobCapability(entity);
				if (entity.isAIDisabled())
				{
					mobData.setTicksStunned(mobData.getTicksStunned() + 1);
				}
				if (entity.isAIDisabled() && (mobData.getTicksStunned() % mobData.getStunnedDuration() == 0))
				{
					entity.setNoAI(false);
				}
			}
			
			if (event.getEntityLiving() instanceof EntityGhast)
			{

			}
			
			if (event.getEntityLiving() instanceof EntityMob)
			{
				EntityMob mob = (EntityMob) event.getEntityLiving();

				mob.targetTasks.addTask(0, new EntityAINearestAttackableTarget<>(mob, EntityDummyTarget.class, true));
			} 
		}

		
	}
	
	@SubscribeEvent
	public void onPlayerLogin(PlayerLoggedInEvent event)
	{
		EntityPlayer player = event.player;
		IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

		MagicMastery.network.sendTo(new MessageSyncAllPlayerData(playerData), (EntityPlayerMP) player);
	}
	
	@SubscribeEvent
	public void onPlayerLoggout(PlayerLoggedOutEvent event)
	{
		
	}

    @SubscribeEvent
    public void onPlayerTick(PlayerTickEvent event)
    {
        if (event.phase == TickEvent.Phase.START)
        {
            EntityPlayer player = event.player;
            IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

            // Check if on server and apply levitation code
            if (!player.world.isRemote)
            {
                if (playerData.getIsLevitating())
                {
                    // reset fall distance because technically they are
                    // levitating but minecraft thinks they are falling which
                    // means when they land they would take insane fall damage.
                    player.fallDistance = 0;

                    // prevent the player from getting kicked from the server
                    // for flying while using levitation spell.
                    if (player instanceof EntityPlayerMP)
                    {

                        try
                        {
                            floatingTickCount.setInt(((EntityPlayerMP) player).connection, 0);
                        } catch (IllegalAccessException e)
                        {
                            e.printStackTrace();
                        }

                    }

                    // decrease mana every second.
                    if (player.ticksExisted % 20 == 0)
                    {
                        if (playerData.getMana() - 2 >= 0)
                        {
                            playerData.setMana(playerData.getMana() - 2);
                        }
                        else
                        {
                            playerData.setIsLevitating(false);
                            MagicMastery.network.sendTo(new MessagePlayerIsLevitatingToClient(playerData.getIsLevitating()), (EntityPlayerMP) player);
                        }
                    }

                }
            }

            // Ensure the code within this if statement is only ran on Client
            if (player.world.isRemote)
            {
                if (Keybinds.levitate_down.isKeyDown())
                {
                    playerData.setLevitationAmp(1);
                }
                else if (Keybinds.levitate_up.isKeyDown())
                {
                    playerData.setLevitationAmp(9);
                }
                else
                {
                    playerData.setLevitationAmp(5);
                }

                if (playerData.getIsLevitating())
                {
                    player.motionY += (0.05D * (double) (playerData.getLevitationAmp() + 1) - player.motionY) * 0.2D;
                    player.fallDistance = 0;
                }

                // if this clients player is stunned, increment tickStunned and
                // disable all hotkey other than settings Gui key, open
                // inventory key, and swap items keys
                if (playerData.getIsStunned())
                {
                    playerData.setTicksStunned(playerData.getTicksStunned() + 1);

                    if (playerData.getTicksStunned() < playerData.getStunDuration())
                    {
                        // disable all hotkey other than settings Gui key, open
                        // inventory key, and swap items keys
                        //KeyBinding.unPressAllKeys();
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindForward.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindBack.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindLeft.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindRight.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindJump.getKeyCode(), false);
                        KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindInventory.getKeyCode(), false);
                    }
                    else
                    {
                        playerData.setIsStunned(false);
                        playerData.setTicksStunned(0);
                    }
                }

                return;
            }

            // ensure player mana doesn't exceed player max mana every tick.
            // this makes adding mana though items or any other means easier to
            // handle. if any item sets players mana above the players max mana
            // it will be fixed on player tick (almost instantly).
            if (playerData.getMana() > playerData.getMaxMana())
            {
                playerData.setMana(playerData.getMaxMana());
            }

            // sync player mana every 5 ticks
            if (player.ticksExisted % 5 == 0)
            {
                MagicMastery.network.sendTo(new MessageSyncMana(playerData), (EntityPlayerMP) player);
            }

            // regen player mana every second
            if (player.ticksExisted % 20 == 0)
            {
                if ((playerData.getMana() + playerData.getManaRegenPerSecond()) <= playerData.getMaxMana())
                {
                    playerData.setMana(playerData.getMana() + playerData.getManaRegenPerSecond());
                }
            }

            // sync player selected spell to all tracking players every half
            // second.
            if (player.ticksExisted % 10 == 0)
            {
                EntityTracker entityTracker = ((WorldServer) player.world).getEntityTracker();
                entityTracker.sendToTracking(player,
                        MagicMastery.network.getPacketFrom(new MessageSyncSelectedSpellToTrackingClients(playerData.getSelectedSpell(), player)));
            }
        }

    }
}

 

 

Here is the @Mod class:

Spoiler

@Mod(modid = Reference.MODID, name = Reference.NAME, version = Reference.VERSION)
public class MagicMastery
{
	@SidedProxy(serverSide = Reference.SERVER_PROXY_CLASS, clientSide = Reference.CLIENT_PROXY_CLASS)
	public static IProxy proxy;
	
	@Instance(Reference.MODID)
	public static MagicMastery instance;
	
	public static SimpleNetworkWrapper network;
	
	@EventHandler
	public void preInit(FMLPreInitializationEvent event)
	{
		CapabilityManager.INSTANCE.register(IPlayerData.class, new PlayerDataStorage(), PlayerData.class);
		CapabilityManager.INSTANCE.register(IMobData.class, new MobDataStorage(), MobData.class);
		network = NetworkRegistry.INSTANCE.newSimpleChannel(Reference.MODID);
		
		ModMessages.registerMessages();
		ModEntities.init();
		
		proxy.preInit();
	}
	
	@EventHandler
	public void init(FMLInitializationEvent event)
	{
		MinecraftForge.EVENT_BUS.register(new AttachCapabilityHandler());
		MinecraftForge.EVENT_BUS.register(new ModEventHandler());
		
		NetworkRegistry.INSTANCE.registerGuiHandler(instance, new GuiHandler());
		proxy.init();
	}
	
	@EventHandler
	public void postInit(FMLPostInitializationEvent event)
	{
		
		proxy.postInit();
	}	
}

 

 

Posted
2 hours ago, Kriptikz said:

Maybe create a method in my proxy to handle this, where the ServerProxy does nothing and ClientProxy has this code?

This is the proper approach. Create a method in your proxy which returns the Minecraft instance on the Client-side only, then use this in your code after the isRemote check. The Server-side implementation should really throw an exception (since the method must never be called server-side).

Posted
16 hours ago, Kriptikz said:

still no idea why it doesn't crash

You said it yourself up above: You had both server and client running on the same machine, so the client was there to load the Minecraft class. As long as the class is loaded in the JVM, the server can load with a reference to a class that it would not load for itself (because class Minecraft is client side-only).

 

It's probably the most common source of "My mod worked in Eclipse and SP but blew a gasket as soon as I tried it in true MP" threads that run like a rash throughout this help forum. I myself tripped over class Minecraft's client-only restriction in my first mod and found help in threads going back to 1.6.2 and earlier.

 

Someday this forum will have a dynamic FAQ AI that detects that predictable error text in the crash report and sends a stock reply plus an admonition to Google the error message to see the thousands (ok, hundreds) of identical past threads. Until then, each newbie has the privilege of repeating the lore to the next who comes along -- so you're now the officer of the watch, please field the next instance (which will probably come within the next week or two).

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Posted
17 hours ago, Jay Avery said:

Create a method in your proxy which returns the Minecraft instance

Returns? That could lead to the same sort of reference to a missing class. I recommend a proxy method that uses the Minecraft class to do what needs doing client-side (if indeed that's even the best way to design this mod).

 

Looking at that design, it doesn't fit with "proper" client-server purposes. The server is the authority, and the client is the UI. Therefore, if the "stun" effect is to prevent player movement, it should do its work on the server (the authority). It should not hack the keys (or even trust a player to be limited by them). In theory, a devious player could have a second set of movement controls (e.g. a joystick mod) to continue moving, and your server-side would not be enforcing the stun.

 

I hate to say it, but it looks like you should go back to the drawing board and find a hook server side to do what you want.

  • Like 1

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Posted
3 minutes ago, jeffryfisher said:

Looking at that design, it doesn't fit with "proper" client-server purposes. The server is the authority, and the client is the UI. Therefore, if the "stun" effect is to prevent player movement, it should do its work on the server (the authority). It should not hack the keys (or even trust a player to be limited by them). In theory, a devious player could have a second set of movement controls (e.g. a joystick mod) to continue moving, and your server-side would not be enforcing the stun.

Yea I figured this could end up becoming a problem. From what I understand the client is what moves the player and the server validates that movement correct? But yea, back to the drawing board.

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.