|
|
|
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
|
|
|
|
}
|