/mcclient/bots/woodcutter/woodcutter.go

https://github.com/kierdavis/mc · Go · 269 lines · 194 code · 64 blank · 11 comment · 71 complexity · 5845406a1a388620092d06c96f72bf32 MD5 · raw file

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/kierdavis/ansi"
  6. "github.com/kierdavis/mc/mcclient"
  7. "io"
  8. "os"
  9. "regexp"
  10. "time"
  11. )
  12. var WhisperRegexp = regexp.MustCompile("^\xC2\xA77([a-zA-Z0-9_]+) whispers (.+)")
  13. var (
  14. usernameP = flag.String("username", "Woodcutter", "The username the bot will log in with.")
  15. passwordP = flag.String("password", "", "The password the bot will log in with. If not specified, no authentication occurs and the server is expected to be in offline mode.")
  16. debugP = flag.Bool("debug", false, "Whether to show debug messages.")
  17. )
  18. func die(err error) {
  19. if err != nil {
  20. ansi.Fprintf(os.Stderr, ansi.RedBold, "Error: %s\n", err.Error())
  21. os.Exit(1)
  22. }
  23. }
  24. type DebugWriter struct{}
  25. func (w DebugWriter) Write(s []byte) (n int, err error) {
  26. return ansi.Print(ansi.White, string(s))
  27. }
  28. func main() {
  29. flag.Parse()
  30. if flag.NArg() < 1 {
  31. ansi.Fprintf(os.Stderr, ansi.RedBold, "usage: %s [options] <server address>\n", os.Args[0])
  32. os.Exit(2)
  33. }
  34. addr := flag.Arg(0)
  35. username := *usernameP
  36. password := *passwordP
  37. debug := *debugP
  38. var debugWriter io.Writer
  39. var client *mcclient.Client
  40. var err error
  41. if debug {
  42. debugWriter = DebugWriter{}
  43. }
  44. if password == "" {
  45. if username == "" {
  46. username = "Player"
  47. }
  48. ansi.Printf(ansi.Green, "Authenticating offline as %s...\n", username)
  49. client = mcclient.LoginOffline(username, debugWriter)
  50. } else {
  51. ansi.Printf(ansi.Green, "Authenticating as %s...\n", username)
  52. client, err = mcclient.Login(username, password, debugWriter)
  53. die(err)
  54. }
  55. client.StoreWorld = true
  56. client.HandleMessage = func(msg string) {
  57. matches := WhisperRegexp.FindStringSubmatch(msg)
  58. if matches != nil {
  59. ansi.Printf(ansi.YellowBold, "Message from %s: %s\n", matches[1], matches[2])
  60. client.Chat(fmt.Sprintf("/tell %s %s", matches[1], matches[2]))
  61. }
  62. //fmt.Printf("# %s\n", mcclient.ANSIEscapes(msg))
  63. //fmt.Printf("# %s\n", msg)
  64. }
  65. go func() {
  66. /*
  67. for err := range client.ErrChan {
  68. ansi.Printf(ansi.RedBold, "Error: %s\n", err.Error())
  69. }
  70. */
  71. die(<-client.ErrChan)
  72. }()
  73. ansi.Printf(ansi.Green, "Connecting to %s...\n", addr)
  74. die(client.Join(addr))
  75. ansi.Printf(ansi.Green, "Connected!\n")
  76. go bot(client)
  77. kickMessage := client.Run()
  78. ansi.Printf(ansi.Green, "Disconnected: %s\n", kickMessage)
  79. }
  80. func bot(client *mcclient.Client) {
  81. for {
  82. time.Sleep(time.Second * 5)
  83. p, ok := findNearestTree(client)
  84. if !ok {
  85. return
  86. }
  87. ansi.Printf(ansi.Green, "Found tree: %d, %d, %d\n", p.x, p.y, p.z)
  88. chop(client, p)
  89. }
  90. }
  91. type xyz struct {
  92. x, y, z int
  93. }
  94. func findNearestTree(client *mcclient.Client) (p xyz, ok bool) {
  95. p = xyz{int(client.PlayerX), int(client.PlayerY), int(client.PlayerZ)}
  96. radius := 1
  97. x := -radius
  98. z := -radius
  99. p.x -= radius
  100. p.z -= radius
  101. dir := 1
  102. mainloop:
  103. for {
  104. //fmt.Scanln()
  105. block, _, _, _, _, ok := client.GetBlock(p.x, p.y, p.z)
  106. if !ok {
  107. ansi.Printf(ansi.RedBold, "No log found!\n")
  108. return p, false
  109. }
  110. //println(p.x, p.y, p.z, block)
  111. if block == 0 {
  112. under, _, _, _, _, _ := client.GetBlock(p.x, p.y-1, p.z)
  113. if under == 0 {
  114. p.y--
  115. } else {
  116. if (dir > 0 && x == radius) || (dir < 0 && x == -radius) {
  117. if (dir > 0 && z == radius) || (dir < 0 && z == -radius) {
  118. if dir < 0 {
  119. radius++
  120. x = -radius
  121. z = -radius
  122. p.x -= 1
  123. p.z -= 1
  124. }
  125. dir = -dir
  126. } else {
  127. z += dir
  128. p.z += dir
  129. }
  130. } else {
  131. x += dir
  132. p.x += dir
  133. }
  134. }
  135. } else if block == 17 {
  136. // We found log!
  137. n := p
  138. for {
  139. n.y++
  140. block, _, _, _, _, ok = client.GetBlock(n.x, n.y, n.z)
  141. if block == 17 { // Log
  142. continue
  143. } else if block == 18 { // Leaves, always found above a tree
  144. break
  145. } else { // Not a log
  146. continue mainloop
  147. }
  148. }
  149. for {
  150. block, _, _, _, _, ok = client.GetBlock(p.x, p.y-1, p.z)
  151. if block == 17 {
  152. p.y--
  153. continue
  154. } else { // Bottom block of trunk
  155. return p, true
  156. }
  157. }
  158. } else {
  159. p.y++
  160. }
  161. }
  162. return p, false
  163. }
  164. func moveTo(client *mcclient.Client, p xyz) {
  165. p.x++ // Dont stand in the tree!
  166. ticker := time.NewTicker(mcclient.Tick)
  167. ansi.Printf(ansi.Green, "Moving from (%d, %d, %d) to (%d, %d, %d)\n", int(client.PlayerX), int(client.PlayerY), int(client.PlayerZ), p.x, p.y, p.z)
  168. for (int(client.PlayerX) != p.x) || (int(client.PlayerY) != p.y) || (int(client.PlayerZ) != p.z) {
  169. //println(client.PlayerX, client.PlayerY, client.PlayerZ)
  170. if int(client.PlayerX) < p.x {
  171. client.PlayerX += 0.2
  172. } else if int(client.PlayerX) > p.x {
  173. client.PlayerX -= 0.2
  174. }
  175. if int(client.PlayerY) < p.y {
  176. client.PlayerY += 0.2
  177. } else if int(client.PlayerY) > p.y {
  178. client.PlayerY -= 0.2
  179. }
  180. if int(client.PlayerZ) < p.z {
  181. client.PlayerZ += 0.2
  182. } else if int(client.PlayerZ) > p.z {
  183. client.PlayerZ -= 0.2
  184. }
  185. client.PlayerStance = client.PlayerY + 1.0
  186. die(client.SendPacket(0x0D, client.PlayerX, client.PlayerY, client.PlayerStance, client.PlayerZ, client.PlayerYaw, client.PlayerPitch, client.PlayerOnGround))
  187. <-ticker.C
  188. }
  189. ansi.Printf(ansi.Green, "Done moving\n")
  190. }
  191. func chop(client *mcclient.Client, p xyz) {
  192. for {
  193. block, _, _, _, _, _ := client.GetBlock(p.x, p.y, p.z)
  194. if block == 17 {
  195. moveTo(client, p)
  196. ansi.Printf(ansi.Green, "Breaking block at (%d, %d, %d)\n", p.x, p.y, p.z)
  197. die(client.SendPacket(0x0E, int8(0), int32(p.x), int8(p.y), int32(p.z), int8(5)))
  198. die(client.SendPacket(0x0E, int8(2), int32(p.x), int8(p.y), int32(p.z), int8(5)))
  199. time.Sleep(time.Second * 3)
  200. p.y++
  201. } else {
  202. break
  203. }
  204. }
  205. }