package main import ( "bufio" "encoding/binary" "net" "regexp" "strconv" "time" ) type Client struct { ClientID uint32 Name string Address string CompanyID uint8 } func main() { var ( clients map[uint32]*Client paused bool = true forcePaused bool = true ) clients = make(map[uint32]*Client) conn, err := net.Dial("tcp", "poop.siteop.biz:3977") failError(err, "net.Dial") logInfoDebug("Connected to poop.siteop.biz:3977") //send auth p := PacketAdminJoin{ Packet: Packet{PType: AdminPacketAdminJoin}, Password: "plop", AppName: "gottdad", AppVersion: "alpha", } _, err = conn.Write(p.Bytes()) failError(err, "conn.Write") logInfoDebug("Authentication sent (%v)", p.Bytes()) r := bufio.NewReader(conn) b := make([]byte, 0xFFFF) read := 0 n := 0 for { p := Packet{} for { if read >= 3 { //logInfoDebug("Packet read") break } n, err = r.Read(b[read:]) logErrorDebug(err, "r.Read") read += n //logInfoDebug("Waiting for packet, read %d bytes.", read) } p.PLength = binary.LittleEndian.Uint16(b[0:]) p.PType = b[2] if p.PLength <= 3 { logInfoAlert("Wrong packet length") break } //logInfoDebug("Waiting for packet data : len : %d / type : %d", p.PLength, p.PType) for { if read >= int(p.PLength) { //logInfoDebug("Data read") break } n, err = r.Read(b[read:]) logErrorDebug(err, "r.Read") read += n //logInfoDebug("Waiting for data, read %d/%d bytes.", read, p.PLength) } switch p.PType { case AdminPacketServerProtocol: sp := PacketServerProtocol{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerProtocol :\n- ProtocolVersion: %v\n- FurtherData: %v\n- UpdatePacketType: %v\n- FrequenciesAllowed: %b", sp.ProtocolVersion, sp.FurtherData, sp.UpdatePacketType, sp.FrequenciesAllowed) case AdminPacketServerWelcome: sp := PacketServerWelcome{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerWelcome :\n- ServerName: %v\n- OpenTTDVersion: %v\n- Dedicated: %v\n- MapSeed: %x\n- MapLandscape: %v\n- MapStartDate: %v\n- Size: %v x %v", sp.ServerName, sp.OpenTTDVersion, sp.Dedicated, sp.MapSeed, sp.MapLandscape, sp.MapStartDate, sp.MapX, sp.MapY) px := PacketAdminUpdateFrequency{ Packet: Packet{PType: AdminPacketAdminUpdateFrequency}, UpdateType: AdminUpdateDate, UpdateFrequency: AdminFrequencyDaily, } _, err = conn.Write(px.Bytes()) px = PacketAdminUpdateFrequency{ Packet: Packet{PType: AdminPacketAdminUpdateFrequency}, UpdateType: AdminUpdateClientInfo, UpdateFrequency: AdminFrequencyAutomatic, } _, err = conn.Write(px.Bytes()) px = PacketAdminUpdateFrequency{ Packet: Packet{PType: AdminPacketAdminUpdateFrequency}, UpdateType: AdminUpdateChat, UpdateFrequency: AdminFrequencyAutomatic, } _, err = conn.Write(px.Bytes()) px = PacketAdminUpdateFrequency{ Packet: Packet{PType: AdminPacketAdminUpdateFrequency}, UpdateType: AdminUpdateConsole, UpdateFrequency: AdminFrequencyAutomatic, } _, err = conn.Write(px.Bytes()) case AdminPacketServerDate: sp := PacketServerDate{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerDate :\n- Date: %d", sp.Date) paused = false case AdminPacketServerClientJoin: sp := PacketServerClientJoin{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerClientJoin :\n- ClientID: %d", sp.ClientID) case AdminPacketServerClientInfo: sp := PacketServerClientInfo{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerClientInfo :\n- ClientID: %d\n- Address: %s\n- Name: %s\n- Lang: %d\n- Date: %d\n- CompanyID: %d", sp.ClientID, sp.Address, sp.Name, sp.Lang, sp.Date, sp.CompanyID) clt := Client{ ClientID: sp.ClientID, Name: sp.Name, Address: sp.Address, CompanyID: sp.CompanyID, } clients[sp.ClientID] = &clt logInfoDebug("Clients : %v", clients) case AdminPacketServerClientError: sp := PacketServerClientError{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerClientError :\n- ClientID: %d\n- ErrorID: %d", sp.ClientID, sp.ErrorID) case AdminPacketServerClientQuit: sp := PacketServerClientQuit{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerClientQuit :\n- ClientID: %d", sp.ClientID) delete(clients, sp.ClientID) case AdminPacketServerChat: sp := PacketServerChat{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerChat :\n- ActionID: %d\n- DestinationID: %d\n- ClientID: %d\n- Message: %s\n- Amount: %d", sp.ActionID, sp.DestinationID, sp.ClientID, sp.Message, sp.Amount) if sp.Message == "!unpause" { logInfoDebug("AdminPacketServerChat : Unpausing") forcePaused = false } if sp.Message == "!pause" { logInfoDebug("AdminPacketServerChat : Pausing") forcePaused = true } case AdminPacketServerConsole: sp := PacketServerConsole{ Packet: p, } sp.Read(b[:p.PLength]) ok, err := regexp.MatchString("\\[udp\\] queried from .*", sp.Text) logErrorDebug(err, "queried from") if sp.Origin != "net" || ok == false { logInfoDebug("AdminPacketServerConsole :\n- Origin: %q\n- Text: %s", sp.Origin, sp.Text) } case AdminPacketServerRCon: sp := PacketServerRCon{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerRCon :\n- ColorID: %d\n- Output: %s", sp.ColorID, sp.Output) ok, _ := regexp.MatchString("Client #[0-9]+ name: '.*' company: [0-9]+ IP: .*", sp.Output) if ok { clt := Client{} r, _ := regexp.Compile("Client #(?P[0-9]+) name: '(?P.*)' company: (?P[0-9]+) IP: (?P
.*)") ID64, _ := strconv.ParseInt(r.ReplaceAllString(sp.Output, "${ClientID}"), 10, 32) clt.ClientID = uint32(ID64) clt.Name = r.ReplaceAllString(sp.Output, "${ClientID}") ID64, _ = strconv.ParseInt(r.ReplaceAllString(sp.Output, "${CompanyID}"), 10, 8) clt.CompanyID = uint8(ID64) clt.Address = r.ReplaceAllString(sp.Output, "${Address}") clients[clt.ClientID] = &clt } case AdminPacketServerRConEnd: sp := PacketServerRConEnd{ Packet: p, } sp.Read(b[:p.PLength]) logInfoDebug("AdminPacketServerRConEnd :\n- Command: %s", sp.Command) default: logInfoDebug("Packet fully read : len : %d / type : %d", p.PLength, p.PType) } c := make([]byte, 0xFFFF) copy(c, b[p.PLength:]) b = c read -= int(p.PLength) if len(clients) == 0 { px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "clients", } _, err = conn.Write(px.Bytes()) } if !paused && forcePaused { paused = false px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "pause", } _, err = conn.Write(px.Bytes()) logInfoDebug("Pause forced") time.Sleep(1 * time.Second) } if paused && !forcePaused && len(clients) > 1 { // server is client #1 paused = false px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "unpause", } _, err = conn.Write(px.Bytes()) logInfoDebug("Unpause forced") time.Sleep(1 * time.Second) } if !paused && len(clients) == 1 { // server is client #1 paused = true px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "pause", } _, err = conn.Write(px.Bytes()) logInfoDebug("Pausing") time.Sleep(1 * time.Second) } } }