package main import ( "bufio" "encoding/binary" "net" "regexp" ) func main() { var ( clients int = -1 paused bool = true forcePaused bool = true ) 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) clients++ 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) 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) if clients > 0 { clients-- } 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- Colour: %d\n- Output: %s", sp.Colour, sp.Output) 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 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()) } if paused && !forcePaused && clients > 0 { paused = false px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "unpause", } _, err = conn.Write(px.Bytes()) } if !paused && clients == 0 { paused = true px := PacketAdminRCon{ Packet: Packet{PType: AdminPacketAdminRCon}, Command: "pause", } _, err = conn.Write(px.Bytes()) } } }