├── net └── srv.go ├── .github └── workflows │ └── go.yml ├── go.mod ├── conf.json ├── LICENSE ├── mclogin ├── realms.go └── login.go ├── README.md ├── float └── float.go ├── go.sum └── AutoFish.go /net/srv.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import "net" 4 | 5 | //checkSRV check if SRV needed and get addrs 6 | func CheckSRV(ip *string, port *int) { 7 | _, addrs, _ := net.LookupSRV("minecraft", "tcp", *ip) 8 | if len(addrs) != 0 && addrs[0].Target != "" { 9 | *ip = addrs[0].Target 10 | *port = int(addrs[0].Port) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: [push] 3 | jobs: 4 | 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.14 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.14 14 | id: go 15 | 16 | - name: Check out code into the Go module directory 17 | uses: actions/checkout@v2 18 | 19 | - name: Get dependencies 20 | run: | 21 | go get -v -t -d ./... 22 | if [ -f Gopkg.toml ]; then 23 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 24 | dep ensure 25 | fi 26 | 27 | - name: Build 28 | run: go build -v . 29 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/MscBaiMeow/FishBot 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/AlecAivazis/survey/v2 v2.0.8 7 | github.com/Netflix/go-expect v0.0.0-20200312175327-da48e75238e2 // indirect 8 | github.com/Tnze/go-mc v1.15.2 9 | github.com/google/uuid v1.1.1 10 | github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c // indirect 11 | github.com/mattn/go-colorable v0.1.2 12 | golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 // indirect 13 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect 14 | golang.org/x/text v0.3.3 // indirect 15 | ) 16 | 17 | replace github.com/Tnze/go-mc => github.com/MscBaiMeow/go-mc v1.15.3-0.20200720014825-3eb7c12f5db2 18 | 19 | //replace github.com/Tnze/go-mc => D:\src\MscBaiMeow\go-mc 20 | -------------------------------------------------------------------------------- /conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "players": [ 3 | { 4 | "name": "Msc__BaiMeow", 5 | "UUID": "1ef88718148741cb8f5770e01fd55ef7", 6 | "Tokens": { 7 | "accessToken": "eyJhbpciOiJIUzI1NiJ9.eyJzdWmiOiIxNTBiY2d0N2Q4MGUxZmNkOWUwZDM5YmY1Yzk0NzhhMiIsInlnZ3QiOiI5NzViNDgwNTdhMDg0ZDcyYjk0N2I1NzQxOTBhYWRhYyIsInNwciI6IjFlZjg4NzE4MTQ4NzQxY2I4ZjU3NzBlMDFmZDU1ZWY3IiwiaXNzIjoiWWdnZHJhc2lsLUF1dGgiLCJleHAiOjE1ODM2MzIzNTYsImlhdCI6MTU4MzQ1OTU1Nn0.WMtYlGEhIv3Ex4roPEmbEL5zdI-i1IfypQ1nr5r1Vo4", 8 | "clientToken": "1ca41fra-6f49-4b67-8bb5-4c432be98633" 9 | }, 10 | "account": "10000@qq.com", 11 | "authserver": "https://authserver.mojang.com", 12 | "authmode": "MojangAuth" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MscBaiMeow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mclogin/realms.go: -------------------------------------------------------------------------------- 1 | package mclogin 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/AlecAivazis/survey/v2" 9 | "github.com/Tnze/go-mc/bot" 10 | "github.com/Tnze/go-mc/realms" 11 | ) 12 | 13 | //Checkrealms can get IP of the realm so that you can login in realms 14 | func Checkrealms(ip *string, port *int, c *bot.Client, version *string, auth *Player) error { 15 | var r *realms.Realms 16 | r = realms.New(*version, c.Name, c.AsTk, c.Auth.UUID) 17 | servers, err := r.Worlds() 18 | if err != nil { 19 | return err 20 | } 21 | var i = 0 22 | //list realms 23 | 24 | //agree TOS 25 | if err := r.TOS(); err != nil { 26 | return err 27 | } 28 | var ( 29 | selected string 30 | preSelected []string 31 | selectedNo int 32 | ) 33 | for _, v := range servers { 34 | preSelected = append(preSelected, fmt.Sprintf("[%d]", i)+v.Name) 35 | i++ 36 | } 37 | prompt := &survey.Select{ 38 | Message: "Choose a realm:", 39 | Options: preSelected, 40 | } 41 | survey.AskOne(prompt, &selected) 42 | fmt.Sscanf(selected, "[%d]", &selectedNo) 43 | //GET IP 44 | ipandport, err := r.Address(servers[selectedNo]) 45 | if err != nil { 46 | return err 47 | } 48 | s := strings.Split(ipandport, ":") 49 | *ip = s[0] 50 | *port, _ = strconv.Atoi(s[1]) 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FishBot 2 | Minecraft内自动钓鱼 3 | Fishing in Minecraft automatically 4 | 5 | 基于[https://github.com/Tnze/go-mc](https://github.com/MscBaiMeow/FishBotReload) 6 | 7 | # 这个项目是我Golang学习的处女作,已经修修补补一段时间了,这次go-mc有一个较大的更新,是时候重写了 8 | # 另见 [https://github.com/MscBaiMeow/FishBotReload](https://github.com/MscBaiMeow/FishBotReload) 9 | 10 | #### 使用方法 11 | 12 | ------ 13 | 14 | -account string 15 | ​ Mojang账号 16 | 17 | -auth string 18 | ​ 验证服务器(外置登陆) (default "https://authserver.mojang.com") 19 | 20 | -ip string 21 | ​ 服务器IP (default "localhost") 22 | 23 | -name string 24 | ​ 游戏ID 25 | 26 | -passwd string 27 | ​ Mojang账户密码 28 | 29 | -port int 30 | ​ 端口,默认25565 (default 25565) 31 | 32 | -realms 33 | ​ 加入领域服 34 | 35 | -t int 36 | ​ 自动重新抛竿时间 (default 45) 37 | 38 | 39 | 如果你正确打开的话,接下来会有指示的 40 | 41 | #### 注意 42 | 43 | ------ 44 | 45 | ~~不支持SRV解析,请自行解析~~ 46 | 47 | 目前优先解析SRV 48 | 49 | 具体方法GUI版本的readme看去 50 | 51 | 52 | 53 | (懒得写了 54 | 55 | #### 鸣谢 56 | 57 | ------ 58 | 59 | [Tnze](https://github.com/Tnze)(go-mc项目作者,FishBot原作者) 60 | 61 | [fcc](https://github.com/Amazefcc233)(GUI版本作者,提供测试服务器) 62 | 63 | [Jing332](https://github.com/jing332)(领域服支持项目抓包) 64 | 65 | [Miaoscraft](https://miaoscraft.cn)(感谢相遇) 66 | -------------------------------------------------------------------------------- /float/float.go: -------------------------------------------------------------------------------- 1 | package float 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | type fishFloat struct { 8 | ID int 9 | pos 10 | } 11 | type analyser struct { 12 | pos //上次位置 13 | h float64 //连续下降高度 14 | } 15 | type pos struct{ x, y, z float64 } 16 | 17 | var float fishFloat 18 | var ana = &analyser{} 19 | 20 | //Distance get the distance from given pos to the float 21 | func Distance(x, z float64) float64 { 22 | x0 := float.x - x 23 | z0 := float.z - z 24 | return math.Sqrt(x0*x0 + z0*z0) 25 | } 26 | 27 | //Set set Float id and pos when new float was spawn 28 | func Set(ID int, x, y, z float64) { 29 | float = fishFloat{ 30 | ID: ID, 31 | pos: pos{x: x, y: y, z: z}, 32 | } 33 | ana.setPos(x, y, z) 34 | } 35 | 36 | //IsMine judge the belonging of the float 37 | func IsMine(EID int) bool { 38 | return EID == float.ID 39 | } 40 | 41 | //IsFish update the pos of the float with deltaXYZ and judge if hook 42 | func IsFish(DeltaX, DeltaY, DeltaZ int) bool { 43 | float.x += float64(DeltaX) / 4096 44 | float.y += float64(DeltaY) / 4096 45 | float.z += float64(DeltaZ) / 4096 46 | // fmt.Println(float) 47 | return ana.AddPos() 48 | } 49 | 50 | func (a *analyser) setPos(x, y, z float64) { 51 | a = &analyser{ 52 | pos: pos{x: x, y: y, z: z}, 53 | h: 0, 54 | } 55 | } 56 | 57 | func (a *analyser) AddPos() bool { 58 | if Distance(a.x, a.z) > 0.6 { 59 | a.setPos(float.x, float.y, float.z) 60 | } else if a.y > float.y { 61 | a.h += a.y - float.y 62 | } else { 63 | a.h = 0 64 | } 65 | a.pos = float.pos 66 | if a.h > 0.3 { 67 | a.h = -1 68 | return true 69 | } 70 | return false 71 | } 72 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/AlecAivazis/survey/v2 v2.0.8 h1:zVjWKN+JIAfmrq6nGWG3DfLS8ypEBhxYy0p7FM+riFk= 2 | github.com/AlecAivazis/survey/v2 v2.0.8/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk= 3 | github.com/MscBaiMeow/go-mc v1.15.3-0.20200720014825-3eb7c12f5db2 h1:KNjSnPuivVkXg+2W9A4Z9fHdVtzLnO5GHNM5nlup1M0= 4 | github.com/MscBaiMeow/go-mc v1.15.3-0.20200720014825-3eb7c12f5db2/go.mod h1:LKj1KKSj4m58fpJaTmOHC3DdQKJ1RSfEGHFR1zMLSF8= 5 | github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= 6 | github.com/Netflix/go-expect v0.0.0-20200312175327-da48e75238e2 h1:y2avNRjCeJT8b7svzjhKZjsvW5Jki/iAqTBEPJURaUg= 7 | github.com/Netflix/go-expect v0.0.0-20200312175327-da48e75238e2/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 11 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 12 | github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= 13 | github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk= 14 | github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= 15 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 16 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 17 | github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= 18 | github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 19 | github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= 20 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 21 | github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= 22 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 23 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= 24 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 25 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 26 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 27 | github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= 28 | github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 29 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 30 | golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 31 | golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= 32 | golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 33 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 34 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 35 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= 39 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 41 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 42 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 43 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 44 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 45 | -------------------------------------------------------------------------------- /AutoFish.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "log" 7 | "os" 8 | "time" 9 | 10 | "github.com/MscBaiMeow/FishBot/net" 11 | "github.com/google/uuid" 12 | 13 | "github.com/MscBaiMeow/FishBot/float" 14 | l "github.com/MscBaiMeow/FishBot/mclogin" 15 | "github.com/Tnze/go-mc/bot" 16 | "github.com/Tnze/go-mc/chat" 17 | _ "github.com/Tnze/go-mc/data/lang/zh-cn" 18 | ygg "github.com/Tnze/go-mc/yggdrasil" 19 | "github.com/mattn/go-colorable" 20 | ) 21 | 22 | var ( 23 | c *bot.Client 24 | watch chan time.Time 25 | timeout int 26 | resp *ygg.Access 27 | auth l.Player 28 | version = "1.16.1" 29 | waiting bool 30 | ) 31 | 32 | func main() { 33 | var ( 34 | ip, name, account, authserver string 35 | port int 36 | realm, removemode bool 37 | uuid string 38 | ) 39 | log.SetOutput(colorable.NewColorableStdout()) 40 | flag.IntVar(&timeout, "t", 45, "自动重新抛竿时间") 41 | flag.StringVar(&ip, "ip", "", "服务器IP") 42 | flag.StringVar(&name, "name", "", "游戏ID") 43 | flag.IntVar(&port, "port", 25565, "端口,默认25565") 44 | flag.StringVar(&account, "account", "", "Mojang账号") 45 | flag.StringVar(&authserver, "auth", "https://authserver.mojang.com", "验证服务器(外置登陆)") 46 | flag.BoolVar(&realm, "realms", false, "加入领域服") 47 | flag.StringVar(&uuid, "uuid", "", "直接根据uuid读取配置文件进入游戏") 48 | flag.BoolVar(&removemode, "remove", false, "删除配置模式") 49 | flag.Parse() 50 | log.Println("自动钓鱼机器人启动!") 51 | log.Println("机器人版本:1.6.0") 52 | log.Printf("游戏版本:%s", version) 53 | log.Println("基于github.com/Tnze/go-mc") 54 | log.Println("作者: Tnze&BaiMeow") 55 | log.Println("-h参数以查看更多用法") 56 | if ip == "" && (!realm && !removemode) { 57 | log.Fatal("没有指定服务器IP,请使用-ip指定,或使用-realms进入领域") 58 | } 59 | net.CheckSRV(&ip, &port) 60 | switch { 61 | //验证登陆 62 | case account != "" && name == "" && uuid == "" && removemode == false: 63 | l.Authlogin(&account, &authserver, &auth) 64 | //盗版登陆 65 | case account == "" && name != "" && uuid == "" && removemode == false: 66 | auth.Name = name 67 | auth.Authmode = "Offline" 68 | //读取配置直接选择账户 69 | case account == "" && name == "" && uuid == "" && removemode == false: 70 | l.LoadConfiglogin(&auth) 71 | //没有输入登陆信息则读取配置询问账户 72 | case account == "" && name == "" && uuid != "" && removemode == false: 73 | l.Directlogin(uuid, &auth) 74 | case account == "" && name == "" && uuid == "" && removemode == true: 75 | l.Configrm() 76 | default: 77 | log.Fatal("格式错误:请使用以下四种格式之一\n验证登陆:AutoFish -account xxx \n盗版登陆:AutoFish -name xxx\n根据uuid读取配置登陆:AutoFish -uuid xxx\n读取配置询问登陆:AutoFish\n删除模式:AutoFish -remove") 78 | } 79 | 80 | c = bot.NewClient() 81 | c.SettingMapRead(false) 82 | c.Name, c.Auth.UUID, c.AsTk = auth.Name, auth.UUID, auth.Tokens.AccessToken 83 | l.AddtoConfig(&auth) 84 | //判断是否领域服登陆,整一个领域ip 85 | if realm && auth.Authmode != "Offline" { 86 | if err := l.Checkrealms(&ip, &port, c, &version, &auth); err != nil { 87 | log.Println(err) 88 | os.Exit(1) 89 | } 90 | } 91 | for { 92 | //Join Game 93 | err := c.JoinServer(ip, port) 94 | if err != nil { 95 | log.Fatal(err) 96 | } 97 | log.Println("Login success") 98 | go sendMsg() 99 | //Regist event handlers 100 | c.Events.GameStart = onGameStart 101 | c.Events.ChatMsg = onChatMsg 102 | c.Events.Disconnect = onDisconnect 103 | c.Events.SpawnObj = onSpawnObj 104 | c.Events.EntityRelativeMove = onEntityRelativeMove 105 | 106 | //JoinGame 107 | err = c.HandleGame() 108 | if err != nil { 109 | log.Fatal(err) 110 | } 111 | log.Println("Reconnect in 5s") 112 | time.Sleep(5 * time.Second) 113 | } 114 | } 115 | func sendMsg() error { 116 | var send []byte 117 | for { 118 | Reader := bufio.NewReader(os.Stdin) 119 | send, _, _ = Reader.ReadLine() 120 | if err := c.Chat(string(send)); err != nil { 121 | return err 122 | } 123 | } 124 | } 125 | 126 | func onGameStart() error { 127 | log.Println("Game start") 128 | watch = make(chan time.Time) 129 | go watchDog() 130 | time.Sleep(time.Second) 131 | err := c.Chat("Login with MscFishBot.") 132 | if err != nil { 133 | return err 134 | } 135 | return c.UseItem(0) 136 | } 137 | 138 | func onChatMsg(msg chat.Message, pos byte, sender uuid.UUID) error { 139 | log.Println("Chat:", msg.String()) 140 | return nil 141 | } 142 | 143 | func onDisconnect(msg chat.Message) error { 144 | log.Println("Disconnect:", msg) 145 | return nil 146 | } 147 | 148 | func watchDog() { 149 | to := time.NewTimer(time.Second * time.Duration(timeout)) 150 | for { 151 | select { 152 | case <-watch: 153 | case <-to.C: 154 | log.Println("rethrow") 155 | Held := c.HeldItem 156 | if err := c.SelectItem((Held + 1) % 9); err != nil { 157 | log.Printf("fail to select item:%s", err.Error()) 158 | } 159 | time.Sleep(time.Millisecond * 500) 160 | if err := c.SelectItem(Held); err != nil { 161 | panic(err) 162 | } 163 | time.Sleep(time.Millisecond * 500) 164 | if err := c.UseItem(0); err != nil { 165 | log.Printf("fail to use item:%s", err.Error()) 166 | } 167 | } 168 | to.Reset(time.Second * time.Duration(timeout)) 169 | } 170 | } 171 | 172 | func onSpawnObj(EID int, UUID [16]byte, Type int, x, y, z float64, Pitch, Yaw float32, Data int, VelocityX, VelocitY, VelocitZ int16) error { 173 | // fmt.Println(Type) 174 | if Type == 106 { 175 | if Data == c.EntityID { 176 | // log.Println("Spawn your Float") 177 | float.Set(EID, x, y, z) 178 | // } else { 179 | // log.Println("Other's Float") 180 | } 181 | } 182 | return nil 183 | } 184 | 185 | func onEntityRelativeMove(EID, DeltaX, DeltaY, DeltaZ int) error { 186 | if float.IsMine(EID) { 187 | if float.IsFish(DeltaX, DeltaY, DeltaZ) { 188 | getFish() 189 | } 190 | } 191 | return nil 192 | } 193 | 194 | func getFish() error { 195 | if err := c.UseItem(0); err != nil { //retrieve 196 | return err 197 | } 198 | log.Println("gra~") 199 | time.Sleep(time.Millisecond * time.Duration(timeout*8)) 200 | if err := c.UseItem(0); err != nil { //throw 201 | return err 202 | } 203 | watch <- time.Now() 204 | return nil 205 | } 206 | -------------------------------------------------------------------------------- /mclogin/login.go: -------------------------------------------------------------------------------- 1 | package mclogin 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | 10 | "github.com/AlecAivazis/survey/v2" 11 | "github.com/Tnze/go-mc/bot" 12 | ygg "github.com/Tnze/go-mc/yggdrasil" 13 | ) 14 | 15 | //Player is a profile of aplayer. 16 | type Player struct { 17 | Name string `json:"name"` 18 | UUID string `json:"UUID"` 19 | Tokens ygg.Tokens `json:"Tokens"` 20 | Account string `json:"account"` 21 | Authserver string `json:"authserver"` 22 | Authmode string `json:"authmode"` 23 | } 24 | 25 | //Config used to restore config in the program 26 | type Config struct { 27 | Players []Player `json:"players"` 28 | } 29 | 30 | var ( 31 | conf Config 32 | access ygg.Access 33 | ) 34 | 35 | //Authlogin is used when you need to login with passwd 36 | func Authlogin(account, authserver *string, auth *Player) { 37 | if *authserver != "https://authserver.mojang.com" { 38 | ygg.AuthURL = fmt.Sprintf("%s/authserver", *authserver) 39 | bot.SessionURL = fmt.Sprintf("%s/sessionserver/session/minecraft/join", *authserver) 40 | log.Println("第三方验证") 41 | auth.Authmode = "ThreeAuth" 42 | } else { 43 | auth.Authmode = "MojangAuth" 44 | } 45 | auth.Authserver = *authserver 46 | auth.Account = *account 47 | password := "" 48 | prompt := &survey.Password{ 49 | Message: "Please type your password", 50 | } 51 | survey.AskOne(prompt, &password) 52 | access, err := ygg.Authenticate(*account, string(password)) 53 | if err != nil { 54 | fmt.Println(err) 55 | os.Exit(1) 56 | } 57 | log.Println("Auth success") 58 | if len(access.AvailableProfiles()) != 1 { 59 | //多用户选择、登陆 60 | var ( 61 | no int 62 | preSelected []string 63 | selected string 64 | ) 65 | //把安排survey包的单选中的选项所需要的切片搞出来 66 | for _, v := range access.AvailableProfiles() { 67 | preSelected = append(preSelected, fmt.Sprintf("[%d]", no)+v.Name) 68 | no++ 69 | } 70 | //让玩家进行选择 71 | prompt := &survey.Select{ 72 | Message: "选择一个角色:", 73 | Options: preSelected, 74 | } 75 | survey.AskOne(prompt, &selected) 76 | //获得选中的用户的序号 77 | fmt.Sscanf(selected, "[%d]", &no) 78 | //refresh刷新获得该用户AsTk 79 | if err = access.Refresh(&access.AvailableProfiles()[no]); err != nil { 80 | log.Fatal(err) 81 | os.Exit(1) 82 | 83 | } 84 | } 85 | //安排登陆账户 86 | auth.UUID, auth.Name = access.SelectedProfile() 87 | auth.Tokens = access.GetTokens() 88 | return 89 | } 90 | 91 | //Loadconf is used to load Config from file 92 | func Loadconf() Config { 93 | data, err := ioutil.ReadFile("./conf.json") 94 | if err != nil { 95 | if os.IsNotExist(err) { 96 | log.Fatal("配置文件不存在,请使用-account参数添加", err) 97 | os.Exit(1) 98 | } 99 | log.Fatal(err) 100 | os.Exit(1) 101 | } 102 | err = json.Unmarshal(data, &conf) 103 | if err != nil { 104 | log.Fatal(err) 105 | } 106 | return conf 107 | } 108 | 109 | //LoadConfiglogin can load config and ask you to choose a profile and login 110 | func LoadConfiglogin(auth *Player) { 111 | var conf = Loadconf() 112 | log.Println("成功读取配置") 113 | //让玩家选一个 114 | var ( 115 | selected string 116 | i = 0 117 | preSelected []string 118 | selectedNo int 119 | ) 120 | for _, v := range conf.Players { 121 | preSelected = append(preSelected, fmt.Sprintf("[%d]", i)+v.Name+"\t"+v.Authmode+"\t"+v.Authserver) 122 | i++ 123 | } 124 | prompt := &survey.Select{ 125 | Message: "选择一个账户:", 126 | Options: preSelected, 127 | } 128 | survey.AskOne(prompt, &selected) 129 | fmt.Sscanf(selected, "[%d]", &selectedNo) 130 | *auth = conf.Players[selectedNo] 131 | //检查登陆类型 132 | switch auth.Authmode { 133 | case "Offline": 134 | return 135 | case "MojangAuth": 136 | //检测asTk是否有效 137 | access.SetTokens(auth.Tokens) 138 | ok, err := access.Validate() 139 | if err != nil { 140 | log.Fatal(err) 141 | os.Exit(1) 142 | } 143 | if ok == true { 144 | return 145 | } 146 | Authlogin(&auth.Account, &auth.Authserver, auth) 147 | case "ThreeAuth": 148 | ygg.AuthURL = fmt.Sprintf("%s/authserver", auth.Authserver) 149 | bot.SessionURL = fmt.Sprintf("%s/sessionserver/session/minecraft/join", auth.Authserver) 150 | access.SetTokens(auth.Tokens) 151 | ok, err := access.Validate() 152 | if err != nil { 153 | log.Fatal(err) 154 | os.Exit(1) 155 | } 156 | if ok == true { 157 | return 158 | } 159 | Authlogin(&auth.Account, &auth.Authserver, auth) 160 | default: 161 | log.Fatal("未知验证模式") 162 | os.Exit(1) 163 | } 164 | } 165 | 166 | //AddtoConfig is used to update the config file with a provided profile 167 | func AddtoConfig(auth *Player) { 168 | //文件不存在 169 | _, err := os.Stat("conf.json") 170 | if os.IsNotExist(err) { 171 | conf.Players = append(conf.Players, *auth) 172 | data, _ := json.Marshal(conf) 173 | var d1 = []byte(data) 174 | err := ioutil.WriteFile("conf.json", d1, 0666) 175 | if err != nil { 176 | log.Fatal(err) 177 | os.Exit(1) 178 | } 179 | return 180 | } 181 | //文件存在 182 | conf = Loadconf() 183 | var i = 0 184 | //判断是否已存在该角色 185 | for _, v := range conf.Players { 186 | //判断验证模式 187 | if v.Authmode == "Offline" { 188 | //判断是否同一个账号 189 | if auth.Name == v.Name { 190 | return 191 | } 192 | } else { 193 | //判断是否同一个账号 194 | if auth.UUID == v.UUID { 195 | //判断是否需要更新AsTk 196 | if auth.Tokens != v.Tokens { 197 | break 198 | } 199 | return 200 | } 201 | } 202 | i++ 203 | } 204 | if i == len(conf.Players) { 205 | conf.Players = append(conf.Players, *auth) 206 | } else { 207 | conf.Players[i].Tokens = auth.Tokens 208 | } 209 | //替换配置文件 210 | data, _ := json.Marshal(conf) 211 | var d1 = []byte(data) 212 | if err := os.Remove("conf.json"); err != nil { 213 | log.Fatal(err) 214 | os.Exit(1) 215 | } 216 | err = ioutil.WriteFile("conf.json", d1, 0666) 217 | if err != nil { 218 | log.Fatal(err) 219 | os.Exit(1) 220 | } 221 | } 222 | 223 | //Directlogin is used to load config and login according to the uuid 224 | func Directlogin(uuid string, auth *Player) { 225 | log.Println("根据UUID读取配置") 226 | conf = Loadconf() 227 | for _, v := range conf.Players { 228 | if v.UUID == uuid { 229 | log.Println("在配置文件中找到该角色") 230 | *auth = v 231 | if auth.Authmode == "ThreeAuth" { 232 | ygg.AuthURL = fmt.Sprintf("%s/authserver", auth.Authserver) 233 | bot.SessionURL = fmt.Sprintf("%s/sessionserver/session/minecraft/join", auth.Authserver) 234 | } 235 | access.SetTokens(auth.Tokens) 236 | ok, err := access.Validate() 237 | if err != nil { 238 | log.Fatal(err) 239 | os.Exit(1) 240 | } 241 | if ok != true { 242 | log.Println("无效的AccessToken") 243 | //refresh 244 | log.Println("正在刷新AccessToken") 245 | err = access.Refresh(&ygg.Profile{ 246 | ID: auth.UUID, 247 | Name: auth.Name, 248 | }) 249 | //救不了,只能重新登录 250 | if err != nil { 251 | log.Println("刷新AccessToken失败,请重新输入密码") 252 | Authlogin(&auth.Account, &auth.Authserver, auth) 253 | return 254 | } 255 | auth.Tokens = access.GetTokens() 256 | return 257 | } 258 | return 259 | } 260 | } 261 | log.Fatal("未记录的UUID,请使用-account添加登录") 262 | } 263 | 264 | //Configrm means remove-mode 265 | func Configrm() { 266 | conf := Loadconf() 267 | var ( 268 | selected string 269 | i = 0 270 | preSelected []string 271 | selectedNo int 272 | ) 273 | for _, v := range conf.Players { 274 | preSelected = append(preSelected, fmt.Sprintf("[%d]", i)+v.Name+"\t"+v.Authmode+"\t"+v.Authserver) 275 | i++ 276 | } 277 | prompt := &survey.Select{ 278 | Message: "选择你要删除的账户:", 279 | Options: preSelected, 280 | } 281 | survey.AskOne(prompt, &selected) 282 | fmt.Sscanf(selected, "[%d]", &selectedNo) 283 | conf.Players = append(conf.Players[:selectedNo], conf.Players[selectedNo+1:]...) 284 | data, _ := json.Marshal(conf) 285 | var d1 = []byte(data) 286 | if err := os.Remove("conf.json"); err != nil { 287 | log.Fatal(err) 288 | os.Exit(1) 289 | } 290 | err := ioutil.WriteFile("conf.json", d1, 0666) 291 | if err != nil { 292 | log.Fatal(err) 293 | os.Exit(1) 294 | } 295 | name := false 296 | prompt1 := &survey.Confirm{ 297 | Message: "已删除选择账户,继续删除账户?", 298 | } 299 | survey.AskOne(prompt1, &name) 300 | if name == true { 301 | Configrm() 302 | } 303 | os.Exit(1) 304 | } 305 | --------------------------------------------------------------------------------