waahhhh/minecraft-query

在PHP中使用Minecraft查询

dev-master 2019-01-19 02:00 UTC

This package is not auto-updated.

Last update: 2020-10-09 22:54:16 UTC


README

构建和测试状态: pipeline status

支持的PHP版本

  • 7.1
  • 7.2
  • 7.3

简介

此存储库包含项目 https://github.com/winny-/mcstat 的内容!"mcstat" 的许可证可在 https://github.com/winny-/mcstat/blob/master/LICENSE 找到。

:warning: PHP (up to 7.3) is currently unable to deal with unsigned integer - negative integer can't convert to VarInt and vice versa.
请参阅单元测试的解决方案

This means that no full-support of the data-type VarInt is possible.
The good news: currently all information returned from the minecraft server are not negative. :tada

This project was developed on PHP 7.2.5. The client is written in OOP and should keep the usage simple.

示例用法

<?php
$query = new \MinecraftQuery\ServerListPing('0.0.0.0', 25565);
$response = $query->getStatus();
var_dump($response);

输出

class MinecraftQuery\ServerListPingResponseStatus#2 (7) {
  private $motd =>
  string(19) "My Minecraft-Server"
  private $playersMax =>
  int(10)
  private $playersOnline =>
  int(2)
  private $serverVersion =>
  string(6) "1.13.2"
  private $protocolVersion =>
  int(404)
  private $handshakeDuration =>
  double(0.13642597198486)
  private $statusDuration =>
  double(2.8133392333984E-5)
}
  • \MinecraftQuery\ServerListPingResponseStatus 的获取器可提供所有可用信息。

Minecraft UDP查询使用UT3查询协议

来源: http://wiki.vg/Query

端口:查询端口(在server.properties中配置)

请求和响应包格式

来源: http://wiki.vg/Query#Base_packet_format

请求包格式

魔法 2x 字节:FE FD (0xFE, 0xFD)
类型字节:9 (握手),0 (状态)
会话 ID int32:(应该是随机的)
有效载荷(变化):握手有效载荷或状态有效载荷

响应包格式

类型字节:9 (握手),0 (状态)
会话 ID int32:(应该是随机的)
有效载荷(变化):握手有效载荷或状态有效载荷

握手

请求

魔法 2x 字节:FE FD
类型字节:09
会话 ID int32:00 00 00 01
有效载荷:(空)

转储
FE FD 09 00 00 00 01

响应

类型字节:09
会话 ID int32:00 00 00 01
挑战令牌字符串(以空字符终止):"9513307\0"

将令牌字符串转换为 int32
00 91 29 5B

转储
09 00 00 00 01 39 35 31 33 33 30 37 00 | .....9513307.

注意:所有令牌每30秒过期。
需要记住,令牌可能会过期。

基本统计信息

请求

魔法 2x 字节:FE FD
类型字节:00
会话 ID int32:00 00 00 01
挑战令牌 int32:00 91 29 5B

转储
FE FD 00 00 00 00 01 00 91 29 5B

响应

类型字节:00
会话 ID int32:00 00 00 01
MOTD 字符串(以空字符终止):"A Minecraft Server\0"
gametype 字符串(以空字符终止):"SMP\0"
map 字符串(以空字符终止):"world\0"
numplayers 字符串(以空字符终止):"2\0"
maxplayers 字符串(以空字符终止):"20\0"
hostport short (小端):DD 63 (25565)
hostip 字符串(以空字符终止):"127.0.0.1\0"
挑战令牌字符串(以空字符终止字符串):"9513307\0"

转储
00 00 00 00 01 41 20 4D 69 6E 65 63 72 61 66 74 | .....A Minecraft
20 53 65 72 76 65 72 00 53 4D 50 00 77 6F 72 6C | Server.SMP.worl
64 00 32 00 32 30 00 DD 63 31 32 37 2E 30 2E 30 | d.2.20.##127.0.0
2E 31 00 | .1.

完整统计信息

每5秒缓存一次。

请求

魔法 2x 字节:FE FD
类型字节:00
会话 ID int32:00 00 00 01
挑战令牌 int32:00 91 29 5B
填充(挑战令牌最多8字节):00 00 00 00

转储
FE FD 00 00 00 00 01 00 91 29 5B 00 00 00 00

响应

类型字节:00
会话 ID int32:00 00 00 01
填充 11x 字节(无意义):73 70 6C 69 74 6E 75 6D 00 80 00
字符串的 K,V 分节对(每个以 null-终止): "hostname\0A Minecraft Server\0gametype\0SMP\0..."
填充 10x 字节(无意义):01 70 6C 61 79 65 72 5F 00 00
玩家节字符串(每个以 null-终止 + 双空字符终止在末尾): "Player1\0Player2\0...Player5\0\0"

转储
00 00 00 00 01 73 70 6C 69 74 6E 75 6D 00 80 00 | .....splitnum...
68 6F 73 74 6E 61 6D 65 00 41 20 4D 69 6E 65 63 72 61 66 74 00 53 4D 50 00 67 61 6D 65 5F 69 64 00 4D 49 4E 45 43 52 41 46 54 00 76 65 72 73 69 6F 6E 00 42 65 74 61 20 31 2E 39 20 50 72 65 6C 65 61 73 65 20 34 00 70 6C 75 67 69 6E 73 00 00 6D 61 70 00 77 6F 72 6C 64 00 6E 75 6D 70 6C 61 79 65 72 73 00 32 00 6D 61 78 70 6C 61 79 65 72 73 00 32 30 00 68 6F 73 74 70 6F 72 74 00 32 35 35 36 35 00 68 6F 73 74 69 70 00 31 32 37 2E 30 2E 30 2E 31 00 00 01 70 6C 61 79 65 72 5F 00 62 61 72 6E 65 79 67 61 6C 65 00 00 | hostname.A Minecraft craft | type.SMP.game_id.MINECRAFT.version.Beta 1.9 Pre-release 4.plugins..map.world.numplayers.2.maxplayers.20.hostport.25565.hostip.127.0.0.1...player_barn
72 61 66 74 20 53 65 72 76 65 72 00 67 61 6D 65 | raft Server.game
74 79 70 65 00 53 4D 50 00 67 61 6D 65 5F 69 64 00 4D 49 4E 45 43 52 41 46 54 00 76 65 72 73 69 6F 6E 00 42 65 74 61 20 31 2E 39 20 50 72 65 6C 65 61 73 65 20 34 00 70 6C 75 67 69 6E 73 00 00 6D 61 70 00 77 6F 72 6C 64 00 6E 75 6D 70 6C 61 79 65 72 73 00 32 00 6D 61 78 70 6C 61 79 65 72 73 00 32 30 00 68 6F 73 74 70 6F 72 74 00 32 35 35 36 35 00 68 6F 73 74 69 70 00 31 32 37 2E 30 2E 30 2E 31 00 00 01 70 6C 61 79 65 72 5F 00 62 61 72 6E 65 79 67 61 6C 65 00 00 | type.SMP.game_id.MINECRAFT.version.Beta 1.9 Pre-release 4.plugins..map.world.numplayers.2.maxplayers.20.hostport.25565.hostip.127.0.0.1...player_barne
00 00 62 61 72 6E 65 79 67 61 6C 65 00 56 69 76 61 6C 61 68 65 6C 76 69 67 00 00 | ..barneygale.Vivalahelvig..
00 00 62 61 72 6E 65 79 67 61 6C 65 00 56 69 76 61 6C 61 68 65 6C 76 69 67 00 00 | ..barneygale.Vivalahelvig..

hostname (MOTD for the current server): "A Minecraft Server"
gametype (hardcoded to SMP): "SMP"
game_id (hardcoded to MINECRAFT): "MINECRAFT"
version (Server version): "1.2.5"
plugins
Plugin 列表,未被原版服务器使用,其中为空字符串(但仍然以 null 结尾,见上面的十六进制转储)。
这是 dinnerbone 提出的格式,目前由 bukkit 使用。
[SERVER_MOD_NAME[: PLUGIN_NAME(; PLUGIN_NAME...)]]
'CraftBukkit on Bukkit 1.2.5-R4.0: WorldEdit 5.3; CommandBook 2.1'
map (当前地图名称): "world"
numplayers (在线玩家数量): "1"
maxplayers (服务器上最大玩家数量): "20"
hostport: "25565"
hostip: "127.0.0.1"

Minecraft TCP 查询使用服务器列表 Ping

来源:http://wiki.vg/Protocol#Server_List_Ping_.280xFE.29

握手字节:9
统计字节:0
端口:主端口

握手

请求

数据包 ID:0x00
协议版本:VarInt(340 为 1.12.2)
服务器地址:String 255(172.0.0.1 或主机)
服务器端口:无符号短整型 1-65535
下一个状态:VarInt 枚举(1:状态,2:登录)

响应

无响应

获取下一个状态

请求

数据包 ID:0x00
无字段

响应

数据包 ID:0x00
JSON 响应:字符串(UTF-8)最大 32767

注意:Notchian 服务器将等待接收以下 Ping 数据包 30 秒,
超时并发送响应。

VarInt

http://wiki.vg/Data_types#VarInt_and_VarLong

感谢 https://github.com/fmoo/python-varint

开发

运行 Docker 容器

docker-compose up

连接到 Docker 容器

docker-compose exec minecraft-query bash

安装开发依赖项

composer install

执行单元测试

composer test-unit