Giter VIP home page Giter VIP logo

jraknet's Introduction

Twitter Reddit YouTube Twitch

📣 Heya, my name's Whirvis!

I'm the creator of JRakNet and Ketill. I'm a self taught software engineer from the age of twelve, and an aspring game developer. I code primarily in Java, Kotlin, and C. Of course, I am also happy to code in other languages as needed.

jraknet's People

Contributors

danissimo avatar dependabot[bot] avatar hmy2001 avatar mrpowergamerbr avatar saehing avatar sgdc3 avatar thestacktracewhisperer avatar whirvis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jraknet's Issues

Event system progress

There is currently no proper event system, and it is needed for API users to properly use JRakNet.

Add packet priorities and send at correct intervals

At the moment, JRakNet sends packets at the first update after they are added to the queue and then resends them at a pre-specified interval. This does work without problems, however it can be taxing on some machines.

There are also no packet priorities, which, like packet reliabilities, can increase the performance of the game if used correctly. At the moment the only priority is essentially IMMEDIATE as every packet as sent as soon as possible.

LoginFailureException caused by getMaximumTransferUnit()

It is suspected that when the client is trying to retrieve the computers maximum transfer unit so it can be used during login, that the MTU being returned is sometimes -1. This is expected to happen on some machines, but since the client isn't prepared to handle it if -1 is returned no matter what server the client is attempting to connect to a LoginFailureException will ALWAYS be thrown.

Client connections are re-instantiated too easily

During login, client might send a duplicate packet because it thought the packet might of been lost. This causes the server to remove the connecting client saying that it was re-instantiating the session, when the client never actually restarted the login.

java.lang.IndexOutOfBoundsException: ... UnpooledUnsafeHeapByteBuf on server, and didn't call handleMessage()

I've tried to properly sending message from client to server for quite long time without success.

I did read document on Raknet, and saw a few sample code here of JRakNet in issues section as I cannot find it anywhere. But still I cannot make it through. I believe it might due to I didn't do it properly and correctly in the way of Raknet.

From testing, as soon as client connected and then sent message, server has the following error (but not crash)

java.lang.IndexOutOfBoundsException: readerIndex(19) + length(1) exceeds writerIndex(19): UnpooledUnsafeHeapByteBuf(ridx: 19, widx: 19, cap: 19)
	at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1413)
	at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:687)
	at net.marfgamer.jraknet.Packet.readTriadLE(Packet.java:239)
	at net.marfgamer.jraknet.protocol.message.EncapsulatedPacket.decode(EncapsulatedPacket.java:107)
	at net.marfgamer.jraknet.protocol.message.CustomPacket.decode(CustomPacket.java:76)
	at net.marfgamer.jraknet.server.RakNetServer.handleMessage(RakNetServer.java:607)
	at net.marfgamer.jraknet.server.RakNetServerHandler.channelRead(RakNetServerHandler.java:128)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:332)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1319)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:904)
	at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:571)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:512)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:426)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:398)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:805)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
	at java.lang.Thread.run(Thread.java:748)

it didn't receive any message, it didn't call handleMessage(). Right after that client will be timeout.

I have the following quick testing code for both server and client.
Here is for server code (in Kotlin)

import net.marfgamer.jraknet.server.RakNetServer
import net.marfgamer.jraknet.server.RakNetServerListener
import net.marfgamer.jraknet.session.RakNetClientSession
import net.marfgamer.jraknet.RakNetPacket

fun main(args: Array<String>) {
	val server = RakNetServer(5670, 10)

	server.listener = object: RakNetServerListener {
		override fun onClientConnect(session: RakNetClientSession) {
			println("Client connected from ${session.address}")
		}

		override fun onClientDisconnect(session: RakNetClientSession, reason: String) {
			println("Client disconnected: ${session.address}")
		}

		override fun handleMessage(session: RakNetClientSession, packet: RakNetPacket, channel: Int) {
			println("Got message from ${session.address}, packet id: ${packet.id}")
		}

		override fun onServerStart() {
			println("Server started")
		}
	}

	server.start()
}

and here for client side

import java.net.InetSocketAddress
import net.marfgamer.jraknet.client.RakNetClient
import net.marfgamer.jraknet.client.RakNetClientListener
import net.marfgamer.jraknet.session.RakNetServerSession
import net.marfgamer.jraknet.RakNetPacket
import net.marfgamer.jraknet.protocol.Reliability
import net.marfgamer.jraknet.protocol.MessageIdentifier
import net.marfgamer.jraknet.protocol.message.acknowledge.Record
import net.marfgamer.jraknet.protocol.message.CustomPacket

class Client {
	
	interface Listener {
		fun onClient_Connect(client: Client)
		fun onClient_Disconnect(client: Client)
	}

	val SERVER_ADDRESS: String = "xxx.xxx.xxx.xxx"
	val SERVER_PORT: Int = 5070

	val client = RakNetClient()
	var listener: Listener? = null

	init {
			val that = this

			client.listener = object: RakNetClientListener {
			override fun onConnect(session: RakNetServerSession) {
				println("Successfully connected to server with address ${session.address}")

				that.listener?.onClient_Connect(that)
			}

			override fun onDisconnect(session: RakNetServerSession, reason: String) {
				println("Successfully disconnected from server with address ${session.address}")

				that.listener?.onClient_Disconnect(that)

				client.shutdown()
			}

			override fun onAcknowledge(session: RakNetServerSession, record: Record) {
				println("Acked ${record.index}:${record.endIndex}")
			}

			override fun onNotAcknowledge(session: RakNetServerSession, record: Record) {
				println("Not ack ${record.index}:${record.endIndex}")
			}

			override fun handleMessage(session: RakNetServerSession, packet: RakNetPacket, channel: Int) {
				println("Received ${packet.readString()} on channel: $channel")
			}

			override fun onHandlerException(address: InetSocketAddress, throwable: Throwable) {
				println("handled exception")
				throwable.printStackTrace();
			}

			override fun onThreadException(throwable: Throwable) {
				println("handled thread exception")
				throwable.printStackTrace();
			}
		}
	}

	fun connectThreaded() {
		client.connectThreaded(SERVER_ADDRESS, SERVER_PORT)
	}

	fun sendMessage(message: String) {
		val packet = RakNetPacket(MessageIdentifier.ID_USER_PACKET_ENUM.toInt())
		packet.write((message).toByteArray())
		client.sendMessage(Reliability.RELIABLE_SEQUENCED_WITH_ACK_RECEIPT, 0, packet)
	}
}

class Consumer: Client.Listener {
	val client = Client()
	
	init {
		client.listener = this
		client.connectThreaded()
	}

	override fun onClient_Connect(client: Client) {
		client.sendMessage("Hello")
		println("sent message")
	}

	override fun onClient_Disconnect(client: Client) {
	}
}

fun main(args: Array<String>)  {
	Consumer()
}

Note for client side, I started the client with connectThreaded() to avoid blocking in calling thread.

What did I do wrong here? Please kindly point me out to the proper and correct way to send message from client to server. Thanks!

PS: Not for minecraft server, just normal server/client setup.

Please add support for more MTU values

The MCPE game uses the MTU 1492 but JRakNet doesn't support that MTU. The way I have fixed this for my own use is by adding new MaximumTransferUnit(1492, 3) to the list of units in RakNetClient. I put it as the first item in the array

MTU values don't seem to be right, somewhere

When connecting to a Minecraft PE server it sends back a connection response 1 packet with an MTU of 1492, while the library expects an MTU of 1464. It then throws this exception:

net.marfgamer.jraknet.client.InvalidProtocolException: Received invalid packet from server during login at net.marfgamer.jraknet.client.SessionPreparation.handlePacket(SessionPreparation.java:94) at net.marfgamer.jraknet.client.RakNetClient.handleMessage(RakNetClient.java:410) at net.marfgamer.jraknet.client.RakNetClientHandler.channelRead(RakNetClientHandler.java:67) at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:84) at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:153) at io.netty.channel.PausableChannelEventExecutor.invokeChannelRead(PausableChannelEventExecutor.java:86) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:389) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:956) at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:514) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:471) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:385) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:351) at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) at io.netty.util.internal.chmv8.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1412) at io.netty.util.internal.chmv8.ForkJoinTask.doExec(ForkJoinTask.java:280) at io.netty.util.internal.chmv8.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:877) at io.netty.util.internal.chmv8.ForkJoinPool.scan(ForkJoinPool.java:1706) at io.netty.util.internal.chmv8.ForkJoinPool.runWorker(ForkJoinPool.java:1661) at io.netty.util.internal.chmv8.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:126)

The servers I've tried are MiNet and an MCPE Lan Game. I've also tried Nukkit, but haven't verified if the problem is the same. I got this stack trace when I modified cn.nukkit.raknet.server.SessionManager.tickProcessor() to print the exception before blocking an address

2017-1-24 21:38:44 [ALERT] java.lang.ArrayIndexOutOfBoundsException: 17 at cn.nukkit.raknet.protocol.Packet.getByte(Packet.java:71) at cn.nukkit.raknet.protocol.packet.CLIENT_CONNECT_DataPacket.decode(CLIENT_CONNECT_DataPacket.java:34) at cn.nukkit.raknet.server.Session.handleEncapsulatedPacketRoute(Session.java:387) at cn.nukkit.raknet.server.Session.handleEncapsulatedPacket(Session.java:335) at cn.nukkit.raknet.server.Session.handlePacket(Session.java:491) at cn.nukkit.raknet.server.SessionManager.receivePacket(SessionManager.java:183) at cn.nukkit.raknet.server.SessionManager.tickProcessor(SessionManager.java:80) at cn.nukkit.raknet.server.SessionManager.run(SessionManager.java:70) at cn.nukkit.raknet.server.SessionManager.<init>(SessionManager.java:58) at cn.nukkit.raknet.server.RakNetServer.run(RakNetServer.java:101)

I can't figure out where the problem is, but that's what I do know.

No UDT congestion control

RakNet has a feature built into it called the UDT congestion control algorithm, which helps with making sure data is not lost and sends at a reasonable rate for the client. At the moment, JRakNet sends all user data immediately and other internal features like recovery are done at a set interval.

Only one split packet can be sent before JRakNet breaks

RakNetSession's are only able to send one split packet, after that they are no longer able to properly handle them. I should've tested multiple split packets sends before publishing v2.0 at all :/ I believe this has to do with the sequence number indexing that I have neglected for the past 3 months thinking they made no difference. I was most likely sorely mistaken.

RakNetPacket does not check for overflow with ID's

While the RakNetPacket class makes sure the ID is at least 0, it does not make sure that the ID is no bigger than 255. This can cause confusing glitches as no exception is thrown since the int is just casted down to an unsigned byte. An example of this would be:

  • User creates RakNetPacket with ID 543
  • RakNetPacket throws no errors, as 543 is well within the range of a signed int
  • RakNetPacket encodes ID by giving it to the packet class, which also throws no errors as it allows integers when calling writeByte() or writeUByte() and just casts it down to a byte before ANDing it with 0xFF
  • 31 gets written instead

java.lang.UnsupportedOperationException: direct buffer

fev 21, 2017 8:54:10 PM io.netty.channel.AbstractChannelHandlerContext invokeExceptionCaught
ADVERT╩NCIA: An exception 'java.lang.NullPointerException' [enable DEBUG level for full stacktrace] was thrown by a user handler's exceptionCaught() method while handling the following exception:
java.lang.UnsupportedOperationException: direct buffer
        at io.netty.buffer.PooledUnsafeDirectByteBuf.array(PooledUnsafeDirectByteBuf.java:343)
        at net.marfgamer.jraknet.server.RakNetServerHandler.channelRead(RakNetServerHandler.java:102)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:332)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1319)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:904)
        at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:571)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:512)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:426)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:398)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:805)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
        at java.lang.Thread.run(Unknown Source)

Latest JRakNet version

Code:


        raknet = new RakNetServer(server.getPort(), server.getMaxPlayers(), new MCPEIdentifier(server.getMotd(), ProtocolInfo.CURRENT_PROTOCOL, ProtocolInfo.MINECRAFT_VERSION_NETWORK, server.getOnlinePlayers().size(),
                server.getMaxPlayers(), server.getServerUniqueId().getMostSignificantBits() & Long.MAX_VALUE, "New World", "Survival"));
        raknet.setListener(new RakNetServerListener() {
            // Client connected
            @Override
            public void onClientConnect(RakNetClientSession session) {
                openSession(String.valueOf(session.getGloballyUniqueId()), session.getAddress().getHostString(), session.getInetPort(), session.getGloballyUniqueId());
            }

            // Client disconnected
            @Override
            public void onClientDisconnect(RakNetClientSession session, String reason) {
                // We first check if the global ID exists (prevents NPE when shutting down the server)
                if (players.containsKey(String.valueOf(session.getGloballyUniqueId()))) {
                    close(players.get(String.valueOf(session.getGloballyUniqueId())), reason);
                }
            }

            // Packet received
            @Override
            public void handleMessage(RakNetClientSession session, RakNetPacket packet, int channel) {
                handleRakNetPacket(session.getGloballyUniqueId(), packet);
            }
            
            // UT3 server query
            @Override
            public void handleNettyMessage(ByteBuf buf, InetSocketAddress address) {
                System.out.println("Received Netty message!");
            }
        });

(This happens without any clients connecting to it)

Some features for v2.3

  • Add a feature so clients can add a list of external servers they will repeatedly ping and update Implemented
  • Add the ability to retrieve the current client protocol and server protocol (Even though it is already listed in the RakNet interface) Implemented
  • Add ability for server to enable and disable broadcasting Implemented
  • Add the ability to retrieve the release, major, and minor version of JRakNet using the RakNet interface Implemented
  • Fix #13 Fixed

Minecraft: Windows 10 edition fails to connect to the server

I'm running your server example code on Windows 10 and trying to connect to the server using the Minecraft: Windows 10 edition. Whenever I attempt to connect to the server from this version on my machine this error is thrown. The server is running on the default Minecraft PC port (25565). Also, connecting to the server works fine on Minecraft: Pocket Edition, it only crashes when using Minecraft: Windows 10 Edition.

ConcurrentModificationException in RakNetSession

Somethings the recoveryQueue IntMap will cause a ConcurrentModificationException in the RakNetSession class, it is thought to be due to a lack of synchronization in the methods working with it but it is not exactly known.

Consistent lag under heavy loads

When the server is under heavy loads in terms of packets to handle, the sever will start to choke up at a extremely consistent interval and then unfreeze and handle the packets normally.

Client calls onConnect() too early

While this is not a HUGE deal, it can be a bit annoying at times. When the client is connecting, the last packet needed for connection to complete is a NewIncomingConnection packet, and the server just accepts it unless the connection failed. In that case, it will send a ID_CONNECTION_ATTEMPT_FAILED. This can be fixed by making use of the WITH_ACK_RECEIPT packets, but I have yet to implement that feature.

Record equals() method broken

While using equals() on the Record with another Record object works, using any native number types results in a ClassCastException.

Split queue glitch

If a new unreliable packet overflows the split queue, it too will be remove along with the other unreliable packets.

Client has disconnected from the server for the reason "null"

Client from address /192.168.43.212:19132 has connected to the server
Client from address /192.168.43.212:19132 has disconnected from the server for the reason "null"

Happens with both MCW10/MCPE and that happens randomly, sometimes it decides to "fuck everything" and disconnect for the reason "null", sometimes it works and doesn't disconnect for no reason.

NullPointerException relating to listeners

Gentlemen, during the startup of the server and the client it is not checked if the listener is null or not. This in turn can cause a NullPointerException if starting a server or client using startThreaded() if an exception occurs during startup. I plan to fix this as soon as possible.

ArrayUtils.toJRakNetString() broken

When putting the array together, the array forgets to actually get the object based on it's index and instead uses the whole array, creating a jarbled mess.

Invalid CustomPacket ID range

The CustomPacket ID range is 0x7F to 0x86, when it should be 0x80 to 0x8F. This causes platforms that do not use this range (0x75-0x86) will not be able to connect to the server.

No client

Needed so API users can actually build games with the servers they have made

Reliable packets are not ACK'ed

Sometimes reliable packets will not be responded too with an ACK packet, causing clients or servers to repeatedly send a packet over and over again. It is unknown what causes this bug.

JRakNet binds to port even it's been bound by another program

Normally with Java sockets, if a port is being used by another program an exception is thrown saying the address is in use and it cannot bind. However with Netty in JRakNet, even if the port has been bound by another program it succeeds in binding to the port. However, both servers fail to receive packets from then on until both of them are closed and one of them is restarted.

MCPE 1.1 not connecting

What the title says. With PE 1.1 neither onClientConnect, onClientDisconnect or handleMessage are being called, and the client doesn't show the server in the server list.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.