Skip to content

Commit 5747968

Browse files
author
jython234
committed
Start work on a JRakLib client library.
1 parent d8bae60 commit 5747968

3 files changed

Lines changed: 410 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* JRakLib is not affiliated with Jenkins Software LLC or RakNet.
3+
* This software is a port of RakLib https://github.com/PocketMine/RakLib.
4+
5+
* This file is part of JRakLib.
6+
*
7+
* JRakLib is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* JRakLib is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with JRakLib. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package net.beaconpe.jraklib.client;
21+
22+
import net.beaconpe.jraklib.protocol.EncapsulatedPacket;
23+
24+
/**
25+
* An interface for communication with the client implementation
26+
* .
27+
* @author jython234
28+
*/
29+
public interface ClientInstance {
30+
31+
/**
32+
* Called when the connection is opened to the RakNet server.
33+
* @param serverId The serverId of the RakNet server.
34+
*/
35+
void connectionOpened(long serverId);
36+
37+
/**
38+
* Called when the connection is closed.
39+
* @param reason The reason for the closure.
40+
*/
41+
void connectionClosed(String reason);
42+
43+
/**
44+
* Called when an <code>EncapsulatedPacket</code> is received from the RakNet server.
45+
* @param packet The packet received.
46+
* @param flags Flags from the packet.
47+
*/
48+
void handleEncapsulated(EncapsulatedPacket packet, int flags);
49+
50+
/**
51+
* Called when an unrecognized packet is received from the server.
52+
* @param payload Raw payload (in bytes) of the strange packet.
53+
*/
54+
void handleRaw(byte[] payload);
55+
56+
/**
57+
* Called when an internal option is updated. Current only supports "bandwith"
58+
* @param option The option name.
59+
* @param value The option value.
60+
*/
61+
void handleOption(String option, String value);
62+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/**
2+
* JRakLib is not affiliated with Jenkins Software LLC or RakNet.
3+
* This software is a port of RakLib https://github.com/PocketMine/RakLib.
4+
5+
* This file is part of JRakLib.
6+
*
7+
* JRakLib is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* JRakLib is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with JRakLib. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package net.beaconpe.jraklib.client;
21+
22+
import net.beaconpe.jraklib.Logger;
23+
import net.beaconpe.jraklib.protocol.UNCONNECTED_PING;
24+
import net.beaconpe.jraklib.protocol.UNCONNECTED_PONG;
25+
26+
import java.io.IOException;
27+
import java.net.DatagramPacket;
28+
import java.net.InetSocketAddress;
29+
import java.util.LinkedList;
30+
import java.util.List;
31+
32+
/**
33+
* Represents a JRakLib Client.
34+
* @author jython234
35+
*/
36+
public class JRakLibClient extends Thread{
37+
private static long startTime = -1;
38+
protected InetSocketAddress serverEndpoint;
39+
40+
protected Logger logger;
41+
protected boolean shutdown = false;
42+
43+
protected List<byte[]> externalQueue;
44+
protected List<byte[]> internalQueue;
45+
46+
public JRakLibClient(Logger logger, String serverIP, int serverPort){
47+
if(serverPort < 1 || serverPort > 65536){
48+
throw new IllegalArgumentException("Invalid port range.");
49+
}
50+
this.logger = logger;
51+
this.serverEndpoint = new InetSocketAddress(serverIP, serverPort);
52+
53+
externalQueue = new LinkedList<>();
54+
internalQueue = new LinkedList<>();
55+
56+
start();
57+
}
58+
59+
/**
60+
* Pings a RakNet server at the specified <code>serverIP</code> and <code>serverPort</code>.
61+
* @param logger Logger implementation.
62+
* @param serverIP The server's IP Address.
63+
* @param serverPort The server's port.
64+
* @param tries Amount of packets sent with no response before giving up. (tries)
65+
* @param delay Delay between packets sent with no response. (In milliseconds)
66+
* @throws IOException If there is a problem while reading/sending.
67+
* @return The ping response
68+
*/
69+
public static PingResponse pingServer(Logger logger, String serverIP, int serverPort, int tries, int delay) throws IOException {
70+
if(startTime == -1){
71+
startTime = System.currentTimeMillis();
72+
}
73+
UDPClientSocket socket = new UDPClientSocket(logger);
74+
for(int i = 0; i < tries; i++){
75+
UNCONNECTED_PING ping = new UNCONNECTED_PING();
76+
ping.pingId = System.currentTimeMillis() - startTime; //Amount since start.
77+
ping.encode();
78+
socket.writePacket(ping.buffer, new InetSocketAddress(serverIP, serverPort));
79+
80+
DatagramPacket pkt = socket.readPacketBlocking(delay);
81+
if(pkt != null && pkt.getData()[0] == UNCONNECTED_PONG.ID){
82+
UNCONNECTED_PONG pong = new UNCONNECTED_PONG();
83+
pong.buffer = pkt.getData();
84+
pong.decode();
85+
return new PingResponse(pong.serverID, pong.pingID, pong.serverName);
86+
}
87+
}
88+
return null;
89+
}
90+
91+
public boolean isShutdown(){
92+
return shutdown == true;
93+
}
94+
95+
public void shutdown(){
96+
shutdown = true;
97+
}
98+
99+
public int getServerPort(){
100+
return serverEndpoint.getPort();
101+
}
102+
103+
public String getServerIP(){
104+
return serverEndpoint.getHostString();
105+
}
106+
107+
public Logger getLogger(){
108+
return logger;
109+
}
110+
111+
public List<byte[]> getExternalQueue(){
112+
return externalQueue;
113+
}
114+
115+
public List<byte[]> getInternalQueue(){
116+
return internalQueue;
117+
}
118+
119+
public void pushMainToThreadPacket(byte[] bytes){
120+
internalQueue.add(0, bytes);
121+
}
122+
123+
public byte[] readMainToThreadPacket(){
124+
if(!internalQueue.isEmpty()) {
125+
byte[] data = internalQueue.get(internalQueue.size() - 1);
126+
internalQueue.remove(data);
127+
return data;
128+
}
129+
return null;
130+
}
131+
132+
public void pushThreadToMainPacket(byte[] bytes){
133+
externalQueue.add(0, bytes);
134+
}
135+
136+
public byte[] readThreadToMainPacket(){
137+
if(!externalQueue.isEmpty()) {
138+
byte[] data = externalQueue.get(externalQueue.size() - 1);
139+
externalQueue.remove(data);
140+
return data;
141+
}
142+
return null;
143+
}
144+
145+
private class ShutdownHandler extends Thread {
146+
@Override
147+
public void run() {
148+
if (shutdown != true) {
149+
logger.emergency("[JRakLib Thread #" + getId() + "] JRakLib crashed!");
150+
}
151+
}
152+
}
153+
154+
/**
155+
* Represents a PingResponse from a server.
156+
*/
157+
public static class PingResponse {
158+
/**
159+
* The PingId from the packet. The original amount sent to the server was the time sent start. (in milliseconds)
160+
* <br>
161+
* You can find more information here: http://wiki.vg/Pocket_Minecraft_Protocol#ID_CONNECTED_PING_OPEN_CONNECTIONS_.280x01.29
162+
*/
163+
public final long pingId;
164+
/**
165+
* The serverId from the packet. This is the server's unique identifier generated at startup. (The value changes each runtime, and could be modified in transport)
166+
*/
167+
public final long serverId;
168+
/**
169+
* The server's name or MOTD.
170+
*/
171+
public final String name;
172+
173+
public PingResponse(long serverId, long pingId, String name){
174+
this.pingId = pingId;
175+
this.serverId = serverId;
176+
this.name = name;
177+
}
178+
}
179+
180+
@Override
181+
public void run(){
182+
setName("JRakLib Client Thread #"+getId());
183+
Runtime.getRuntime().addShutdownHook(new ShutdownHandler());
184+
UDPClientSocket socket = new UDPClientSocket(logger);
185+
}
186+
}

0 commit comments

Comments
 (0)