commit 6cc194a5d16f85c375422f4cfc957d4b81d101f1 Author: Brian Buller Date: Sun Dec 21 13:30:42 2014 -0600 Initial Commit For some reason. diff --git a/mc_man.go b/mc_man.go new file mode 100644 index 0000000..d3fd1bf --- /dev/null +++ b/mc_man.go @@ -0,0 +1,134 @@ +package main + +import ( + "fmt" + "github.com/br0xen/mc_man/util" + "log" + "os" + "os/exec" + "strings" +) + +func main() { + // Load the Config + util.LoadConfig() + + xmxVal := "1024M" + xmsVal := "1024M" + args := os.Args[1:] + if len(args) > 0 { + if args[0] == "-help" { + fmt.Println("Usage: mc_man ") + fmt.Println(" - The Maximum Memory Allocation Pool for the JVM") + fmt.Println(" - The Initial Memory Allocation Pool") + os.Exit(0) + } + if len(args) > 0 { + xmxVal = args[0] + if len(args) > 1 { + xmsVal = args[1] + } + } + } + + // The minecraft server command + cmd := exec.Command("java", "-Xmx"+xmxVal, "-Xms"+xmsVal, "-jar", "minecraft_server.jar", "nogui") + + // Control StdIn + stdin, err := cmd.StdinPipe() + if err != nil { + log.Fatal(err) + } + + // Pipe the process' stdout to stdout for monitoring + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + + // Kick off the process + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + // Build a string channel for stdout + ch := make(chan string) + + // And a routine to keep the channel updated + go func() { + buf := make([]byte, 1024) + for { + n, err := stdout.Read(buf) + if n != 0 { + // Something there throw it into the channel + ch <- string(buf[:n]) + } + if err != nil { + // Error, break out of loop + break + } + } + fmt.Println("mc_man stopped") + close(ch) + }() + + listen_for := "" + listen_for_user := "" + + // The forever loop to monitor the channel +loop: + for { + s, ok := <-ch + if !ok { + break loop + } + m := util.NewMessage(s) + // First check for anything we're listening for + + if listen_for != "" && strings.Contains(m.Text, listen_for) { + r := strings.Split(m.Text, listen_for) + if len(r) > 0 { + p_str := r[1] + p_str = strings.Replace(p_str, ",", "", -1) + util.SetHome(listen_for_user, p_str) + stdin.Write([]byte("tell " + listen_for_user + " Set your home to " + p_str)) + listen_for = "" + listen_for_user = "" + } + } else { + if m.IsStopRequest() { + stdin.Write([]byte("stop\n")) + } else if m.IsHomeRequest() { + home_str, found := util.GetHome(m.User.Name) + if found { + stdin.Write([]byte("tp " + m.User.Name + " " + home_str + "\n")) + } + } else if m.IsSetHomeRequest() { + listen_for = "Teleported " + m.User.Name + " to " + listen_for_user = m.User.Name + stdin.Write([]byte("tp " + m.User.Name + " ~ ~ ~\n")) + } else if m.IsVisitRequest() { + visiting_user, err := m.VisitingUser() + if !err { + fmt.Printf("\x1b[31;1m%s requested a tp visit to %s\x1b[0m\n", m.User.Name, visiting_user) + porch_str, found := util.GetPorch(visiting_user) + fmt.Printf(">>> Porch String: " + porch_str) + if found { + stdin.Write([]byte("tp " + m.User.Name + " " + porch_str + "\n")) + } else { + stdin.Write([]byte("tell " + m.User.Name + " Couldn't find that user's porch 1\n")) + } + } else { + stdin.Write([]byte("tell " + m.User.Name + " Couldn't find that user's porch 2\n")) + } + } else if m.IsSetPorchRequest() { + listen_for = "Teleported " + m.User.Name + " to " + listen_for_user = m.User.Name + stdin.Write([]byte("tp " + m.User.Name + " ~ ~ ~\n")) + } else { + // fmt.Printf("\x1b[34;1m%s\x1b[0m", m.Output()) + } + } + fmt.Printf("\x1b[34;1m%s\x1b[0m", m.Output()) + } +} diff --git a/util/config.go b/util/config.go new file mode 100644 index 0000000..7b07b33 --- /dev/null +++ b/util/config.go @@ -0,0 +1,160 @@ +package util + +import ( + "fmt" + "github.com/antonholmquist/jason" + "io/ioutil" + // "log" + // "os" + // "bytes" + "strings" +) + +type Config struct { + // The JSON object of what was read + LoadedJson jason.Object + Options jason.Object + FeatureTPHome bool + FeatureTPVisit bool + Users []*User + U User +} + +var c *Config + +func LoadConfig() { + c = new(Config) + config_str, err := ioutil.ReadFile("mc_man.config") + if err == nil { + j, _ := jason.NewObjectFromBytes(config_str) + o, _ := j.GetObjectArray("options") + + for _, option := range o { + opt_name, _ := option.GetString("name") + opt_enabled, _ := option.GetBoolean("enabled") + if opt_name == "home" { + c.FeatureTPHome = opt_enabled + } else if opt_name == "visit" { + c.FeatureTPVisit = opt_enabled + } + } + + c.Users = make([]*User, 1) + u, _ := j.GetObjectArray("users") + for _, user := range u { + user_name, err := user.GetString("name") + if err == nil && user_name != "" { + user_home, _ := user.GetString("home") + user_porch, _ := user.GetString("porch") + us := NewUser(user_name) + // TODO: Check if this user is an op on the server + us.Home = user_home + us.Porch = user_porch + c.Users = append(c.Users, us) + c.U = *us + } + } + fmt.Printf("Loaded %d Users", len(c.Users)) + } +} + +func WriteConfig() { + // Generate the JSON string for the config file + d := "{\"options\":[" + // Output options array + d = d + "{\"name\":\"home\",\"enabled\":" + if c.FeatureTPHome { + d = d + "true" + } else { + d = d + "false" + } + d = d + "},{\"name\":\"visit\",\"enabled\":" + if c.FeatureTPVisit { + d = d + "true" + } else { + d = d + "false" + } + d = d + "}],\"users\":[" + d = d + c.U.ToJSONString() + // Output users array + /* + num_users := len(c.Users) + fmt.Printf("Number of Users: %d", num_users) + for i := 0; i < num_users; i++ { + user := c.Users[i] + // for _, user := range c.Users { + fmt.Println(d) + num_users-- + d = d + user.ToJSONString() + if user.Name != "" { + if num_users > 0 { + d = d + "," + } + } + } + */ + d = d + "]}" + do := []byte(d) + ioutil.WriteFile("mc_man.config", do, 0644) +} + +func SetHome(user string, loc string) { + /* + u, idx := FindUser(user) + if idx == -1 { + u = NewUser(user) + c.Users = append(c.Users, u) + idx = len(c.Users) - 1 + } + u.Home = strings.Replace(loc, "\n", "", -1) + // Replace the user in the Users array + c.Users[idx] = u + */ + c.U.Home = strings.Replace(loc, "\n", "", -1) + WriteConfig() +} + +func GetHome(user string) (string, bool) { + /* + u, idx := FindUser(user) + if idx == -1 || u.Home == "" { + return "", false + } + */ + return c.U.Home, true +} + +func SetPorch(user string, loc string) { + /* + u, idx := FindUser(user) + if idx == -1 { + u = NewUser(user) + c.Users = append(c.Users, u) + idx = len(c.Users) - 1 + } + u.Porch = strings.Replace(loc, "\n", "", -1) + c.Users[idx] = u + */ + c.U.Porch = strings.Replace(loc, "\n", "", -1) + WriteConfig() +} + +func GetPorch(user string) (string, bool) { + /* + u, idx := FindUser(user) + if idx > -1 || u.Porch == "" { + return "", false + } + return u.Porch, true + */ + return c.U.Porch, true +} + +func FindUser(name string) (*User, int) { + for i, user := range c.Users { + if user.Name == name { + return user, i + } + } + return nil, -1 +} diff --git a/util/message.go b/util/message.go new file mode 100644 index 0000000..50e4023 --- /dev/null +++ b/util/message.go @@ -0,0 +1,94 @@ +package util + +import ( + //"fmt" + "regexp" + "strings" +) + +type Message struct { + User *User + Text string + + IsStopRequest func() bool + IsHomeRequest func() bool + IsSetHomeRequest func() bool + IsVisitRequest func() bool + IsSetPorchRequest func() bool + VisitingUser func() (string, bool) + Output func() string +} + +func NewMessage(t string) *Message { + m := new(Message) + msg_user := regexp.MustCompile("<[^>]+>") + tmpUser := msg_user.FindString(t) + tmpUser = strings.Replace(tmpUser, "<", "", -1) + tmpUser = strings.Replace(tmpUser, ">", "", -1) + m.User = NewUser(tmpUser) + if tmpUser == "br0xen" { + m.User.IsOp = true + } + m.Text = t + if m.User.Name != "" { + res := strings.Split(t, "<"+m.User.Name+"> ") + if len(res) > 0 { + m.Text = res[1] + } + } + + m.IsStopRequest = func() bool { + return (m.User.IsOp && m.Text == "!stop\n") + } + + m.IsHomeRequest = func() bool { + if m.User.Name != "" { + return (m.Text == "!home\n") + } else { + return false + } + } + + m.IsSetHomeRequest = func() bool { + if m.User.Name != "" { + return (m.Text == "!set home\n") + } else { + return false + } + } + + m.IsSetPorchRequest = func() bool { + if m.User.Name != "" { + return (m.Text == "!set porch\n") + } else { + return false + } + } + + m.IsVisitRequest = func() bool { + if m.User.Name != "" { + return strings.HasPrefix(m.Text, "!visit ") + } else { + return false + } + } + + m.VisitingUser = func() (string, bool) { + if m.IsVisitRequest() { + s := strings.Replace(m.Text, "!visit ", "", -1) + s = strings.Replace(s, "\n", "", -1) + return s, false + } + return "", true + } + + m.Output = func() string { + if m.User.Name != "" { + return "<" + m.User.Name + "> " + m.Text + } else { + return m.Text + } + } + + return m +} diff --git a/util/message_manager.go b/util/message_manager.go new file mode 100644 index 0000000..6d2af98 --- /dev/null +++ b/util/message_manager.go @@ -0,0 +1,41 @@ +package util + +import ( + "strings" +) + +type MessageManager struct { + /* Process takes a string and returns whether + * we did anything with that string or not + */ + Process func(inp string) bool + + /* listeners is an array of functions that + * tell the manager how to listen for specific + * text and what to do if we receive it. + * Each listener returns true if the input was + * "consumed" (i.e. - Don't send to any more + * listeners) + */ + listeners []func(inp string) bool + + /* tempListeners is an array of functions that + * work the same as 'listeners', but these are + * just temporary and higher priority than + * 'listeners' + */ + tempListeners []func(inp string) bool +} + +func NewManager() *MessageManager { + mm := new(MessageManager) + mm.Process = func(inp string) bool { + // TODO: send to temp listeners + for i, listener := range listeners { + if listener(inp) { + return true + } + } + } + return mm +} diff --git a/util/user.go b/util/user.go new file mode 100644 index 0000000..0d461d0 --- /dev/null +++ b/util/user.go @@ -0,0 +1,21 @@ +package util + +type User struct { + Name string + IsOp bool + Home string + Porch string + ToJSONString func() string +} + +func NewUser(nm string) *User { + m := new(User) + m.Name = nm + m.IsOp = false + m.Home = "" + m.Porch = "" + m.ToJSONString = func() string { + return "{\"name\":\"" + m.Name + "\",\"home\":\"" + m.Home + "\",\"porch\":\"" + m.Porch + "\"}" + } + return m +}