Blog/utils/MdtInfo.go

168 lines
3.3 KiB
Go
Raw Normal View History

2024-05-22 08:30:01 +00:00
package utils
import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"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
}
func connectServer(host string) (buf InfoBuffer, err error) {
socket, err := net.Dial("udp", host)
if err != nil {
return InfoBuffer{}, err
}
defer socket.Close()
sendData, _ := hex.DecodeString("FE01")
_, err = socket.Write(sendData)
if err != nil {
return InfoBuffer{}, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
workDone := make(chan struct{}, 1)
data := make([]byte, 2048)
go func() {
_, err = socket.Read(data)
workDone <- struct{}{}
}()
select {
case <-workDone:
buf.New(data)
case <-ctx.Done():
return InfoBuffer{}, fmt.Errorf("超时:%v", err)
}
return buf, nil
}
func ping(host string) (int64, error) {
startTime := time.Now()
conn, err := net.DialTimeout("tcp", host, time.Second*2)
if err != nil {
return 0, err
}
conn.Close()
conn.RemoteAddr()
elapsedTime := time.Since(startTime).Milliseconds()
return elapsedTime, nil
}
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)
d, err := ping(add)
if err != nil {
info.Status = "Offline"
return info, err
}
info.Ping = int(d)
buf, err := connectServer(add)
if err != nil {
info.Status = "Offline"
return info, err
}
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
}