Kriptikz Posted April 12, 2017 Posted April 12, 2017 (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 April 14, 2017 by Kriptikz Quote
Draco18s Posted April 12, 2017 Posted April 12, 2017 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. Quote 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.
Kriptikz Posted April 12, 2017 Author Posted April 12, 2017 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(); } } Quote
Kriptikz Posted April 13, 2017 Author Posted April 13, 2017 Even though it's not crashing I understand that I shouldn't do it this way, what would be the recommended way to do this? Quote
Jay Avery Posted April 13, 2017 Posted April 13, 2017 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). Quote
Kriptikz Posted April 13, 2017 Author Posted April 13, 2017 Ok thanks guys, still no idea why it doesn't crash, but I'm going to fix it before it does. Now to figure exactly how I want to handle this. Quote
jeffryfisher Posted April 13, 2017 Posted April 13, 2017 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). Quote 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.
jeffryfisher Posted April 13, 2017 Posted April 13, 2017 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. 1 Quote 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.
Kriptikz Posted April 13, 2017 Author Posted April 13, 2017 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. Quote
Recommended Posts
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.