Steam游戏服务器信息查询

该代码主要用于查询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主服务器查询
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....

最后修改:2022 年 02 月 15 日 08 : 28 PM