Move to event loop, prettify warps, add delay to warp with damage counter
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
c037c66fc6
commit
f9512b2485
|
@ -1,2 +1,12 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
/usr/bin/sleeper -dir ${SERVER_PATH:-/data}
|
if [ -z "$SERVER_PATH" ]; then
|
||||||
|
SERVER_PATH="/data"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_PATH="$SERVER_PATH/scripts"
|
||||||
|
|
||||||
|
if [ -d "/scripts" ]; then
|
||||||
|
SCRIPT_PATH="/scripts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/bin/sleeper -dir $SERVER_PATH -scriptPath $SCRIPT_PATH
|
|
@ -6,24 +6,24 @@ const (
|
||||||
ServerStarted = "server_started"
|
ServerStarted = "server_started"
|
||||||
ServerClosing = "server_closing"
|
ServerClosing = "server_closing"
|
||||||
|
|
||||||
// LoggedIn, Args: User, Address, X, Y, Z
|
// LoggedIn Args: User, Address, X, Y, Z
|
||||||
LoggedIn = "logged_in"
|
LoggedIn = "logged_in"
|
||||||
|
|
||||||
// Authenticated, Args: User, UUID
|
// Authenticated Args: User, UUID
|
||||||
Authenticated = "authenticated"
|
Authenticated = "authenticated"
|
||||||
|
|
||||||
// Join, Args: User
|
// Join Args: User
|
||||||
Join = "join"
|
Join = "join"
|
||||||
|
|
||||||
// Leave, Args: User
|
// Leave Args: User
|
||||||
Leave = "leave"
|
Leave = "leave"
|
||||||
|
|
||||||
// Op, Args: User, Source?
|
// Op Args: User, Source?
|
||||||
Op = "op"
|
Op = "op"
|
||||||
|
|
||||||
// Deop, Args: User, Source?
|
// Deop Args: User, Source?
|
||||||
Deop = "deop"
|
Deop = "deop"
|
||||||
|
|
||||||
// Message, Args: User, Message
|
// Message Args: User, Message
|
||||||
Message = "message"
|
Message = "message"
|
||||||
)
|
)
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -7,9 +7,9 @@ require (
|
||||||
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
||||||
github.com/hpcloud/tail v1.0.0
|
github.com/hpcloud/tail v1.0.0
|
||||||
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c
|
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c
|
||||||
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4
|
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583
|
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583
|
||||||
golang.org/x/sys v0.0.0-20190415145633-3fd5a3612ccd // indirect
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
|
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -3,19 +3,27 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat6
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c h1:d9Pm+C0vGwMRxn04D6MjHbqkEvG+qlpHjlARadAAmpQ=
|
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c h1:d9Pm+C0vGwMRxn04D6MjHbqkEvG+qlpHjlARadAAmpQ=
|
||||||
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c/go.mod h1:vvnpyLNjExupwOjP8Dvqprqwtt3BxXKoDSvWkHvCODs=
|
github.com/ppacher/nbt v0.0.0-20181201174858-0cad976cf07c/go.mod h1:vvnpyLNjExupwOjP8Dvqprqwtt3BxXKoDSvWkHvCODs=
|
||||||
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4 h1:E2wndDHuZBEqCUijjvLhfFu8wInU9ciBZuXXkn/lGHk=
|
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4 h1:E2wndDHuZBEqCUijjvLhfFu8wInU9ciBZuXXkn/lGHk=
|
||||||
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4/go.mod h1:MpDGxcw1VVpnQrSbEjy5ZRc+RVgO3j68N8RuI8snkF4=
|
github.com/tystuyfzand/mcgorcon v0.0.0-20190418232414-4bb1402707f4/go.mod h1:MpDGxcw1VVpnQrSbEjy5ZRc+RVgO3j68N8RuI8snkF4=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 h1:SZPG5w7Qxq7bMcMVl6e3Ht2X7f+AAGQdzjkbyOnNNZ8=
|
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 h1:SZPG5w7Qxq7bMcMVl6e3Ht2X7f+AAGQdzjkbyOnNNZ8=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190415145633-3fd5a3612ccd h1:MNN7PRW7zYXd8upVO5qfKeOnQG74ivRNv7sz4k4cQMs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20190415145633-3fd5a3612ccd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
|
29
main.go
29
main.go
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
log "github.com/sirupsen/logrus"
|
||||||
"meow.tf/residentsleeper/commands"
|
"meow.tf/residentsleeper/commands"
|
||||||
"meow.tf/residentsleeper/events"
|
"meow.tf/residentsleeper/events"
|
||||||
"meow.tf/residentsleeper/rcon"
|
"meow.tf/residentsleeper/rcon"
|
||||||
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
serverPath string
|
serverPath string
|
||||||
|
scriptPath string
|
||||||
rconPort int
|
rconPort int
|
||||||
rconPassword string
|
rconPassword string
|
||||||
debug bool
|
debug bool
|
||||||
|
@ -30,6 +31,7 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&serverPath, "dir", "", "server directory")
|
flag.StringVar(&serverPath, "dir", "", "server directory")
|
||||||
|
flag.StringVar(&scriptPath, "scriptPath", "", "script path override")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -37,13 +39,17 @@ func main() {
|
||||||
|
|
||||||
debug = *flagDebug
|
debug = *flagDebug
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
// Load properties
|
// Load properties
|
||||||
configPath := path.Join(serverPath, "server.properties")
|
configPath := path.Join(serverPath, "server.properties")
|
||||||
|
|
||||||
cfg, err := loadServerConfig(configPath)
|
cfg, err := loadServerConfig(configPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to load config:", err)
|
log.WithError(err).Fatalln("Unable to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
if rconEnabled, ok := cfg["enable-rcon"]; !ok || rconEnabled != "true" {
|
if rconEnabled, ok := cfg["enable-rcon"]; !ok || rconEnabled != "true" {
|
||||||
|
@ -75,7 +81,9 @@ func main() {
|
||||||
|
|
||||||
client.Debug = debug
|
client.Debug = debug
|
||||||
|
|
||||||
scriptPath := path.Join(serverPath, "scripts")
|
if scriptPath == "" {
|
||||||
|
scriptPath = path.Join(serverPath, "scripts")
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(scriptPath); !os.IsNotExist(err) {
|
if _, err := os.Stat(scriptPath); !os.IsNotExist(err) {
|
||||||
config.BasePath = path.Join(scriptPath, "config")
|
config.BasePath = path.Join(scriptPath, "config")
|
||||||
|
@ -87,11 +95,11 @@ func main() {
|
||||||
os.Mkdir(config.BasePath, 0755)
|
os.Mkdir(config.BasePath, 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Loading scripts from", scriptPath)
|
log.WithField("path", scriptPath).Info("Loading scripts")
|
||||||
err = LoadScripts(scriptPath)
|
err = loadScripts(scriptPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Warning: Unable to load scripts -", err)
|
log.WithError(err).Warn("Unable to load scripts")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,9 +112,10 @@ func handleCommands(eventArgs ...interface{}) {
|
||||||
user := eventArgs[0].(string)
|
user := eventArgs[0].(string)
|
||||||
str := eventArgs[1].(string)
|
str := eventArgs[1].(string)
|
||||||
|
|
||||||
if debug {
|
log.WithFields(log.Fields{
|
||||||
log.Println("Message from " + user + ": " + str)
|
"user": user,
|
||||||
}
|
"message": str,
|
||||||
|
}).Debug("Message received")
|
||||||
|
|
||||||
args := commands.ParseCommandArguments(str)
|
args := commands.ParseCommandArguments(str)
|
||||||
|
|
||||||
|
@ -150,5 +159,5 @@ func handleCommands(eventArgs ...interface{}) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
match.Call(ctx)
|
go match.Call(ctx)
|
||||||
}
|
}
|
||||||
|
|
33
parser.go
33
parser.go
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"github.com/acarl005/stripansi"
|
"github.com/acarl005/stripansi"
|
||||||
"github.com/hpcloud/tail"
|
"github.com/hpcloud/tail"
|
||||||
"log"
|
log "github.com/sirupsen/logrus"
|
||||||
"meow.tf/residentsleeper/events"
|
"meow.tf/residentsleeper/events"
|
||||||
"meow.tf/residentsleeper/rcon"
|
"meow.tf/residentsleeper/rcon"
|
||||||
"os"
|
"os"
|
||||||
|
@ -33,12 +33,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func logParser(logPath string) {
|
func logParser(logPath string) {
|
||||||
log.Println("Watching log path", logPath)
|
log.WithField("path", logPath).Info("Watching log path")
|
||||||
|
|
||||||
stat, err := os.Stat(logPath)
|
stat, err := os.Stat(logPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to open log file:", err)
|
log.WithError(err).Fatalln("Unable to stat log file")
|
||||||
}
|
}
|
||||||
|
|
||||||
seek := &tail.SeekInfo{
|
seek := &tail.SeekInfo{
|
||||||
|
@ -49,7 +49,7 @@ func logParser(logPath string) {
|
||||||
t, err := tail.TailFile(logPath, tail.Config{Location: seek, Follow: true, ReOpen: true})
|
t, err := tail.TailFile(logPath, tail.Config{Location: seek, Follow: true, ReOpen: true})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to open file:", err)
|
log.WithError(err).Fatalln("Unable to open log file")
|
||||||
}
|
}
|
||||||
|
|
||||||
var m []string
|
var m []string
|
||||||
|
@ -63,7 +63,7 @@ func logParser(logPath string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if m = messageRegexp.FindStringSubmatch(line.Text); m != nil {
|
if m = messageRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
events.Call(events.Message, m[1], m[2])
|
go events.Call(events.Message, m[1], m[2])
|
||||||
} else if m = loggedInRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = loggedInRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
position, err := rcon.SliceToFloats(strings.Split(m[3], ", "))
|
position, err := rcon.SliceToFloats(strings.Split(m[3], ", "))
|
||||||
|
|
||||||
|
@ -71,13 +71,13 @@ func logParser(logPath string) {
|
||||||
position = []float64{0, 0, 0}
|
position = []float64{0, 0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Call(events.LoggedIn, m[1], m[2], position[0], position[1], position[2])
|
go events.Call(events.LoggedIn, m[1], m[2], position[0], position[1], position[2])
|
||||||
} else if m = authenticatedRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = authenticatedRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
events.Call(events.Authenticated, m[1], m[2])
|
go events.Call(events.Authenticated, m[1], m[2])
|
||||||
} else if m = joinedRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = joinedRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
events.Call(events.Join, m[1])
|
go events.Call(events.Join, m[1])
|
||||||
} else if m = leftRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = leftRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
events.Call(events.Leave, m[1])
|
go events.Call(events.Leave, m[1])
|
||||||
} else if m = opRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = opRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
source := "Server"
|
source := "Server"
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ func logParser(logPath string) {
|
||||||
source = subM[1]
|
source = subM[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Call(events.Op, m[1], source)
|
go events.Call(events.Op, m[1], source)
|
||||||
} else if m = deopRegexp.FindStringSubmatch(line.Text); m != nil {
|
} else if m = deopRegexp.FindStringSubmatch(line.Text); m != nil {
|
||||||
source := "Server"
|
source := "Server"
|
||||||
|
|
||||||
|
@ -97,14 +97,17 @@ func logParser(logPath string) {
|
||||||
source = subM[1]
|
source = subM[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Call(events.Deop, m[1], source)
|
go events.Call(events.Deop, m[1], source)
|
||||||
} else if stoppingRegexp.MatchString(line.Text) {
|
} else if stoppingRegexp.MatchString(line.Text) {
|
||||||
events.Call(events.ServerClosing)
|
go func() {
|
||||||
client.Disconnect()
|
events.Call(events.ServerClosing)
|
||||||
|
|
||||||
|
client.Disconnect()
|
||||||
|
}()
|
||||||
} else if startedRegexp.MatchString(line.Text) {
|
} else if startedRegexp.MatchString(line.Text) {
|
||||||
events.Call(events.ServerStarted)
|
go events.Call(events.ServerStarted)
|
||||||
} else if rconRegexp.MatchString(line.Text) {
|
} else if rconRegexp.MatchString(line.Text) {
|
||||||
events.Call(events.Init)
|
go events.Call(events.Init)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
rcon/rcon.go
11
rcon/rcon.go
|
@ -3,8 +3,8 @@ package rcon
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/tystuyfzand/mcgorcon"
|
"github.com/tystuyfzand/mcgorcon"
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,15 +68,16 @@ func (r *Session) openConnection() *mcgorcon.Client {
|
||||||
<-time.After(10 * time.Second)
|
<-time.After(10 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Connection opened")
|
log.WithFields(log.Fields{
|
||||||
|
"host": r.host,
|
||||||
|
"port": r.port,
|
||||||
|
}).Info("Connection opened")
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Session) SendCommand(command string) (string, error) {
|
func (r *Session) SendCommand(command string) (string, error) {
|
||||||
if r.Debug {
|
log.WithField("command", command).Debug("Sending command")
|
||||||
log.Println("Send command: " + command)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.connection().SendCommand(command)
|
return r.connection().SendCommand(command)
|
||||||
}
|
}
|
||||||
|
|
33
scripting.go
33
scripting.go
|
@ -1,20 +1,21 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/yuin/gopher-lua"
|
"github.com/yuin/gopher-lua"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
luajson "layeh.com/gopher-json"
|
luajson "layeh.com/gopher-json"
|
||||||
"layeh.com/gopher-luar"
|
"layeh.com/gopher-luar"
|
||||||
"log"
|
|
||||||
"meow.tf/residentsleeper/scripting/commands"
|
"meow.tf/residentsleeper/scripting/commands"
|
||||||
"meow.tf/residentsleeper/scripting/config"
|
"meow.tf/residentsleeper/scripting/config"
|
||||||
"meow.tf/residentsleeper/scripting/event"
|
"meow.tf/residentsleeper/scripting/event"
|
||||||
|
"meow.tf/residentsleeper/scripting/eventloop"
|
||||||
"meow.tf/residentsleeper/scripting/minecraft"
|
"meow.tf/residentsleeper/scripting/minecraft"
|
||||||
"meow.tf/residentsleeper/scripting/regexp"
|
"meow.tf/residentsleeper/scripting/regexp"
|
||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadScripts(scriptPath string) error {
|
func loadScripts(scriptPath string) error {
|
||||||
files, err := ioutil.ReadDir(scriptPath)
|
files, err := ioutil.ReadDir(scriptPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,7 +27,7 @@ func LoadScripts(scriptPath string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Loading script", file.Name())
|
log.WithField("file", file.Name()).Info("Loading script")
|
||||||
|
|
||||||
err = loadScript(path.Join(scriptPath, file.Name()))
|
err = loadScript(path.Join(scriptPath, file.Name()))
|
||||||
|
|
||||||
|
@ -39,17 +40,25 @@ func LoadScripts(scriptPath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadScript(scriptFile string) error {
|
func loadScript(scriptFile string) error {
|
||||||
L := lua.NewState()
|
loop := eventloop.NewEventLoop()
|
||||||
|
|
||||||
luajson.Preload(L)
|
var err error
|
||||||
|
|
||||||
L.PreloadModule("config", config.Loader)
|
loop.Run(func(L *lua.LState) {
|
||||||
L.PreloadModule("event", event.Loader)
|
luajson.Preload(L)
|
||||||
L.PreloadModule("regexp", regexp.Loader)
|
|
||||||
L.PreloadModule("minecraft", minecraft.Loader)
|
|
||||||
L.PreloadModule("commands", commands.Loader)
|
|
||||||
|
|
||||||
L.SetGlobal("rcon", luar.New(L, client))
|
L.PreloadModule("config", config.Loader)
|
||||||
|
L.PreloadModule("event", event.Loader)
|
||||||
|
L.PreloadModule("regexp", regexp.Loader)
|
||||||
|
L.PreloadModule("minecraft", minecraft.Loader)
|
||||||
|
L.PreloadModule("commands", commands.Loader)
|
||||||
|
|
||||||
return L.DoFile(scriptFile)
|
L.SetGlobal("rcon", luar.New(L, client))
|
||||||
|
|
||||||
|
err = L.DoFile(scriptFile)
|
||||||
|
})
|
||||||
|
|
||||||
|
loop.Start()
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package commands
|
||||||
import (
|
import (
|
||||||
lua "github.com/yuin/gopher-lua"
|
lua "github.com/yuin/gopher-lua"
|
||||||
"meow.tf/residentsleeper/commands"
|
"meow.tf/residentsleeper/commands"
|
||||||
|
"meow.tf/residentsleeper/scripting/eventloop"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Loader(L *lua.LState) int {
|
func Loader(L *lua.LState) int {
|
||||||
|
@ -20,15 +21,19 @@ func commandRegister(L *lua.LState) int {
|
||||||
|
|
||||||
handler := L.CheckFunction(2)
|
handler := L.CheckFunction(2)
|
||||||
|
|
||||||
|
loop := eventloop.FromState(L)
|
||||||
|
|
||||||
cb := func(ctx *commands.CommandContext) {
|
cb := func(ctx *commands.CommandContext) {
|
||||||
L.Push(handler)
|
loop.RunOnLoop(func(L *lua.LState) {
|
||||||
L.Push(lua.LString(ctx.User))
|
L.Push(handler)
|
||||||
|
L.Push(lua.LString(ctx.User))
|
||||||
|
|
||||||
for _, v := range ctx.Arguments {
|
for _, v := range ctx.Arguments {
|
||||||
L.Push(lua.LString(v))
|
L.Push(lua.LString(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
L.PCall(1+ctx.ArgumentCount, 0, nil)
|
L.PCall(1+ctx.ArgumentCount, 0, nil)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.Register(name, cb)
|
commands.Register(name, cb)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
lua "github.com/yuin/gopher-lua"
|
lua "github.com/yuin/gopher-lua"
|
||||||
luar "layeh.com/gopher-luar"
|
luar "layeh.com/gopher-luar"
|
||||||
"meow.tf/residentsleeper/events"
|
"meow.tf/residentsleeper/events"
|
||||||
|
"meow.tf/residentsleeper/scripting/eventloop"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Loader(L *lua.LState) int {
|
func Loader(L *lua.LState) int {
|
||||||
|
@ -23,14 +24,18 @@ func onFunc(L *lua.LState) int {
|
||||||
name := L.CheckString(1)
|
name := L.CheckString(1)
|
||||||
handler := L.CheckFunction(2)
|
handler := L.CheckFunction(2)
|
||||||
|
|
||||||
|
loop := eventloop.FromState(L)
|
||||||
|
|
||||||
events.On(name, func(args ...interface{}) {
|
events.On(name, func(args ...interface{}) {
|
||||||
L.Push(handler)
|
loop.RunOnLoop(func(L *lua.LState) {
|
||||||
|
L.Push(handler)
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
L.Push(luar.New(L, arg))
|
L.Push(luar.New(L, arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
L.PCall(len(args), 0, handler)
|
L.PCall(len(args), 0, handler)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
package eventloop
|
||||||
|
|
||||||
|
import (
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
|
luar "layeh.com/gopher-luar"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type job struct {
|
||||||
|
cancelled bool
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Timer struct {
|
||||||
|
job
|
||||||
|
timer *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interval struct {
|
||||||
|
job
|
||||||
|
ticker *time.Ticker
|
||||||
|
stopChan chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventLoop struct {
|
||||||
|
vm *lua.LState
|
||||||
|
jobChan chan func()
|
||||||
|
jobCount int32
|
||||||
|
canRun bool
|
||||||
|
|
||||||
|
auxJobs []func()
|
||||||
|
auxJobsLock sync.Mutex
|
||||||
|
wakeup chan struct{}
|
||||||
|
|
||||||
|
stopCond *sync.Cond
|
||||||
|
running bool
|
||||||
|
|
||||||
|
enableConsole bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventLoop(opts ...Option) *EventLoop {
|
||||||
|
vm := lua.NewState()
|
||||||
|
|
||||||
|
loop := &EventLoop{
|
||||||
|
vm: vm,
|
||||||
|
jobChan: make(chan func()),
|
||||||
|
wakeup: make(chan struct{}, 1),
|
||||||
|
stopCond: sync.NewCond(&sync.Mutex{}),
|
||||||
|
enableConsole: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.SetGlobal("__loop", luar.New(vm, loop))
|
||||||
|
|
||||||
|
vm.PreloadModule("timers", loop.timerLoader)
|
||||||
|
|
||||||
|
return loop
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*EventLoop)
|
||||||
|
|
||||||
|
// EnableConsole controls whether the "console" module is loaded into
|
||||||
|
// the runtime used by the loop. By default, loops are created with
|
||||||
|
// the "console" module loaded, pass EnableConsole(false) to
|
||||||
|
// NewEventLoop to disable this behavior.
|
||||||
|
func EnableConsole(enableConsole bool) Option {
|
||||||
|
return func(loop *EventLoop) {
|
||||||
|
loop.enableConsole = enableConsole
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) timerLoader(L *lua.LState) int {
|
||||||
|
// register functions to the table
|
||||||
|
mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
|
||||||
|
"setInterval": loop.setInterval,
|
||||||
|
"setTimeout": loop.setTimeout,
|
||||||
|
"clearInterval": loop.clearIntervalBinding,
|
||||||
|
})
|
||||||
|
|
||||||
|
// returns the module
|
||||||
|
L.Push(mod)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) schedule(repeating bool) int {
|
||||||
|
if fn, ok := loop.vm.Get(1).(*lua.LFunction); ok {
|
||||||
|
delay := loop.vm.CheckInt(2)
|
||||||
|
|
||||||
|
log.Println("Delay:", delay)
|
||||||
|
var args []lua.LValue
|
||||||
|
if loop.vm.GetTop() > 2 {
|
||||||
|
args = make([]lua.LValue, loop.vm.GetTop()-2)
|
||||||
|
|
||||||
|
for i := 3; i < loop.vm.GetTop(); i++ {
|
||||||
|
args[i-3] = loop.vm.Get(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f := func() {
|
||||||
|
loop.vm.Push(fn)
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
loop.vm.Push(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := loop.vm.PCall(len(args), 0, fn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error calling function:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop.jobCount++
|
||||||
|
|
||||||
|
var val interface{}
|
||||||
|
|
||||||
|
if repeating {
|
||||||
|
val = loop.addInterval(f, time.Duration(delay)*time.Millisecond)
|
||||||
|
} else {
|
||||||
|
val = loop.addTimeout(f, time.Duration(delay)*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.vm.Push(luar.New(loop.vm, val))
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
log.Println("Unable to get function to call")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) setTimeout(_ *lua.LState) int {
|
||||||
|
return loop.schedule(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) setInterval(_ *lua.LState) int {
|
||||||
|
return loop.schedule(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) clearIntervalBinding(L *lua.LState) int {
|
||||||
|
ud := L.CheckUserData(1)
|
||||||
|
|
||||||
|
if interval, ok := ud.Value.(*Interval); ok {
|
||||||
|
loop.clearInterval(interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTimeout schedules to run the specified function in the context
|
||||||
|
// of the loop as soon as possible after the specified timeout period.
|
||||||
|
// SetTimeout returns a Timer which can be passed to ClearTimeout.
|
||||||
|
// The instance of goja.Runtime that is passed to the function and any Values derived
|
||||||
|
// from it must not be used outside of the function. SetTimeout is
|
||||||
|
// safe to call inside or outside of the loop.
|
||||||
|
func (loop *EventLoop) SetTimeout(fn func(*lua.LState), timeout time.Duration) *Timer {
|
||||||
|
t := loop.addTimeout(func() { fn(loop.vm) }, timeout)
|
||||||
|
loop.addAuxJob(func() {
|
||||||
|
loop.jobCount++
|
||||||
|
})
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearTimeout cancels a Timer returned by SetTimeout if it has not run yet.
|
||||||
|
// ClearTimeout is safe to call inside or outside of the loop.
|
||||||
|
func (loop *EventLoop) ClearTimeout(t *Timer) {
|
||||||
|
loop.addAuxJob(func() {
|
||||||
|
loop.clearTimeout(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInterval schedules to repeatedly run the specified function in
|
||||||
|
// the context of the loop as soon as possible after every specified
|
||||||
|
// timeout period. SetInterval returns an Interval which can be
|
||||||
|
// passed to ClearInterval. The instance of goja.Runtime that is passed to the
|
||||||
|
// function and any Values derived from it must not be used outside of
|
||||||
|
// the function. SetInterval is safe to call inside or outside of the
|
||||||
|
// loop.
|
||||||
|
func (loop *EventLoop) SetInterval(fn func(*lua.LState), timeout time.Duration) *Interval {
|
||||||
|
i := loop.addInterval(func() { fn(loop.vm) }, timeout)
|
||||||
|
loop.addAuxJob(func() {
|
||||||
|
loop.jobCount++
|
||||||
|
})
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearInterval cancels an Interval returned by SetInterval.
|
||||||
|
// ClearInterval is safe to call inside or outside of the loop.
|
||||||
|
func (loop *EventLoop) ClearInterval(i *Interval) {
|
||||||
|
loop.addAuxJob(func() {
|
||||||
|
loop.clearInterval(i)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) setRunning() {
|
||||||
|
loop.stopCond.L.Lock()
|
||||||
|
if loop.running {
|
||||||
|
panic("Loop is already started")
|
||||||
|
}
|
||||||
|
loop.running = true
|
||||||
|
loop.stopCond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run calls the specified function, starts the event loop and waits until there are no more delayed jobs to run
|
||||||
|
// after which it stops the loop and returns.
|
||||||
|
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
|
||||||
|
// of the function.
|
||||||
|
// Do NOT use this function while the loop is already running. Use RunOnLoop() instead.
|
||||||
|
// If the loop is already started it will panic.
|
||||||
|
func (loop *EventLoop) Run(fn func(*lua.LState)) {
|
||||||
|
loop.setRunning()
|
||||||
|
fn(loop.vm)
|
||||||
|
loop.run(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the event loop in the background. The loop continues to run until Stop() is called.
|
||||||
|
// If the loop is already started it will panic.
|
||||||
|
func (loop *EventLoop) Start() {
|
||||||
|
loop.setRunning()
|
||||||
|
go loop.run(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the loop that was started with Start(). After this function returns there will be no more jobs executed
|
||||||
|
// by the loop. It is possible to call Start() or Run() again after this to resume the execution.
|
||||||
|
// Note, it does not cancel active timeouts.
|
||||||
|
// It is not allowed to run Start() and Stop() concurrently.
|
||||||
|
// Calling Stop() on an already stopped loop or inside the loop will hang.
|
||||||
|
func (loop *EventLoop) Stop() {
|
||||||
|
loop.jobChan <- func() {
|
||||||
|
loop.canRun = false
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.stopCond.L.Lock()
|
||||||
|
for loop.running {
|
||||||
|
loop.stopCond.Wait()
|
||||||
|
}
|
||||||
|
loop.stopCond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunOnLoop schedules to run the specified function in the context of the loop as soon as possible.
|
||||||
|
// The order of the runs is preserved (i.e. the functions will be called in the same order as calls to RunOnLoop())
|
||||||
|
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
|
||||||
|
// of the function. It is safe to call inside or outside of the loop.
|
||||||
|
func (loop *EventLoop) RunOnLoop(fn func(*lua.LState)) {
|
||||||
|
loop.addAuxJob(func() { fn(loop.vm) })
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) runAux() {
|
||||||
|
loop.auxJobsLock.Lock()
|
||||||
|
jobs := loop.auxJobs
|
||||||
|
loop.auxJobs = nil
|
||||||
|
loop.auxJobsLock.Unlock()
|
||||||
|
for _, job := range jobs {
|
||||||
|
job()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) run(inBackground bool) {
|
||||||
|
loop.canRun = true
|
||||||
|
loop.runAux()
|
||||||
|
|
||||||
|
for loop.canRun && (inBackground || loop.jobCount > 0) {
|
||||||
|
select {
|
||||||
|
case job := <-loop.jobChan:
|
||||||
|
job()
|
||||||
|
if loop.canRun {
|
||||||
|
select {
|
||||||
|
case <-loop.wakeup:
|
||||||
|
loop.runAux()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-loop.wakeup:
|
||||||
|
loop.runAux()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop.stopCond.L.Lock()
|
||||||
|
loop.running = false
|
||||||
|
loop.stopCond.L.Unlock()
|
||||||
|
loop.stopCond.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) addAuxJob(fn func()) {
|
||||||
|
loop.auxJobsLock.Lock()
|
||||||
|
loop.auxJobs = append(loop.auxJobs, fn)
|
||||||
|
loop.auxJobsLock.Unlock()
|
||||||
|
select {
|
||||||
|
case loop.wakeup <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) addTimeout(f func(), timeout time.Duration) *Timer {
|
||||||
|
t := &Timer{
|
||||||
|
job: job{fn: f},
|
||||||
|
}
|
||||||
|
t.timer = time.AfterFunc(timeout, func() {
|
||||||
|
loop.jobChan <- func() {
|
||||||
|
loop.doTimeout(t)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) addInterval(f func(), timeout time.Duration) *Interval {
|
||||||
|
i := &Interval{
|
||||||
|
job: job{fn: f},
|
||||||
|
ticker: time.NewTicker(timeout),
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go i.run(loop)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) doTimeout(t *Timer) {
|
||||||
|
if !t.cancelled {
|
||||||
|
t.fn()
|
||||||
|
t.cancelled = true
|
||||||
|
loop.jobCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) doInterval(i *Interval) {
|
||||||
|
if !i.cancelled {
|
||||||
|
i.fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) clearTimeout(t *Timer) {
|
||||||
|
if t != nil && !t.cancelled {
|
||||||
|
t.timer.Stop()
|
||||||
|
t.cancelled = true
|
||||||
|
loop.jobCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loop *EventLoop) clearInterval(i *Interval) {
|
||||||
|
if i != nil && !i.cancelled {
|
||||||
|
i.cancelled = true
|
||||||
|
close(i.stopChan)
|
||||||
|
loop.jobCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interval) run(loop *EventLoop) {
|
||||||
|
L:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-i.stopChan:
|
||||||
|
i.ticker.Stop()
|
||||||
|
break L
|
||||||
|
case <-i.ticker.C:
|
||||||
|
loop.jobChan <- func() {
|
||||||
|
loop.doInterval(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromState(L *lua.LState) *EventLoop {
|
||||||
|
loopGlobal := L.GetGlobal("__loop")
|
||||||
|
|
||||||
|
if ud, ok := loopGlobal.(*lua.LUserData); ok {
|
||||||
|
return ud.Value.(*EventLoop)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
local event = require('event')
|
local event = require('event')
|
||||||
local commands = require('commands')
|
local commands = require('commands')
|
||||||
|
timers = require('timers')
|
||||||
minecraft = require('minecraft')
|
minecraft = require('minecraft')
|
||||||
config = require('config')
|
config = require('config')
|
||||||
|
|
||||||
|
@ -11,12 +12,22 @@ warps = {}
|
||||||
lastHomeTime = {}
|
lastHomeTime = {}
|
||||||
lastWarpTime = {}
|
lastWarpTime = {}
|
||||||
|
|
||||||
|
objectiveName = "damageTaken"
|
||||||
|
|
||||||
event.on('init', function()
|
event.on('init', function()
|
||||||
local loadedHomes, err = config.load('homes')
|
local loadedHomes, err = config.load('homes')
|
||||||
|
|
||||||
if loadedHomes and not err then
|
if loadedHomes and not err then
|
||||||
homes = loadedHomes
|
homes = loadedHomes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local loadedWarps, err = config.load('warps')
|
||||||
|
|
||||||
|
if loadedWarps and not err then
|
||||||
|
warps = loadedWarps
|
||||||
|
end
|
||||||
|
|
||||||
|
rcon:SendCommand('scoreboard objectives add ' .. objectiveName .. ' minecraft.custom:minecraft.damage_taken')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
commands.register('sethome', function(user)
|
commands.register('sethome', function(user)
|
||||||
|
@ -36,7 +47,7 @@ commands.register('sethome', function(user)
|
||||||
print('Unable to save homes')
|
print('Unable to save homes')
|
||||||
end
|
end
|
||||||
|
|
||||||
rcon:SendMessage(user, string.format("Home location set to %d, %d, %d", c[1], c[2], c[3]))
|
rcon:SendColorfulMessage(user, 'green', string.format("Home location set to %d, %d, %d", c[1], c[2], c[3]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
commands.register('resethome', function(user)
|
commands.register('resethome', function(user)
|
||||||
|
@ -48,7 +59,7 @@ commands.register('resethome', function(user)
|
||||||
print('Unable to save homes')
|
print('Unable to save homes')
|
||||||
end
|
end
|
||||||
|
|
||||||
rcon:SendMessage(user, 'Home location reset')
|
rcon:SendColorfulMessage(user, 'green', 'Home location reset')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
commands.register('home', function(user)
|
commands.register('home', function(user)
|
||||||
|
@ -59,7 +70,7 @@ commands.register('home', function(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
if loc == nil then
|
if loc == nil then
|
||||||
rcon:SendMessage(user, "You haven't set your spawn or home yet.")
|
rcon:SendColorfulMessage(user, 'red', "You haven't set your spawn or home yet.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,13 +79,35 @@ commands.register('home', function(user)
|
||||||
if lastWarp ~= nil and lastWarp + warpDelay > os.time() and not minecraft.isOp(user) then
|
if lastWarp ~= nil and lastWarp + warpDelay > os.time() and not minecraft.isOp(user) then
|
||||||
local delay = warpDelay - (os.time() - lastWarp)
|
local delay = warpDelay - (os.time() - lastWarp)
|
||||||
|
|
||||||
rcon:SendMessage(user, "You need to wait " .. delay .. " seconds before warping again.")
|
rcon:SendColorfulMessage(user, 'red', "You need to wait " .. delay .. " seconds before warping again.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
lastHomeTime[user] = os.time()
|
lastHomeTime[user] = os.time()
|
||||||
|
|
||||||
rcon:Teleport(user, string.format("%f %d %f", loc[1], loc[2], loc[3]))
|
local delayLeft = 5
|
||||||
|
|
||||||
|
local originalDamage, err = rcon:SendCommand("scoreboard players get " .. user .. " " .. objectiveName)
|
||||||
|
|
||||||
|
local interval = nil
|
||||||
|
|
||||||
|
interval = timers.setInterval(function()
|
||||||
|
if delayLeft == 0 then
|
||||||
|
local newDamage, err = rcon:SendCommand("scoreboard players get " .. user .. " " .. objectiveName)
|
||||||
|
|
||||||
|
timers.clearInterval(interval)
|
||||||
|
|
||||||
|
if newDamage ~= originalDamage then
|
||||||
|
rcon:SendColorfulMessage(user, 'red', "Teleport was interrupted by combat.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
rcon:SendCommand('execute in minecraft:overworld run tp ' .. user .. ' ' .. string.format("%f %d %f", loc[1], loc[2], loc[3]))
|
||||||
|
else
|
||||||
|
rcon:SendColorfulMessage(user, 'gray', "Teleporting in " .. delayLeft .. " seconds")
|
||||||
|
delayLeft = delayLeft - 1
|
||||||
|
end
|
||||||
|
end, 1000)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
commands.register('setwarp <place>', function(user, place)
|
commands.register('setwarp <place>', function(user, place)
|
||||||
|
@ -82,7 +115,6 @@ commands.register('setwarp <place>', function(user, place)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local loc = rcon:GetLocation(user)
|
local loc = rcon:GetLocation(user)
|
||||||
|
|
||||||
local c = {}
|
local c = {}
|
||||||
|
@ -99,12 +131,12 @@ commands.register('setwarp <place>', function(user, place)
|
||||||
print('Unable to save warps')
|
print('Unable to save warps')
|
||||||
end
|
end
|
||||||
|
|
||||||
rcon:SendMessage(user, string.format("Warp %s set to %d, %d, %d", place, c[1], c[2], c[3]))
|
rcon:SendColorfulMessage(user, 'green', string.format("Warp %s set to %d, %d, %d", place, c[1], c[2], c[3]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
commands.register('warp <place>', function(user, place)
|
commands.register('warp <place>', function(user, place)
|
||||||
if warps[place] == nil then
|
if warps[place] == nil then
|
||||||
rcon:SendMessage(user, "This warp point doesn't exist")
|
rcon:SendColorfulMessage(user, 'red', "This warp point doesn't exist")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -115,23 +147,11 @@ commands.register('warp <place>', function(user, place)
|
||||||
if lastWarp ~= nil and lastWarp + warpDelay > os.time() and not minecraft.isOp(user) then
|
if lastWarp ~= nil and lastWarp + warpDelay > os.time() and not minecraft.isOp(user) then
|
||||||
local delay = warpDelay - (os.time() - lastWarp)
|
local delay = warpDelay - (os.time() - lastWarp)
|
||||||
|
|
||||||
rcon:SendMessage(user, "You need to wait " .. delay .. " seconds before warping again.")
|
rcon:SendColorfulMessage(user, 'red', "You need to wait " .. delay .. " seconds before warping again.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
lastWarpTime[user] = os.time()
|
lastWarpTime[user] = os.time()
|
||||||
|
|
||||||
rcon:Teleport(user, string.format("%f %d %f", loc[1], loc[2], loc[3]))
|
rcon:SendCommand('execute in minecraft:overworld run tp ' .. user .. ' ' .. string.format("%f %d %f", loc[1], loc[2], loc[3]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
tprequests = {}
|
|
||||||
|
|
||||||
commands.register('tpa <target>', function(user, target)
|
|
||||||
|
|
||||||
end)
|
|
||||||
|
|
||||||
commands.register('tpaccept', function(user)
|
|
||||||
end)
|
|
||||||
|
|
||||||
commands.register('tpdeny', function(user)
|
|
||||||
end)
|
|
Loading…
Reference in New Issue