A modification-free API for Minecraft utilizing log parsing
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.
 
 
 
 

110 lines
3.3 KiB

package main
import (
"github.com/acarl005/stripansi"
"github.com/hpcloud/tail"
"log"
"meow.tf/residentsleeper/events"
"meow.tf/residentsleeper/rcon"
"os"
"regexp"
"strings"
)
const (
timeThreadRegexp = "^\\[.*?\\]\\s\\[.*?\\/INFO\\]:\\s"
)
var (
messageRegexp = regexp.MustCompile(timeThreadRegexp + "<(.*?)>\\s(.*)")
joinedRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?) joined the game$")
leftRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?) left the game$")
stoppingRegexp = regexp.MustCompile(timeThreadRegexp + "Stopping server")
rconRegexp = regexp.MustCompile(timeThreadRegexp + "RCON running on")
loggedInRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?)\\[(.*?)\\] logged in with entity id \\d+ at \\((.*?)\\)")
startedRegexp = regexp.MustCompile(timeThreadRegexp + "Done \\(.*?\\)! For help, type \"help\"")
authenticatedRegexp = regexp.MustCompile(timeThreadRegexp + "UUID of player (.*?) is (.*?)$")
opRegexp = regexp.MustCompile("Made (.*?) a server operator")
deopRegexp = regexp.MustCompile("Made (.*?) no longer a server operator")
sourceRegexp = regexp.MustCompile(timeThreadRegexp + "\\[(.*?): (.*?)\\]")
sleepRegexp = regexp.MustCompile("^z{3,}$")
timeRegexp = regexp.MustCompile("(\\d+)$")
)
func logParser(logPath string) {
log.Println("Watching log path", logPath)
stat, err := os.Stat(logPath)
if err != nil {
log.Fatalln("Unable to open log file:", err)
}
seek := &tail.SeekInfo{
Offset: stat.Size(),
}
// Start parsing file
t, err := tail.TailFile(logPath, tail.Config{Location: seek, Follow: true, ReOpen: true})
if err != nil {
log.Fatalln("Unable to open file:", err)
}
var m []string
for line := range t.Lines {
line.Text = stripansi.Strip(strings.TrimSpace(line.Text))
if debug {
log.Println("Parsing line", line.Text)
log.Println("Bytes:", []byte(line.Text))
}
if m = messageRegexp.FindStringSubmatch(line.Text); m != nil {
events.Call(events.Message, m[1], m[2])
} else if m = loggedInRegexp.FindStringSubmatch(line.Text); m != nil {
position, err := rcon.SliceToFloats(strings.Split(m[3], ", "))
if err != nil {
position = []float64{0, 0, 0}
}
events.Call(events.LoggedIn, m[1], m[2], position[0], position[1], position[2])
} else if m = authenticatedRegexp.FindStringSubmatch(line.Text); m != nil {
events.Call(events.Authenticated, m[1], m[2])
} else if m = joinedRegexp.FindStringSubmatch(line.Text); m != nil {
events.Call(events.Join, m[1])
} else if m = leftRegexp.FindStringSubmatch(line.Text); m != nil {
events.Call(events.Leave, m[1])
} else if m = opRegexp.FindStringSubmatch(line.Text); m != nil {
source := "Server"
subM := sourceRegexp.FindStringSubmatch(line.Text)
if subM != nil {
source = subM[1]
}
events.Call(events.Op, m[1], source)
} else if m = deopRegexp.FindStringSubmatch(line.Text); m != nil {
source := "Server"
subM := sourceRegexp.FindStringSubmatch(line.Text)
if subM != nil {
source = subM[1]
}
events.Call(events.Deop, m[1], source)
} else if stoppingRegexp.MatchString(line.Text) {
events.Call(events.ServerClosing)
client.Disconnect()
} else if startedRegexp.MatchString(line.Text) {
events.Call(events.ServerStarted)
} else if rconRegexp.MatchString(line.Text) {
events.Call(events.Init)
}
}
}