For the people using Realm-Relay, I am sure you may have ran into an incident where you are not able to connect to certain servers. This is due to an unexpected packet size.
US West is the server I kept having issues with because there are so many people at the nexus.
Now the issue at hand happens because when you connect to US West, one of the first few packets that comes back is all the data for EVERY single object that is in the area (where it is possible to render). I literally mean one single packet. Realm-Relay was not ready for a packet so big and as a result it bugs out and fails to connect to US West or any server that has too much data in one spot.
There is a buffer that stores all the data as it comes in until the whole packet is received and then it parses the packet and gets rid of the data in the buffer. This buffer is currently set to a size of 65536.
There are two temporary fixes for this issue:
- 1) change bufferLength to a larger number. 85536 works. But as soon as you hit a packet size that is larger than 85k it will bug out again. So then you change and change it again until you have a large enough buffer to not run into the issue. But now you are wasting space in heap.
- 2) Re-size the buffer larger dynamically during runtime. Well, this is a nice fix that seems to be fairly lasting, but resizing a buffer takes away milliseconds of sending/receiving data. It may cause a few milliseconds of lag. It depends on your system and the Java code.
Those are just temporary fixes that do not require major change in the code design for receiving packets. There are other solutions too that you can implement. Feel free to use which ever solution you find is best.
Steps to implement one of the above changes:
Note: Obviously skip these steps if you already know how to use a Java IDE.
- 1) Download and Install Java SE Development Kit 7 (JDK 7)
- 2) Download and Install an IDE. Eclipse is free but fairly hard to use. I use IntelliJ IDEA at work so I don't know too much about Eclipse. I believe the correct Eclipse version is "Eclipse IDE for Java Developers". I used Eclipse Standard when I need to use Eclipse because I am working with someone that uses Eclipse.
- 3) Configure IDE to use JDK 1.7 or JDK 7. In Eclipse, go to Window Menu -> Preference. On the left side collapse Java -> Compiler. You should now see JDK Compliance on the right side. Change the compiler compliance level to "1.7".
- 4) Download the Realm-Relay v1.1.0 source code. https://******.com/DeVoidCoder/Realm-Relay. On the right side, there should be a Download ZIP. Extract the content.
- 5) Load source code into new project. In Eclipse, go to File menu -> New -> Java Project. Type in a Project Name. In JRE, make sure you select the correct JDK/JRE version. jre7 or JavaSE-1.7. Keep in mind the location of the project file. Click on Next and then Finish. Now go to where you extracted the zip file and copy all files within "Realm-Relay-master" into the location of the project folder you made in eclipse. This should be 2 folders, scripts and src. And a couple of readme/txt files.
- 6) Configure IDE to compile and run the source code. On the left side should be your Workspace and under the Package tab, right click in the white area. Select Refresh. You should see the files inside your project now. In the toolbar at the top you should see a few icons. The one you need is "Run". It should be a white play icon with a green circle around it. Before you click on it, make sure to close any existing Realm Relays you have open. Then Click on it and select Java Application. At this point, there should be a console window that starts outputting text. If it was successful in compiling, then you should see something like this "22:05:03 Realm Relay listener started" at the bottom. If not, post what was output and I can see if I can give you some tips.
- 7) Modify Code. This will be explained below.
- 8) Create a runnable jar file. Once you are sure you can compile the code successfully and you see "Realm Relay listener started". Go to File menu -> Export. In the Export window look for Java and expand it. There should be an item called "Runnable JAR File". Select it and click next. Under Launch Configuration there should only be one item, but this depends on workspace projects. Mine was called "Java Application Realm-Relay". Select up the Export destination and click Finish.
- 9) Copy the new jar file into the realm-relay folder that you have been using. There should be the win_start.bat there. At this point, you can either replace the realmrelay.jar or rename it. Or you can copy the win_start.bat and point it at the new jar file you compiled.
- 10) Run the bat and if everything went smoothly then you have just modified the realm relay code.
Note: I may have missed the JDK configuration in Eclipse. The basic idea is that it needs to point the JDK 1.7.
Modifying the source code
Now the fun part. First you need to get an idea of what the workspace window on the left is and how to use it. It basically contains and overview of all your files/classes. In the folder "src", you will see a bunch of items. These are package names. When you open up the package names, such as "realmrelay" you will see files. In this case, "GetXMLParse.java", "User.java", and "ROTMGRelay.java". Double click on the files will open up the code editor and here you can modify the code.
Lets label the fixes as #1 and #2. Use one or both if you want? One should be fine.
#1) Open up "User.java". Near the top there is a line like this: "private static final int bufferLength = 65536;". Oh. Hey! we see that number I mentioned before. 65536. Just change the number to something bigger. Don't go too big then you can run out of memory. 85536. 10000? Whatever you want. That was easy. Just run the project and make sure it can compile.
#2) This one requires a bit more work. Open up "ROTMGRelay.java".
First you need to a library to the class. You can do this by adding this line at the top: "import java.util.Arrays;" after "package realmrelay;"
Next, You need to find the code that handles the receiving of packets from the server.
Specifically, do a Find (Ctrl + F) for "while (user.remoteBufferIndex >= 5)". The next line after that code should be declare and set integer variable called "packetLength". After declaration of the integer variable, add this code:
Code:
// check to see if packet length is bigger than buffer size
if (user.remoteBuffer.length < packetLength)
{ // resize buffer to match packet length
user.remoteBuffer = Arrays.copyOf(user.remoteBuffer, packetLength);
}
The resulting code should look something like this:
Code:
user.remoteBufferIndex += bytesRead;
while (user.remoteBufferIndex >= 5) {
int packetLength = ((ByteBuffer) ByteBuffer.allocate(4).put(user.remoteBuffer[0]).put(user.remoteBuffer[1]).put(user.remoteBuffer[2]).put(user.remoteBuffer[3]).rewind()).getInt();
// check to see if packet length is bigger than buffer size
if (user.remoteBuffer.length < packetLength)
{ // resize buffer to match packet length
user.remoteBuffer = Arrays.copyOf(user.remoteBuffer, packetLength);
}
if (user.remoteBufferIndex < packetLength) {
break;
}
To continue with #2), go to "User.java" and look for "public final byte[] remoteBuffer = new byte[bufferLength];"
Remove the "final" and it should become "public byte[] remoteBuffer = new byte[bufferLength];"
#2 already applied!
I just took a look at the realm-relay ****** and realized that DeVoidCoder had already accepted my pull request for the temporary packet resize change. If you download it now, you should have it patched up already.
The only thing you would need to do is change if you got this accidental commit:
"ROTMGRelay.echo("Server Packet: " + user.remoteBufferIndex + " / " + packetLength);"
to
"//ROTMGRelay.echo("Server Packet: " + user.remoteBufferIndex + " / " + packetLength);"
Or else you would have unneeded spam.
That is all... good luck!