This repository has been archived by the owner on Oct 20, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- 新增查询MC服务器信息 - 新增 Rcon 功能 - 新增机器人管理员功能 - 新增群自动欢迎 & 自动接受入群请求 - 新增被主人邀请入群自动接受 - 修复了一些 Bug - 新增了更多 Bug
- Loading branch information
1 parent
9bc1513
commit dbae137
Showing
19 changed files
with
1,325 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.3.8-RELEASE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package net.kronos.rkon.core; | ||
|
||
import java.io.IOException; | ||
import java.net.Socket; | ||
import java.nio.charset.Charset; | ||
import java.util.Random; | ||
|
||
import net.kronos.rkon.core.ex.AuthenticationException; | ||
|
||
import top.starwish.namelessbot.utils.Utils; | ||
|
||
public class Rcon { | ||
|
||
private final Object sync = new Object(); | ||
private final Random rand = new Random(); | ||
|
||
private int requestId; | ||
private Socket socket; | ||
|
||
private Charset charset; | ||
|
||
/** | ||
* Create, connect and authenticate a new Rcon object | ||
* | ||
* @param host Rcon server address | ||
* @param port Rcon server port | ||
* @param password Rcon server password | ||
* | ||
* @throws IOException | ||
* @throws AuthenticationException | ||
*/ | ||
public Rcon(String host, int port, byte[] password) throws IOException, AuthenticationException { | ||
// Default charset is utf8 | ||
this.charset = Charset.forName("UTF-8"); | ||
|
||
// Connect to host | ||
this.connect(host, port, password); | ||
} | ||
|
||
/** | ||
* Connect to a rcon server | ||
* | ||
* @param host Rcon server address | ||
* @param port Rcon server port | ||
* @param password Rcon server password | ||
* | ||
* @throws IOException | ||
* @throws AuthenticationException | ||
*/ | ||
public void connect(String host, int port, byte[] password) throws IOException, AuthenticationException { | ||
if(host == null || host.trim().isEmpty()) { | ||
throw new IllegalArgumentException("Host can't be null or empty"); | ||
} | ||
|
||
if(port < 1 || port > 65535) { | ||
throw new IllegalArgumentException("Port is out of range"); | ||
} | ||
|
||
// Connect to the rcon server | ||
synchronized(sync) { | ||
// New random request id | ||
this.requestId = rand.nextInt(); | ||
|
||
// We can't reuse a socket, so we need a new one | ||
this.socket = new Socket(host, port); | ||
} | ||
|
||
// Send the auth packet | ||
RconPacket res = this.send(RconPacket.SERVERDATA_AUTH, password); | ||
|
||
// Auth failed | ||
if(res.getRequestId() == -1) { | ||
throw new AuthenticationException("Password rejected by server"); | ||
} | ||
} | ||
|
||
/** | ||
* Disconnect from the current server | ||
* | ||
* @throws IOException | ||
*/ | ||
public void disconnect() throws IOException { | ||
synchronized(sync) { | ||
this.socket.close(); | ||
} | ||
} | ||
|
||
/** | ||
* Send a command to the server | ||
* | ||
* @param payload The command to send | ||
* @return The payload of the response | ||
* | ||
* @throws IOException | ||
*/ | ||
public String command(String payload) throws IOException { | ||
if (payload == null || payload.trim().isEmpty()) { | ||
throw new IllegalArgumentException("Payload can't be null or empty"); | ||
} | ||
|
||
RconPacket response = this.send(RconPacket.SERVERDATA_EXECCOMMAND, payload.getBytes()); | ||
|
||
return Utils.deColor(new String(response.getPayload(), this.getCharset())); | ||
} | ||
|
||
private RconPacket send(int type, byte[] payload) throws IOException { | ||
synchronized(sync) { | ||
return RconPacket.send(this, type, payload); | ||
} | ||
} | ||
|
||
public int getRequestId() { | ||
return requestId; | ||
} | ||
|
||
public Socket getSocket() { | ||
return socket; | ||
} | ||
|
||
public Charset getCharset() { | ||
return charset; | ||
} | ||
|
||
public void setCharset(Charset charset) { | ||
this.charset = charset; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package net.kronos.rkon.core; | ||
|
||
import java.io.DataInputStream; | ||
import java.io.EOFException; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.net.SocketException; | ||
import java.nio.BufferUnderflowException; | ||
import java.nio.ByteBuffer; | ||
import java.nio.ByteOrder; | ||
|
||
import net.kronos.rkon.core.ex.MalformedPacketException; | ||
|
||
public class RconPacket { | ||
|
||
public static final int SERVERDATA_EXECCOMMAND = 2; | ||
public static final int SERVERDATA_AUTH = 3; | ||
|
||
private int requestId; | ||
private int type; | ||
private byte[] payload; | ||
|
||
private RconPacket(int requestId, int type, byte[] payload) { | ||
this.requestId = requestId; | ||
this.type = type; | ||
this.payload = payload; | ||
} | ||
|
||
public int getRequestId() { | ||
return requestId; | ||
} | ||
|
||
public int getType() { | ||
return type; | ||
} | ||
|
||
public byte[] getPayload() { | ||
return payload; | ||
} | ||
|
||
/** | ||
* Send a Rcon packet and fetch the response | ||
* | ||
* @param rcon Rcon instance | ||
* @param type The packet type | ||
* @param payload The payload (password, command, etc.) | ||
* @return A RconPacket object containing the response | ||
* | ||
* @throws IOException | ||
* @throws MalformedPacketException | ||
*/ | ||
protected static RconPacket send(Rcon rcon, int type, byte[] payload) throws IOException { | ||
try { | ||
RconPacket.write(rcon.getSocket().getOutputStream(), rcon.getRequestId(), type, payload); | ||
} | ||
catch(SocketException se) { | ||
// Close the socket if something happens | ||
rcon.getSocket().close(); | ||
|
||
// Rethrow the exception | ||
throw se; | ||
} | ||
|
||
return RconPacket.read(rcon.getSocket().getInputStream()); | ||
} | ||
|
||
/** | ||
* Write a rcon packet on an outputstream | ||
* | ||
* @param out The OutputStream to write on | ||
* @param requestId The request id | ||
* @param type The packet type | ||
* @param payload The payload | ||
* | ||
* @throws IOException | ||
*/ | ||
private static void write(OutputStream out, int requestId, int type, byte[] payload) throws IOException { | ||
int bodyLength = RconPacket.getBodyLength(payload.length); | ||
int packetLength = RconPacket.getPacketLength(bodyLength); | ||
|
||
ByteBuffer buffer = ByteBuffer.allocate(packetLength); | ||
buffer.order(ByteOrder.LITTLE_ENDIAN); | ||
|
||
buffer.putInt(bodyLength); | ||
buffer.putInt(requestId); | ||
buffer.putInt(type); | ||
buffer.put(payload); | ||
|
||
// Null bytes terminators | ||
buffer.put((byte)0); | ||
buffer.put((byte)0); | ||
|
||
// Woosh! | ||
out.write(buffer.array()); | ||
out.flush(); | ||
} | ||
|
||
/** | ||
* Read an incoming rcon packet | ||
* | ||
* @param in The InputStream to read on | ||
* @return The read RconPacket | ||
* | ||
* @throws IOException | ||
* @throws MalformedPacketException | ||
*/ | ||
private static RconPacket read(InputStream in) throws IOException { | ||
// Header is 3 4-bytes ints | ||
byte[] header = new byte[4 * 3]; | ||
|
||
// Read the 3 ints | ||
in.read(header); | ||
|
||
try { | ||
// Use a bytebuffer in little endian to read the first 3 ints | ||
ByteBuffer buffer = ByteBuffer.wrap(header); | ||
buffer.order(ByteOrder.LITTLE_ENDIAN); | ||
|
||
int length = buffer.getInt(); | ||
int requestId = buffer.getInt(); | ||
int type = buffer.getInt(); | ||
|
||
// Payload size can be computed now that we have its length | ||
byte[] payload = new byte[length - 4 - 4 - 2]; | ||
|
||
DataInputStream dis = new DataInputStream(in); | ||
|
||
// Read the full payload | ||
dis.readFully(payload); | ||
|
||
// Read the null bytes | ||
dis.read(new byte[2]); | ||
|
||
return new RconPacket(requestId, type, payload); | ||
} | ||
catch(BufferUnderflowException | EOFException e) { | ||
throw new MalformedPacketException("Cannot read the whole packet"); | ||
} | ||
} | ||
|
||
private static int getPacketLength(int bodyLength) { | ||
// 4 bytes for length + x bytes for body length | ||
return 4 + bodyLength; | ||
} | ||
|
||
private static int getBodyLength(int payloadLength) { | ||
// 4 bytes for requestId, 4 bytes for type, x bytes for payload, 2 bytes for two null bytes | ||
return 4 + 4 + payloadLength + 2; | ||
} | ||
|
||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/net/kronos/rkon/core/ex/AuthenticationException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package net.kronos.rkon.core.ex; | ||
|
||
public class AuthenticationException extends Exception { | ||
|
||
public AuthenticationException(String message) { | ||
super(message); | ||
} | ||
|
||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/net/kronos/rkon/core/ex/MalformedPacketException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package net.kronos.rkon.core.ex; | ||
|
||
import java.io.IOException; | ||
|
||
public class MalformedPacketException extends IOException { | ||
|
||
public MalformedPacketException(String message) { | ||
super(message); | ||
} | ||
|
||
} |
Oops, something went wrong.