chore: update project structure and enhance plugin functionality
- Added new entries to .gitignore for database files. - Updated go.mod and go.sum to include new indirect dependencies for database and ORM support. - Refactored event handling to improve message reply functionality in the protocol. - Enhanced the dispatcher to allow for better event processing and logging. - Removed outdated plugin documentation and unnecessary files to streamline the codebase. - Improved welcome message formatting and screenshot options for better user experience.
This commit is contained in:
141
internal/plugins/mcstatus/ping.go
Normal file
141
internal/plugins/mcstatus/ping.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package mcstatus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mcnet "github.com/Tnze/go-mc/net"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// ServerStatus 服务器状态信息
|
||||
type ServerStatus struct {
|
||||
Host string
|
||||
Port int
|
||||
Latency int64 // 延迟(毫秒)
|
||||
Version Version
|
||||
Players Players
|
||||
Description string // MOTD
|
||||
Favicon string // Base64 编码的图标
|
||||
}
|
||||
|
||||
// Version 版本信息
|
||||
type Version struct {
|
||||
Name string
|
||||
Protocol int
|
||||
}
|
||||
|
||||
// Players 玩家信息
|
||||
type Players struct {
|
||||
Online int
|
||||
Max int
|
||||
}
|
||||
|
||||
// Ping 查询 Minecraft 服务器状态
|
||||
func Ping(host string, port int, timeout time.Duration) (*ServerStatus, error) {
|
||||
// 连接服务器
|
||||
startTime := time.Now()
|
||||
conn, err := mcnet.DialMC(fmt.Sprintf("%s:%d", host, port))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
latency := time.Since(startTime).Milliseconds()
|
||||
|
||||
// 发送握手包
|
||||
handshake := pk.Marshal(
|
||||
0x00, // Handshake packet ID
|
||||
pk.VarInt(47), // Protocol version (1.8+)
|
||||
pk.String(host),
|
||||
pk.UnsignedShort(port),
|
||||
pk.VarInt(1), // Next state: Status
|
||||
)
|
||||
if err := conn.WritePacket(handshake); err != nil {
|
||||
return nil, fmt.Errorf("failed to send handshake: %w", err)
|
||||
}
|
||||
|
||||
// 发送状态请求
|
||||
request := pk.Marshal(0x00) // Status request packet ID
|
||||
if err := conn.WritePacket(request); err != nil {
|
||||
return nil, fmt.Errorf("failed to send status request: %w", err)
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
var response pk.Packet
|
||||
if err := conn.ReadPacket(&response); err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var statusJSON pk.String
|
||||
if err := response.Scan(&statusJSON); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse response: %w", err)
|
||||
}
|
||||
|
||||
// 解析 JSON 响应
|
||||
var statusData map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(statusJSON), &statusData); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse JSON: %w", err)
|
||||
}
|
||||
|
||||
status := &ServerStatus{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Latency: latency,
|
||||
}
|
||||
|
||||
// 解析 description
|
||||
if desc, ok := statusData["description"].(map[string]interface{}); ok {
|
||||
if text, ok := desc["text"].(string); ok {
|
||||
status.Description = text
|
||||
} else if text, ok := desc["extra"].([]interface{}); ok && len(text) > 0 {
|
||||
// 处理 extra 数组
|
||||
var descText strings.Builder
|
||||
for _, item := range text {
|
||||
if itemMap, ok := item.(map[string]interface{}); ok {
|
||||
if text, ok := itemMap["text"].(string); ok {
|
||||
descText.WriteString(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
status.Description = descText.String()
|
||||
}
|
||||
} else if desc, ok := statusData["description"].(string); ok {
|
||||
status.Description = desc
|
||||
}
|
||||
|
||||
// 解析 version
|
||||
if version, ok := statusData["version"].(map[string]interface{}); ok {
|
||||
if name, ok := version["name"].(string); ok {
|
||||
status.Version.Name = name
|
||||
}
|
||||
if protocol, ok := version["protocol"].(float64); ok {
|
||||
status.Version.Protocol = int(protocol)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 players
|
||||
if players, ok := statusData["players"].(map[string]interface{}); ok {
|
||||
if online, ok := players["online"].(float64); ok {
|
||||
status.Players.Online = int(online)
|
||||
}
|
||||
if max, ok := players["max"].(float64); ok {
|
||||
status.Players.Max = int(max)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 favicon
|
||||
if favicon, ok := statusData["favicon"].(string); ok {
|
||||
// 移除 data:image/png;base64, 前缀
|
||||
if strings.HasPrefix(favicon, "data:image/png;base64,") {
|
||||
status.Favicon = strings.TrimPrefix(favicon, "data:image/png;base64,")
|
||||
} else {
|
||||
status.Favicon = favicon
|
||||
}
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
Reference in New Issue
Block a user