Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Player Entity Stuck #97

Closed
SpaceManiac opened this issue May 23, 2014 · 1 comment
Closed

Player Entity Stuck #97

SpaceManiac opened this issue May 23, 2014 · 1 comment
Labels

Comments

@SpaceManiac
Copy link
Member

Sometimes, the player entity becomes "stuck" existing in the world even when its corresponding GlowSession is no longer being pulsed and its connection has closed.

Here's a pair of stacktraces that preceded one instance of the problem:

00:47:15 [WARNING] No codec to write: LoginSuccessMessage in PLAY
00:47:15 [SEVERE] Error in network output
io.netty.handler.codec.EncoderException: java.lang.Exception: Unknown message type: class net.glowstone.net.message.login.LoginSuccessMessage.
        at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:107)
        at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:645)
        at io.netty.channel.DefaultChannelHandlerContext.access$2000(DefaultChannelHandlerContext.java:29)
        at io.netty.channel.DefaultChannelHandlerContext$WriteTask.run(DefaultChannelHandlerContext.java:906)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
        at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.Exception: Unknown message type: class net.glowstone.net.message.login.LoginSuccessMessage.
        at com.flowpowered.networking.pipeline.MessageEncoder.encode(MessageEncoder.java:54)
        at com.flowpowered.networking.pipeline.MessageEncoder.encode(MessageEncoder.java:41)
        at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:89)
        ... 7 more
00:47:15 [SEVERE] Error while executing GlowTask{id=3, plugin=null, sync=true: net.glowstone.net.handler.login.EncryptionKeyResponseHandler$ClientAuthThread$1@1b23fa7}
java.lang.NullPointerException
        at net.glowstone.EventFactory.onPlayerLogin(EventFactory.java:119)
        at net.glowstone.net.GlowSession.setPlayer(GlowSession.java:204)
        at net.glowstone.net.handler.login.EncryptionKeyResponseHandler$ClientAuthThread$1.run(EncryptionKeyResponseHandler.java:156)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at net.glowstone.scheduler.GlowTask.run(GlowTask.java:163)
        at net.glowstone.scheduler.GlowScheduler.pulse(GlowScheduler.java:180)
        at net.glowstone.scheduler.GlowScheduler.access$100(GlowScheduler.java:24)
        at net.glowstone.scheduler.GlowScheduler$2.run(GlowScheduler.java:109)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

In this case, #91 causes data to be sent which confuses the client, causing it to disconnect. Then, because the disconnect happened so quickly, an NPE occurs trying to determine the IP address of the now-disconnected socket for PlayerJoinEvent (which is still trying to happen even though the player is now disconnected). The session is removed from the SessionRegistry but the player entity is left behind. A problem is later caused when the player is kicked, for example during shutdown, when sending the kick message to a closed socket and then trying to add a listener to the (null) future. This symptom can be removed by changing the area near the sendWithFuture call to the following, but it does not fix the cause.

} else {
    ChannelFuture future = sendWithFuture(new KickMessage(reason));
    // sendWithFuture returns null if channel is already closed - maybe a little dumb
    if (future != null) {
        sendWithFuture(new KickMessage(reason)).addListener(ChannelFutureListener.CLOSE);
    }
}

When and how GlowSession#onDisconnect, GlowSession#onOutboundThrowable, and GlowNetworkServer#sessionInactivated are called should be investigated.

@SpaceManiac
Copy link
Member Author

I think I've fixed most of the problems detailed in this post in 9827627 and 9287485. It should be impossible now except under sketchy race condition circumstances (which might be worth looking into) for the player to exist in the world without being connected.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

1 participant