I am looking for a way to reset specific values when a player logs out of his world on a server or client. The event needs to fire on client and server sides to reset these values. The method WorldEvent.Unload works great, except that it is also fired when the player's dimension changes. Is there a different way I can do this? Thanks!
"PlayerEvent.PlayerLoggedOut" works great for the server side, but some of the values I need to reset include textures and"PlayerEvent.PlayerLoggedOut" doesn't run a client thread. Thanks for the idea though! Are there any other events, or will I just have to use that one and use a packet from server to client?
I've noticed that in the Event class, there is a ListenerList. Would it be possible in the WorldEvent.Unload event to remove the listeners "DimensionManager.unloadWorlds" and ForgeInternalHandler.onDimensionsUnload(Unload)?" That's what I need mostly.
I don't think you want to remove listeners, as that might affect other mods. Just handle the log out event on server and send custom packet. Not really that difficult.
I though it wouldn't be too difficult, but the packet doesn't seem to be received on the client side using "PlayerEvent.PlayerLoggedOut." It doesn't receive on the client of an integrated server or dedicated server. Any ideas? Here is my code:
@SubscribeEvent()
public void onLogOutServer(PlayerEvent.PlayerLoggedOutEvent event)
{
//TODO packet works server side, but client seems to "get away" before it receives the message...
ModOreSheep.INSTANCE.sendTo(new ClientResetPacket(true), (EntityPlayerMP) event.player);
}
Custom Packet and Handler: I assume that the "reset" boolean isn't necessary, but I wasn't sure if a message could be empty.
public class ClientResetPacket implements IMessage
{
boolean reset;
public ClientResetPacket()
{
System.out.println("ClientResetPacket ran!");
}
public ClientResetPacket(boolean canExecute)
{
this.reset = canExecute;
}
@Override
public void toBytes(ByteBuf buf)
{
buf.writeBoolean(reset);
}
@Override
public void fromBytes(ByteBuf buf)
{
buf.readBoolean();
}
//The params of the IMessageHandler are <REQ, REPLY>, meaning that the first is the packet you are receiving, and the second is the packet you are returning. The returned packet can be used as a "response" from a sent packet.
public static class ClientResetHandler implements IMessageHandler<ClientResetPacket, IMessage>
{
@Override
public IMessage onMessage(ClientResetPacket message, MessageContext ctx)
{
if (message.reset)
{
System.out.println("packet reset client");
/*method to reset client*/;
}
return null;
}
}
}
Error:
[08:53:56] [Netty Server IO #3/ERROR] [FML]: NetworkDispatcher exception
java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.write0(Native Method) ~[?:1.8.0_101]
at sun.nio.ch.SocketDispatcher.write(Unknown Source) ~[?:1.8.0_101]
at sun.nio.ch.IOUtil.writeFromNativeBuffer(Unknown Source) ~[?:1.8.0_101]
at sun.nio.ch.IOUtil.write(Unknown Source) ~[?:1.8.0_101]
at sun.nio.ch.SocketChannelImpl.write(Unknown Source) ~[?:1.8.0_101]
at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:417) ~[NioSocketChannel.class:4.1.9.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:856) ~[AbstractChannel$AbstractUnsafe.class:4.1.9.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:362) ~[AbstractNioChannel$AbstractNioUnsafe.class:4.1.9.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:823) ~[AbstractChannel$AbstractUnsafe.class:4.1.9.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1296) ~[DefaultChannelPipeline$HeadContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:117) ~[ChannelDuplexHandler.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115) ~[ChannelOutboundHandlerAdapter.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115) ~[ChannelOutboundHandlerAdapter.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115) ~[ChannelOutboundHandlerAdapter.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.flush(NetworkDispatcher.java:559) ~[NetworkDispatcher.class:?]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:802) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831) ~[AbstractChannelHandlerContext.class:4.1.9.Final]
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1032) ~[DefaultChannelPipeline.class:4.1.9.Final]
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:296) ~[AbstractChannel.class:4.1.9.Final]
at net.minecraft.network.NetworkManager$4.run(NetworkManager.java:261) [NetworkManager$4.class:?]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [AbstractEventExecutor.class:4.1.9.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403) [SingleThreadEventExecutor.class:4.1.9.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:442) [NioEventLoop.class:4.1.9.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [SingleThreadEventExecutor$5.class:4.1.9.Final]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_101]
In the output, the a dedicated server outputs "ClientResetPacket ran!" and somtimes the error above, but nothing on an integrated server. In both, the client does not output "packet reset client." is there a problem with the "PlayerEvent.PlayerLoggedOutEvent'" event or is there a problem with my code? Thanks!
Okay assuming that you did the packet properly, I guess it may make sense since the player is logged out that it would no longer be able to send a packet to the client.
Since both of us can't seem to find a client side event that is suitable, then maybe you need to use a "keep alive" packet system. You could send a packet once a second (or some such interval) to the client and if the client doesnt get the packet in over two seconds it could assume that it goi logged out or otherwise disconnected.
Maybe there is another way to achieve what you're goal is. You never really said why you need this. What are you trying to do at the high level?
I got everything to work! It's not a great way to do it, but it works. I used the "FMLNetworkEvent.ClientDisconnectionFromServerEvent," which works for clients on both dedicated and integrated servers.
To answer your question, I needed the client to delete some entity dynamic textures that are created when the player looks at my entity (see my ore sheep mod). I needed to delete these textures when logging out of a world, preventing a memory leak/refreshing the texures for a new world. This new event works, except that trying to delete textures in this event using "Minecraft.getMinecraft().getTextureManager().deleteTexture(/*texture here*/)" gives an error "no openGL in this thread" or something like that. I had to set a boolean to true in "FMLNetworkEvent.ClientDisconnectionFromServerEvent" and then to a boolean check in my entity's render class to delete the textures the next time it is triggered.
Like I said, it works now, but it is super messy! Ideally, I need to be able to delete the textures directly in the event "FMLNetworkEvent.ClientDisconnectionFromServerEvent" or a similar one.
Cool. That event definitely looks like the right one.
I wouldn't say it really that messy. Events are intended for intercepting the normal processing flow and in this case it is very infrequent so there is no performance concern. After that, there is nothing wrong with having a boolean to indicate the state that gets checked when needed.
I am looking for a way to reset specific values when a player logs out of his world on a server or client. The event needs to fire on client and server sides to reset these values. The method WorldEvent.Unload works great, except that it is also fired when the player's dimension changes. Is there a different way I can do this? Thanks!
Maybe the PlayerEvent.PlayerLoggedOut event might work.
"PlayerEvent.PlayerLoggedOut" works great for the server side, but some of the values I need to reset include textures and"PlayerEvent.PlayerLoggedOut" doesn't run a client thread. Thanks for the idea though! Are there any other events, or will I just have to use that one and use a packet from server to client?
I've noticed that in the Event class, there is a ListenerList. Would it be possible in the WorldEvent.Unload event to remove the listeners "DimensionManager.unloadWorlds" and ForgeInternalHandler.onDimensionsUnload(Unload)?" That's what I need mostly.
I don't think you want to remove listeners, as that might affect other mods. Just handle the log out event on server and send custom packet. Not really that difficult.
I though it wouldn't be too difficult, but the packet doesn't seem to be received on the client side using "PlayerEvent.PlayerLoggedOut." It doesn't receive on the client of an integrated server or dedicated server. Any ideas? Here is my code:
Mod Class:
Packet Handler Class:
Custom Packet and Handler: I assume that the "reset" boolean isn't necessary, but I wasn't sure if a message could be empty.
Error:
In the output, the a dedicated server outputs "ClientResetPacket ran!" and somtimes the error above, but nothing on an integrated server. In both, the client does not output "packet reset client." is there a problem with the "PlayerEvent.PlayerLoggedOutEvent'" event or is there a problem with my code? Thanks!
Okay assuming that you did the packet properly, I guess it may make sense since the player is logged out that it would no longer be able to send a packet to the client.
Since both of us can't seem to find a client side event that is suitable, then maybe you need to use a "keep alive" packet system. You could send a packet once a second (or some such interval) to the client and if the client doesnt get the packet in over two seconds it could assume that it goi logged out or otherwise disconnected.
Maybe there is another way to achieve what you're goal is. You never really said why you need this. What are you trying to do at the high level?
I got everything to work! It's not a great way to do it, but it works. I used the "FMLNetworkEvent.ClientDisconnectionFromServerEvent," which works for clients on both dedicated and integrated servers.
To answer your question, I needed the client to delete some entity dynamic textures that are created when the player looks at my entity (see my ore sheep mod). I needed to delete these textures when logging out of a world, preventing a memory leak/refreshing the texures for a new world. This new event works, except that trying to delete textures in this event using "Minecraft.getMinecraft().getTextureManager().deleteTexture(/*texture here*/)" gives an error "no openGL in this thread" or something like that. I had to set a boolean to true in "FMLNetworkEvent.ClientDisconnectionFromServerEvent" and then to a boolean check in my entity's render class to delete the textures the next time it is triggered.
Like I said, it works now, but it is super messy! Ideally, I need to be able to delete the textures directly in the event "FMLNetworkEvent.ClientDisconnectionFromServerEvent" or a similar one.
Thanks for your help!
Cool. That event definitely looks like the right one.
I wouldn't say it really that messy. Events are intended for intercepting the normal processing flow and in this case it is very infrequent so there is no performance concern. After that, there is nothing wrong with having a boolean to indicate the state that gets checked when needed.