查询steam游戏服务器信息API,可查询arma3,dayz等steam游戏

新建类 ServerPlayer.java
封装玩家信息

package com.destiny.kaiheila.destinybot.SteamServerQuery;

public class ServerPlayer {
	
	public int PlayerIndex;
	public String PlayerName;
	public long PlayerScore;
	public float PlayerDuration;
	
	public ServerPlayer(int Index, String Name, long Score, float Duration) {
		this.PlayerIndex = Index;
		this.PlayerName = Name;
		this.PlayerScore = Score;
		this.PlayerDuration = Duration;
	}
	
	public int getIndex() {
		return this.PlayerIndex;
	}
	
	public String getName() {
		return this.PlayerName;
	}
	
	public long getScore() {
		return this.PlayerScore;
	}
	
	public float getDuration() {
		return this.PlayerDuration;
	}
}

新建 SteamServerChallenge.java

steam查询头

package com.destiny.kaiheila.destinybot.SteamServerQuery;

public class SteamServerChallenge {
	
	public static int HEADER = (byte)0x41;
	
}

新建 SteamServerEnvironment.java

专用服务器操作系统标识

package com.destiny.kaiheila.destinybot.SteamServerQuery;

public class SteamServerEnvironment {
	public static int LINUX = 108;
	public static int WINDOWS = 119;
	public static int MAC = 109;
}

新建 SteamServerInfo.java

服务器信息

package com.destiny.kaiheila.destinybot.SteamServerQuery;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class SteamServerInfo {
	private int position = 0;
	
	public static byte HEADER = (byte)0x49;
	private int ServerProtocol;
	private byte[] ServerName;
	private	byte[] ServerMap;
	private byte[] ServerFolder;
	private byte[] ServerGame;
	private short ServerAppID;
	private int ServerPlayers;
	private int ServerMaxPlayers;
	private int ServerBots;
	private int ServerType;
	private int ServerEnvironment;
	private int ServerVisibility;
	private int ServerVAC;
	private byte[] ServerVersion;
	private int ServerEDF;
	
	public SteamServerInfo(byte[] Buffer) {
		this.ServerProtocol = Buffer[0];
		
		this.position++;
		int ServerNameLength = this.getStringLenght(this.position, Buffer);
		this.ServerName = new byte[ServerNameLength];
		System.arraycopy(Buffer, this.position, this.ServerName, 0, ServerNameLength);
		
		this.position = this.position + ServerNameLength + 1;
		int ServerMapLength = this.getStringLenght(this.position, Buffer);
		this.ServerMap = new byte[ServerMapLength];
		System.arraycopy(Buffer, this.position, this.ServerMap, 0, ServerMapLength);
		
		this.position = this.position + ServerMapLength + 1;
		int ServerFolderLength = this.getStringLenght(this.position, Buffer);
		this.ServerFolder = new byte[ServerFolderLength];
		System.arraycopy(Buffer, this.position, this.ServerFolder, 0, ServerFolderLength);
		
		this.position = this.position + ServerFolderLength + 1;
		int ServerGameLength = this.getStringLenght(this.position, Buffer);
		this.ServerGame = new byte[ServerGameLength];
		System.arraycopy(Buffer, this.position, this.ServerGame, 0, ServerGameLength);
		
		this.position = this.position + ServerGameLength + 1;
		this.ServerAppID = ByteBuffer.wrap(Buffer, this.position, this.position + 1).order(ByteOrder.LITTLE_ENDIAN).getShort();
		
		this.position = this.position + 2;
		this.ServerPlayers = Buffer[this.position];
		
		this.position++;
		this.ServerMaxPlayers = Buffer[this.position];
		
		this.position++;
		this.ServerBots = Buffer[this.position];
		
		this.position++;
		this.ServerType = Buffer[this.position];
		
		this.position++;
		this.ServerEnvironment = Buffer[this.position];
		
		this.position++;
		this.ServerVisibility = Buffer[this.position];
		
		this.position++;
		this.ServerVAC = Buffer[this.position];
		
		this.position++;
		int ServerVersionLength = getStringLenght(this.position, Buffer);
		this.ServerVersion = new byte[ServerVersionLength];
		System.arraycopy(Buffer, this.position, this.ServerVersion, 0, ServerVersionLength);
		
		this.position = this.position + ServerVersionLength + 1;
		this.ServerEDF = Buffer[this.position];
	}
	
	public int getProtocol() {
		return this.ServerProtocol;
	}
	
	public String getName() {
		return new String(this.ServerName);
	}
	
	public String getMap() {
		return new String(this.ServerMap);
	}
	
	public String getFolder() {
		return new String(this.ServerFolder);
	}
	
	public String getGame() {
		return new String(this.ServerGame);
	}
	
	public short getAppID() {
		return this.ServerAppID;
	}
	
	public int getPlayers() {
		return this.ServerPlayers;
	}
	
	public int getMaxPlayers() {
		return this.ServerMaxPlayers;
	}
	
	public int getBots() {
		return this.ServerBots;
	}
	
	public int getType() {
		return this.ServerType;
	}
	
	public int getEnvironment() {
		return this.ServerEnvironment;
	}
	
	public int getVisibility() {
		return this.ServerVisibility;
	}
	
	public int getVAC() {
		return this.ServerVAC;
	}
	
	public String getVersion() {
		return new String(this.ServerVersion);
	}
	
	public int getEDF() {
		return this.ServerEDF;
	}
	
	private int getStringLenght(int start, byte[] buffer) {
		for (int i = start; i < buffer.length; i++) {
			if (buffer[i] == 0) {
				return i - start;
			}
		}
		
		return 0;
	}
	
	@Override
	public String toString() {
		return "Protocol : " + this.getProtocol() + "\nName : " + this.getName() + "\nMap : " + this.getMap() + "\nFolder : " + this.getFolder() + "\nGame : " + this.getGame() + "\nAppID : " + this.getAppID() + "\nPlayers : " + this.getPlayers() + "\nMax Players : " + this.getMaxPlayers() + "\nBots : " + this.getBots() + "\nServer Type : " + (char)this.getType() + " (d = DEDICATED|l = NON-DEDICATED|p = SourceTV/proxy)\nEnvironment : " + (char)this.getEnvironment() + " (l = Linux|w = Windows|m = MAC)\nVisibility : " + this.getVisibility() + " (0 = Public|1 = Private)\nVAC : " + this.getVAC() + " (0 = UNSECURED|1 = SECURED)\nVersion : " + this.getVersion() + "\nExtra Data Flag (EDF) : " + this.getEDF();
	}
}

新建 SteamServerPlayer.java

服务器玩家信息

package com.destiny.kaiheila.destinybot.SteamServerQuery;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SteamServerPlayer {
	private int position = 0;
	
	public static byte HEADER = (byte)0x44;
	
	public int PlayersLength;
	public ServerPlayer[] Players;
	
	public SteamServerPlayer(byte[] Buffer) {		
		this.PlayersLength = Buffer[this.position];		
		this.Players = new ServerPlayer[this.getPlayersLength()];
		
		this.position++;
		for (int i = 0; i < this.getPlayersLength(); i++) {			
			int PlayerIndex = Buffer[this.position];
			
			this.position++;
			int PlayerNameLength = getStringLenght(this.position, Buffer);
			byte[] PlayerName = new byte[PlayerNameLength];
			System.arraycopy(Buffer, this.position, PlayerName, 0, PlayerNameLength);
			
			
			this.position = this.position + PlayerNameLength + 1;
			long PlayerScore = ((Buffer[this.position + 3] & 0xFFL) << 24) | ((Buffer[this.position + 2] & 0xFFL) << 16) | ((Buffer[this.position + 1] & 0xFFL) <<  8) | ((Buffer[this.position + 0] & 0xFFL) <<  0);
			
			this.position = this.position + 4;
			float PlayerDuration = ByteBuffer.wrap(new byte[] {Buffer[this.position], Buffer[this.position+1], Buffer[this.position+2], Buffer[this.position+3]}).order(ByteOrder.LITTLE_ENDIAN).getFloat();
			
			this.position = this.position + 4;
			
			this.Players[i] = new ServerPlayer(PlayerIndex, new String(PlayerName), PlayerScore, PlayerDuration);
		}
	}
	
	public int getPlayersLength() {
		return this.PlayersLength;
	}
	
	public ServerPlayer[] getPlayers() {
		return this.Players;
	}
	
	private int getStringLenght(int start, byte[] buffer) {
		for (int i = start; i < buffer.length; i++) {
			if (buffer[i] == 0)
				return i - start;
		}
		
		return 0;
	}

	public List<Map<String,Object>> playerList (){
		List<Map<String,Object>> listMap = new ArrayList<>();
		for (ServerPlayer Player : this.getPlayers()) {
			Map<String,Object> map = new HashMap<>();
			map.put("playerName",Player.getName() );
			map.put("Score",  Long.parseLong(String.valueOf(Player.getScore())));
			map.put("Duration",Math.round(Player.getDuration() / 3600) + ":" + Math.round((Player.getDuration() % 3600) / 60) + ":" + Math.round((Player.getDuration() % 3600) % 60));
			listMap.add(map);
		}
		return listMap;
	}

	public String toString() {
		String PlayerTable = "";
		
		for (ServerPlayer Player : this.getPlayers()) {			
			PlayerTable += Player.getName() + ((Player.getName().length() <= 7) ? "\t\t\t\t" : ((Player.getName().length() <= 15) ? "\t\t\t" : ((Player.getName().length() <= 23) ? "\t\t" : "\t")));
			PlayerTable += new Long(Player.getScore()).intValue() + "\t\t";
			PlayerTable += Math.round(Player.getDuration() / 3600) + ":" + Math.round((Player.getDuration() % 3600) / 60) + ":" + Math.round((Player.getDuration() % 3600) % 60) + "\n";
		}
		
		return "Players : " + this.getPlayersLength() + "\nPlayer Name :\t\t\tScore :\t\tDuration:\n" + PlayerTable;
	}
}

新建SteamServerQuery.java

steam主服务器查询

package com.destiny.kaiheila.destinybot.SteamServerQuery;

import java.net.*;

public class SteamServerQuery {

	private InetAddress ServerAddress;
	private int ServerPort;
	private DatagramSocket UDPClient;

	public SteamServerQuery(InetAddress Address, int Port) {
		try {
			this.UDPClient = new DatagramSocket();
			this.ServerAddress = Address;
			this.ServerPort = Port;
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}

	public SteamServerQuery(String Address, int Port) throws UnknownHostException {
		this(InetAddress.getByName(Address), Port);
	}

	public SteamServerQuery(String Address) throws UnknownHostException {
		this(Address.split(":")[0], Integer.parseInt(Address.split(":")[1]));
	}

	public DatagramSocket getDatagramSocket() {
		return UDPClient;
	}

	public SteamServerInfo getInfo() throws Exception {
		byte[] InfoHeader = new byte[25];
		InfoHeader[0] = (byte)0xFF;
		InfoHeader[1] = (byte)0xFF;
		InfoHeader[2] = (byte)0xFF;
		InfoHeader[3] = (byte)0xFF;
		InfoHeader[4] = (byte)0x54;
		byte[] SourceString = new String("Source Engine Query").getBytes();
		System.arraycopy(SourceString, 0, InfoHeader, 5, SourceString.length);
		InfoHeader[5 + SourceString.length] = (byte) 0x00;
		DatagramPacket SendInfoPacket = new DatagramPacket(InfoHeader, InfoHeader.length, this.ServerAddress, this.ServerPort);
		this.UDPClient.setSoTimeout(3000);
		this.UDPClient.send(SendInfoPacket);
		byte[] ReceivedBuffer = new byte[512];
		DatagramPacket ReceivedInfoPacket = new DatagramPacket(ReceivedBuffer, ReceivedBuffer.length);
		UDPClient.setSoTimeout(3000);
		this.UDPClient.receive(ReceivedInfoPacket);
		if (ReceivedBuffer[0] == (byte)0xFF && ReceivedBuffer[1] == (byte)0xFF && ReceivedBuffer[2] == (byte)0xFF && ReceivedBuffer[3] == (byte)0xFF && ReceivedBuffer[4] == SteamServerInfo.HEADER) {
			byte[] ServerInfoBuffer = new byte[ReceivedBuffer.length - 5];
			System.arraycopy(ReceivedBuffer, 5, ServerInfoBuffer, 0, ServerInfoBuffer.length);
			return new SteamServerInfo(ServerInfoBuffer);
		}
		return null;
	}

	public SteamServerPlayer getPlayer() throws Exception{
		byte[] PlayerHeader = this.getChallenge();
		PlayerHeader[4] = (byte)0x55;
		DatagramPacket SendPlayerPacket = new DatagramPacket(PlayerHeader, PlayerHeader.length, this.ServerAddress, this.ServerPort);
		this.UDPClient.send(SendPlayerPacket);
		byte[] ReceivedPlayerBuffer = new byte[1024];
		DatagramPacket ReceivedPlayerPacket = new DatagramPacket(ReceivedPlayerBuffer, ReceivedPlayerBuffer.length);
		this.UDPClient.setSoTimeout(3000);
		this.UDPClient.receive(ReceivedPlayerPacket);
		if (ReceivedPlayerBuffer[0] == (byte)0xFF && ReceivedPlayerBuffer[1] == (byte)0xFF && ReceivedPlayerBuffer[2] == (byte)0xFF && ReceivedPlayerBuffer[3] == (byte)0xFF && ReceivedPlayerBuffer[4] == SteamServerPlayer.HEADER) {
			byte[] ServerPlayerBuffer = new byte[ReceivedPlayerBuffer.length - 5];
			System.arraycopy(ReceivedPlayerBuffer, 5, ServerPlayerBuffer, 0, ServerPlayerBuffer.length);
			return new SteamServerPlayer(ServerPlayerBuffer);
		} else {
			System.err.println("ERROR Player Packet !");
			return null;
		}
	}

	public byte[] getChallenge() throws Exception {
		byte[] ChallengeHeader = new byte[9];
		ChallengeHeader[0] = (byte)0xFF;
		ChallengeHeader[1] = (byte)0xFF;
		ChallengeHeader[2] = (byte)0xFF;
		ChallengeHeader[3] = (byte)0xFF;
		ChallengeHeader[4] = (byte)0x55;
		ChallengeHeader[5] = (byte)0xFF;
		ChallengeHeader[6] = (byte)0xFF;
		ChallengeHeader[7] = (byte)0xFF;
		ChallengeHeader[8] = (byte)0xFF;

		DatagramPacket SendChallengePacket = new DatagramPacket(ChallengeHeader, ChallengeHeader.length, this.ServerAddress, this.ServerPort);
		this.UDPClient.send(SendChallengePacket);

		byte[] ReceivedChallengeBuffer = new byte[9];
		DatagramPacket ReceivedChallengePacket = new DatagramPacket(ReceivedChallengeBuffer, ReceivedChallengeBuffer.length);
		this.UDPClient.setSoTimeout(3000);
		this.UDPClient.receive(ReceivedChallengePacket);

		if(ReceivedChallengeBuffer[0] == (byte)0xFF && ReceivedChallengeBuffer[1] == (byte)0xFF && ReceivedChallengeBuffer[2] == (byte)0xFF && ReceivedChallengeBuffer[3] == (byte)0xFF && ReceivedChallengeBuffer[4] == SteamServerChallenge.HEADER) {
			return ReceivedChallengeBuffer;
		} else {
			System.err.println("ERROR Challenge Packet !");
			return new byte[9];
		}
	}
}

使用方法:

//参数 IP:查询端口
SteamServerQuery ServerQuery = new SteamServerQuery("0.0.0.0:2303");
//从服务器获取服务器信息
 SteamServerInfo ServerInfo = ServerQuery.getInfo();
//从服务器获取玩家信息
 SteamServerPlayer player = ServerQuery.getPlayer();

ServerInfo.....
player....

文件:文件下载