2024-05-22 08:30:01 +00:00
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GamemodeId int
|
|
|
|
|
|
|
|
const (
|
|
|
|
survival GamemodeId = iota
|
|
|
|
sandbox
|
|
|
|
attack
|
|
|
|
pvp
|
|
|
|
editor
|
|
|
|
)
|
|
|
|
|
|
|
|
type Gamemode struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Id GamemodeId `json:"id"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServerInfo struct {
|
|
|
|
Host string `json:"host"`
|
|
|
|
Port int `json:"port"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Maps string `json:"maps"`
|
|
|
|
Players int `json:"players"`
|
|
|
|
Version int `json:"version"`
|
|
|
|
Wave int `json:"wave"`
|
|
|
|
Vertype string `json:"vertype"`
|
|
|
|
Gamemode Gamemode `json:"gamemode"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
Modename string `json:"modename"`
|
|
|
|
Limit int `json:"limit"`
|
|
|
|
Ping int `json:"ping"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type InfoBuffer struct {
|
|
|
|
*bytes.Reader
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g GamemodeId) Name() string {
|
|
|
|
switch g {
|
|
|
|
case survival:
|
|
|
|
return "生存"
|
|
|
|
case sandbox:
|
|
|
|
return "沙盒"
|
|
|
|
case attack:
|
|
|
|
return "进攻"
|
|
|
|
case pvp:
|
|
|
|
return "PVP"
|
|
|
|
case editor:
|
|
|
|
return "编辑"
|
|
|
|
default:
|
|
|
|
return "Error"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *InfoBuffer) New(b []byte) {
|
|
|
|
r.Reader = bytes.NewReader(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *InfoBuffer) readString() string {
|
|
|
|
l, _ := r.ReadByte()
|
|
|
|
buf := make([]byte, l)
|
|
|
|
r.Read(buf)
|
|
|
|
return string(buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *InfoBuffer) getInt() int {
|
|
|
|
var t int32
|
|
|
|
binary.Read(r, binary.BigEndian, &t)
|
|
|
|
return int(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *InfoBuffer) get() byte {
|
|
|
|
b, _ := r.ReadByte()
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-06-03 08:15:23 +00:00
|
|
|
func connectServer(host string) (buf InfoBuffer, ping int64, err error) {
|
2024-05-22 08:30:01 +00:00
|
|
|
socket, err := net.Dial("udp", host)
|
|
|
|
if err != nil {
|
2024-06-03 08:15:23 +00:00
|
|
|
return InfoBuffer{}, -1, err
|
2024-05-22 08:30:01 +00:00
|
|
|
}
|
|
|
|
defer socket.Close()
|
2024-06-03 08:15:23 +00:00
|
|
|
startTime := time.Now()
|
|
|
|
_, err = socket.Write([]byte{0xFE, 0x01})
|
2024-05-22 08:30:01 +00:00
|
|
|
if err != nil {
|
2024-06-03 08:15:23 +00:00
|
|
|
return InfoBuffer{}, -1, err
|
2024-05-22 08:30:01 +00:00
|
|
|
}
|
2024-06-03 08:15:23 +00:00
|
|
|
data := make([]byte, 500)
|
|
|
|
socket.SetReadDeadline(time.Now().Add(2 * time.Second))
|
|
|
|
_, err = socket.Read(data)
|
2024-05-22 08:30:01 +00:00
|
|
|
if err != nil {
|
2024-06-03 08:15:23 +00:00
|
|
|
return InfoBuffer{}, -1, err
|
2024-05-22 08:30:01 +00:00
|
|
|
}
|
2024-06-03 08:15:23 +00:00
|
|
|
ping = time.Since(startTime).Milliseconds()
|
|
|
|
buf.New(data)
|
|
|
|
return buf, ping, nil
|
2024-05-22 08:30:01 +00:00
|
|
|
}
|
|
|
|
func GetServerInfo(host string) (ServerInfo, error) {
|
|
|
|
var info ServerInfo
|
|
|
|
ip := strings.Split(host, ":")
|
|
|
|
if len(ip) == 1 {
|
|
|
|
info.Host = host
|
|
|
|
info.Port = 6567
|
|
|
|
} else {
|
|
|
|
info.Host = ip[0]
|
|
|
|
port, err := strconv.Atoi(ip[1])
|
|
|
|
if err != nil {
|
|
|
|
return info, err
|
|
|
|
}
|
|
|
|
info.Port = port
|
|
|
|
}
|
|
|
|
add := fmt.Sprintf("%s:%d", info.Host, info.Port)
|
2024-06-03 08:15:23 +00:00
|
|
|
buf, ping, err := connectServer(add)
|
2024-05-22 08:30:01 +00:00
|
|
|
if err != nil {
|
|
|
|
info.Status = "Offline"
|
|
|
|
return info, err
|
|
|
|
}
|
2024-06-03 08:15:23 +00:00
|
|
|
info.Ping = int(ping)
|
2024-05-22 08:30:01 +00:00
|
|
|
info.Status = "Online"
|
|
|
|
info.Name = buf.readString()
|
|
|
|
info.Maps = buf.readString()
|
|
|
|
info.Players = buf.getInt()
|
|
|
|
info.Wave = buf.getInt()
|
|
|
|
info.Version = buf.getInt()
|
|
|
|
info.Vertype = buf.readString()
|
|
|
|
info.Gamemode.Id = GamemodeId(buf.get())
|
|
|
|
info.Gamemode.Name = info.Gamemode.Id.Name()
|
|
|
|
info.Limit = buf.getInt()
|
|
|
|
info.Description = buf.readString()
|
|
|
|
info.Modename = buf.readString()
|
|
|
|
return info, nil
|
|
|
|
}
|