You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
5.3 KiB

package main
import (
"bufio"
"fmt"
"io"
"os/exec"
"regexp"
"strings"
"time"
)
var (
mcOut io.Reader
mcIn io.Writer
mcStop = false
mcLoaded = false
mcRebooting = false
mcWBRunning = false
)
func (u User) McWhitelist() {
mcCommand(fmt.Sprintf("whitelist add %+v", u.McUser))
mcCommand(fmt.Sprintf("nicknames %+v %+v", u.McUser, u.Email))
}
func configureMinecraft() {
log.LogInfo("Starting MinecraftServer")
server := exec.Command("screen", "-r", "1234")
mcIn, _ = server.StdinPipe()
mcOut, _ = server.StdoutPipe()
mcErr, _ := server.StderrPipe()
mcErrScan := bufio.NewScanner(mcErr)
server.Start()
defer server.Wait()
go listenOut()
for mcErrScan.Scan() {
if mcStop {
break
}
log.LogError(mcErrScan.Text())
}
}
func handleMcOnline(s string) {
log.LogDebug("A user has come online or gone offline.")
s = strings.Replace(s, "&e", "", -1)
var u User
parts := strings.Split(s, " ")
log.LogDebug(fmt.Sprintf("%+v", parts))
if parts[2] == "UUID" {
log.LogDebug(fmt.Sprintf("User %+v detected.", parts[5]))
if serverRebooting {
mcCommand(fmt.Sprintf("kick %+v Server reboot pending.", parts[5]))
}
//mcCommand(fmt.Sprintf("kick %+v Server currently unavailable.", parts[5]))
u.McUser = parts[5]
u.Retrieve()
if u.Email == "" {
u.Email = u.McUser
u.McUser = ""
u.Retrieve()
if u.McUser == "" {
sendAdminDiscordMessage(fmt.Sprintf("Unable to verify %+v", parts[5]))
mcCommand(fmt.Sprintf("kick %+v Verified SITNET not found. Admins have been notified.", parts[5]))
return
}
} else if u.Email != parts[5] {
mcCommand(fmt.Sprintf("lp user %+v parent add player", u.McUser))
mcCommand(fmt.Sprintf("nicknames %+v %+v", u.McUser, u.Email))
}
for _, v := range onlineUsers {
if v.Email == u.Email {
return
}
}
onlineUsers = append(onlineUsers, u)
} else {
log.LogDebug(fmt.Sprintf("User %+v detected.", parts[2]))
u.McUser = parts[2]
u.Retrieve()
for k, v := range onlineUsers {
log.LogDebug(fmt.Sprintf("v.McUser: %+v, parts[2]: %+v", v.McUser, parts[2]))
if v.McUser == parts[2] || v.Email == parts[2] {
onlineUsers[k] = onlineUsers[len(onlineUsers)-1] // Copy last element to index i.
onlineUsers = onlineUsers[:len(onlineUsers)-1] // Truncate slice.
}
}
}
u.Write()
log.LogDebug(fmt.Sprintf("Online users: %+v", onlineUsers))
if len(onlineUsers) == 0 && !config.WbFinished {
log.LogInfo("The last user has logged out.")
mcWorldBuilderToggle(true)
} else {
mcWorldBuilderToggle(false)
}
}
func listenOut() {
outScan := bufio.NewScanner(mcOut)
var re = regexp.MustCompile(`INFO\]: <(.*?)> (.*)`)
for outScan.Scan() {
if mcStop {
break
}
output := outScan.Text()
go log.LogInfo(fmt.Sprintf("server.jar: %+v", output))
if !mcLoaded {
if strings.Contains(output, "For help, type \"help\"") {
mcLoaded = true
sendDiscordMessage("Minecraft server is now available.")
mcWorldBuilderToggle(true)
}
continue
}
if strings.Contains(output, "UUID of player") || strings.Contains(output, "left the game") {
go handleMcOnline(output)
}
match := re.FindStringSubmatch(output)
if match != nil {
if match[1] != "Server" {
var u User
u.McUser = match[1]
u.Retrieve()
if u.Email == "" {
u.McUser = ""
u.Email = match[1]
u.Retrieve()
u.Write()
} else if u.Email != match[1] {
mcCommand(fmt.Sprintf("nicknames %+v %+v", u.McUser, u.Email))
}
log.LogDebug(fmt.Sprintf("Minecraft message from retrieved user %+v", u))
go sendDiscordMessage(fmt.Sprintf("[%s]: %s", u.Email, match[2]))
continue
}
} else if mcLoaded && !strings.Contains(output, " INFO]: [Server] [") && !strings.Contains(output, "[WorldBorder]") {
go sendAdminDiscordMessage(output)
}
}
}
func mcWorldBuilderToggle(b bool) {
log.LogDebug("World builder toggled")
if b && !mcWBRunning {
log.LogDebug("Building world!")
mcCommand("wb world fill 500 300 false")
mcCommand("wb fill confirm")
mcWBRunning = true
return
} else if mcWBRunning {
log.LogDebug("Not building world!")
mcCommand("wb fill cancel")
mcWBRunning = false
}
}
func mcSay(message string) {
mcCommand(fmt.Sprintf("say %+v", mcMention(message)))
}
func mcMention(s string) string {
var ret string
if !strings.Contains(s, "@") {
return s
}
parts := strings.Split(s, " ")
for _, part := range parts {
if strings.HasPrefix(part, "<@!") {
var u User
u.DiscordID = strings.Replace(strings.Replace(part, "<@!", "", -1), ">", "", -1)
u.Retrieve()
ret += "@"
ret += u.Email
} else {
ret += part
}
ret += " "
log.LogDebug(ret)
}
return ret
}
func mcCommand(message string) {
mcIn.Write([]byte(message))
mcIn.Write([]byte("\n"))
}
func mcReboot(when int, reminders int) {
if mcRebooting {
return
}
mcRebooting = true
untilReboot := time.Duration(when) * time.Minute
rebootTime := time.Now().Add(untilReboot)
var untilReminder time.Duration
if reminders != 0 {
untilReminder = time.Duration(when / reminders)
}
for {
mcSay(fmt.Sprintf("A reboot has been scheduled for %+v", untilReboot))
if reminders > 0 {
reminders--
time.Sleep(untilReminder)
continue
}
time.Sleep(time.Until(rebootTime))
mcExit()
discordExit()
}
}
func mcExit() {
log.LogCritical("Closing Minecraft (issuing command `stop`)")
mcCommand("stop")
mcStop = true
mcLoaded = false
}