Merge pull request #94 from yuanyan3060/master

添加 golang接口
This commit is contained in:
MistEO
2022-01-05 12:35:56 +08:00
committed by GitHub
8 changed files with 635 additions and 4 deletions

View File

@@ -22,7 +22,10 @@
## MuMu 模拟器
支持。但在部分设备上可能莫名其妙连接出错,可尝试使用自定义连接
支持,但是
- 部分设备上一直连接出错:暂时不知道是什么原因,可尝试使用自定义连接
- 部分设备上卡在主界面无法识别,过一会提示任务出错:暂时不知道是什么原因,可能和 MuMu 的渲染方式有关,推荐换模拟器(
## MuMu 手游助手(星云引擎)
@@ -46,6 +49,7 @@
## 自定义连接
- 下载 [ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
- 进入软件`设置`-`连接设置`填写自定义地址需要填写IP+端口,例如`127.0.0.1:5555`
- **注意 :** 若是使用手机,在非`16:9`分辨率下,部分功能不稳定(但也凑合能用),尤其是基建,几乎是不可用状态,正在进一步适配中。推荐使用`16:9`分辨率,经过的测试验证最多,也最稳定。
1. 下载 [ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
2. 进入软件`设置`-`连接设置`填写自定义地址需要填写IP+端口,例如`127.0.0.1:5555`
**注意 :** 若是使用手机,在非`16:9`分辨率下,部分功能不稳定(但也凑合能用),尤其是基建,几乎是不可用状态,正在进一步适配中。推荐使用`16:9`分辨率,经过的测试验证最多,也最稳定。

42
src/Golang/cli.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
"errors"
"gomma/maa"
"os"
"runtime"
)
func main() {
dir, err := os.Getwd()
if err != nil {
return
}
config, err := maa.LoadConfig("config.yaml")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
config = maa.NewConfig()
err := maa.WriteConfig("config.yaml", config)
if err != nil {
return
}
} else {
return
}
}
if runtime.GOOS == "windows" {
MaaWin, err := maa.NewMaaCliWin(dir)
if err != nil {
return
}
err = MaaWin.Run(config)
if err != nil {
return
}
err = MaaWin.RunWithCron(config)
if err != nil {
return
}
for true {}
}
}

32
src/Golang/config.yaml Normal file
View File

@@ -0,0 +1,32 @@
customadbaddress: ""
cron: "0 0 */2 * * *"
fight:
stage: LastBattle
medicine: 999
stone: 0
times: 999
infrast:
mode: 1
orders:
- Mfg
- Trade
- Control
- Power
- Reception
- Office
- Dorm
drones: Money
threshold: 0.3
recruit:
max: 3
selects:
- 3
- 4
- 5
confirms:
- 3
- 4
- 5
refresh: true
mall:
buy: true

16
src/Golang/go.sum Normal file
View File

@@ -0,0 +1,16 @@
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
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=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

85
src/Golang/maa/config.go Normal file
View File

@@ -0,0 +1,85 @@
package maa
import (
"gopkg.in/yaml.v2"
"io/ioutil"
)
type Config struct {
CustomAdbAddress string
Cron string
Fight struct{
Stage string
Medicine int
Stone int
Times int
}
Infrast struct{
Mode int
Orders []string
Drones string
Threshold float64
}
Recruit struct{
Max int
Selects []int
Confirms []int
Refresh bool
Expedite bool
}
Mall struct{
Buy bool
}
}
func NewConfig() Config {
return Config{
CustomAdbAddress: "",
Cron: "0 0 */2 * * *",
Fight: struct {
Stage string
Medicine int
Stone int
Times int
}{Stage: "LastBattle", Medicine: 999, Stone: 0, Times: 999},
Infrast: struct {
Mode int
Orders []string
Drones string
Threshold float64
}{Mode: 1, Orders:[]string{"Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm"}, Drones: "Money", Threshold: 0.3},
Recruit: struct {
Max int
Selects []int
Confirms []int
Refresh bool
Expedite bool
}{Max: 3, Selects: []int{3,4,5}, Confirms: []int{3,4,5}, Refresh: true, Expedite: true},
Mall: struct{ Buy bool }{Buy: true},
}
}
func LoadConfig(path string) (Config, error) {
conf := Config{}
yamlFile, err := ioutil.ReadFile(path)
if err != nil {
return conf, err
}
err = yaml.Unmarshal(yamlFile, &conf)
if err != nil {
return conf, err
}
return conf, nil
}
func WriteConfig(path string, conf Config) error {
yamlFile, err := yaml.Marshal(&conf)
if err != nil {
return err
}
err = ioutil.WriteFile(path, yamlFile, 0755)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,23 @@
package maa
type Maa interface {
CallBack(message int, details uintptr, arg uintptr) uintptr
CreateEx(arg uintptr) error
CatchDefault() error
CatchEmulator() error
CatchCustom(address string) error
AppendFight(stage string, medicine int, stone int, times int) error
AppendAward() error
AppendVisit() error
AppendMall(do bool) error
AppendInfrast(mode int, orders []string, drones string, threshold float64) error
AppendRecruit(max int, selects []int, confirms []int, refresh bool, expedite bool) error
Start() error
Stop() error
StartRecruitCalc(selects []int, times bool) error
GetVersion() (string, error)
SetPenguinId(id string) error
Run(config Config) error
RunWithCron(config Config) error
}

40
src/Golang/maa/util.go Normal file
View File

@@ -0,0 +1,40 @@
package maa
import "C"
import (
"errors"
"syscall"
"unsafe"
)
var FalseError = errors.New("maa return false")
func UintPtrFromString(s string) (uintptr, error) {
p, err := syscall.BytePtrFromString(s)
if err != nil {
return 0, err
}
return uintptr(unsafe.Pointer(p)), nil
}
func CharPtr2String(r uintptr) string {
if r==0{
return ""
}
p := (*byte)(unsafe.Pointer(r))
data := make([]byte, 0)
for *p != 0 {
data = append(data, *p)
r += unsafe.Sizeof(byte(0))
p = (*byte)(unsafe.Pointer(r))
}
name := string(data)
return name
}
func UintPtrFromBool(b bool) uintptr {
if b{
return 1
}else {
return 0
}
}

389
src/Golang/maa/win.go Normal file
View File

@@ -0,0 +1,389 @@
package maa
import (
"errors"
"fmt"
"github.com/robfig/cron"
log "github.com/sirupsen/logrus"
"syscall"
"unsafe"
)
type MaaCliWin struct {
Path string
DLL *syscall.DLL
Ptr uintptr
}
func NewMaaCliWin(path string) (*MaaCliWin, error) {
dll, err := syscall.LoadDLL(path + "/MeoAssistant.dll")
if err != nil {
return nil, err
}
maa := MaaCliWin{path, dll, 0}
err = maa.CreateEx(0)
if err != nil {
return nil, err
}
return &maa, nil
}
func (m *MaaCliWin) CallBack(message int, details uintptr, arg uintptr) uintptr {
log.Infoln(message, CharPtr2String(details), arg)
return 0
}
func (m *MaaCliWin) CreateEx(arg uintptr) error {
proc, err := m.DLL.FindProc("AsstCreateEx")
if err != nil {
return err
}
a1, err := UintPtrFromString(m.Path)
if err != nil {
return err
}
a2 := syscall.NewCallback(m.CallBack)
a3 := arg
r1, _, err := proc.Call(a1, a2, a3)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("CreateEx", err)
}
m.Ptr = r1
return nil
}
func (m *MaaCliWin) CatchDefault() error {
proc, err := m.DLL.FindProc("AsstCatchDefault")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("CatchDefault", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) CatchEmulator() error {
proc, err := m.DLL.FindProc("AsstCatchEmulator")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("CatchEmulator", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
// CatchCustom 没测过
func (m *MaaCliWin) CatchCustom(address string) error {
proc, err := m.DLL.FindProc("AsstCatchCustom")
if err != nil {
return err
}
a1, err := UintPtrFromString(address)
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr, a1)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("CatchCustom", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendFight(stage string, medicine int, stone int, times int) error {
proc, err := m.DLL.FindProc("AsstAppendFight")
if err != nil {
return err
}
a1, err := UintPtrFromString(stage)
if err != nil {
return err
}
a2 := uintptr(medicine)
a3 := uintptr(stone)
a4 := uintptr(times)
r1, _, err := proc.Call(m.Ptr, a1, a2, a3, a4)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("AppendFight", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendAward() error {
proc, err := m.DLL.FindProc("AsstAppendAward")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn(" AppendAward", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendVisit() error {
proc, err := m.DLL.FindProc("AsstAppendVisit")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("AppendVisit", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendMall(do bool) error {
proc, err := m.DLL.FindProc("AsstAppendMall")
if err != nil {
return err
}
a1:=UintPtrFromBool(do)
r1, _, err := proc.Call(m.Ptr, a1)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("AppendMall", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendInfrast(mode int, orders []string, drones string, threshold float64) error {
proc, err := m.DLL.FindProc("AsstAppendInfrast")
if err != nil {
return err
}
var orderArr []uintptr
for _, order := range orders {
orderStr, err := UintPtrFromString(order)
if err != nil {
return err
}
orderArr = append(orderArr, orderStr)
}
if orderArr == nil {
return errors.New("orders is empty")
}
a1 := uintptr(mode)
a2 := uintptr(unsafe.Pointer(&orderArr[0]))
a3 := uintptr(len(orders))
a4 := uintptr(unsafe.Pointer(&[]byte(drones)[0]))
a5 := uintptr(*(*uint64)(unsafe.Pointer(&threshold)))
r1, _, err := proc.Call(m.Ptr, a1, a2, a3, a4, a5)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("AppendInfrast", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) AppendRecruit(max int, selects []int, confirms []int, refresh bool, expedite bool) error {
proc, err := m.DLL.FindProc("AsstAppendRecruit")
if err != nil {
return err
}
a1 := uintptr(max)
a2 := uintptr(unsafe.Pointer(&selects[0]))
a3 := uintptr(len(selects))
a4 := uintptr(unsafe.Pointer(&confirms[0]))
a5 := uintptr(len(confirms))
a6:=UintPtrFromBool(refresh)
a7:=UintPtrFromBool(expedite)
r1, _, err := proc.Call(m.Ptr, a1, a2, a3, a4, a5, a6, a7)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("AppendRecruit", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) Start() error {
proc, err := m.DLL.FindProc("AsstStart")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("Start", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) Stop() error {
proc, err := m.DLL.FindProc("AsstStop")
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("Stop", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) StartRecruitCalc(selects []int, times bool) error {
proc, err := m.DLL.FindProc("AsstStartRecruitCalc")
if err != nil {
return err
}
a1 := uintptr(unsafe.Pointer(&selects[0]))
a2:=UintPtrFromBool(times)
r1, _, err := proc.Call(m.Ptr, a1, a2)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("StartRecruitCalc", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) GetVersion() (string, error) {
proc, err := m.DLL.FindProc("AsstGetVersion")
if err != nil {
return "", err
}
r1, _, err := proc.Call(m.Ptr)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("GetVersion", err)
}
if r1 == 0 {
return "", FalseError
}
return CharPtr2String(r1), nil
}
func (m *MaaCliWin) SetPenguinId(id string) error {
proc, err := m.DLL.FindProc("AsstSetPenguinId")
if err != nil {
return err
}
a1, err := UintPtrFromString(id)
if err != nil {
return err
}
r1, _, err := proc.Call(m.Ptr, a1)
if !errors.Is(err, syscall.Errno(0)) {
log.Warn("SetPenguinId", err)
}
if r1 == 0 {
return FalseError
}
return nil
}
func (m *MaaCliWin) Run(config Config) error {
version, err := m.GetVersion()
if err != nil {
return err
}
log.Infoln("DLL版本:", version)
// 连接模拟器
if config.CustomAdbAddress != "" {
err := m.CatchCustom(config.CustomAdbAddress)
log.Infoln("连接自定义模拟器", config.CustomAdbAddress)
if err != nil {
log.Error("连接自定义模拟器失败", err)
return err
}
} else {
err := m.CatchDefault()
log.Infoln("连接默认模拟器", config.CustomAdbAddress)
if err != nil {
log.Error("连接默认模拟器失败", err)
return err
}
}
// 添加战斗任务
fight := config.Fight
err = m.AppendFight(fight.Stage, fight.Medicine, fight.Stone, fight.Times)
if err != nil {
return err
}
log.Println("添加战斗任务")
// 添加基建任务
infrast := config.Infrast
err = m.AppendInfrast(infrast.Mode, infrast.Orders, infrast.Drones, infrast.Threshold)
if err != nil {
return err
}
log.Println("添加基建任务")
// 添加公招任务
recruit := config.Recruit
err = m.AppendRecruit(recruit.Max, recruit.Selects, recruit.Confirms, recruit.Refresh, recruit.Expedite)
if err != nil {
return err
}
log.Println("添加公招任务")
// 添加访问好友任务
err = m.AppendVisit()
if err != nil {
return err
}
log.Println("添加访问好友任务")
// 添加商店任务
err = m.AppendMall(config.Mall.Buy)
if err != nil {
return err
}
log.Println("添加商店任务")
// 添加领取任务奖励任务
err = m.AppendAward()
log.Println("添加领取奖励任务")
if err != nil {
return err
}
err = m.Start()
log.Println("开始执行任务")
if err != nil {
return err
}
return nil
}
func (m *MaaCliWin) RunWithCron(config Config) error {
c := cron.New() // 新建一个定时任务对象
err := c.AddFunc(config.Cron, func() {
log.Println(config.Cron, "定时任务开始执行")
err := m.Run(config)
if err != nil {
return
}
})
if err != nil {
fmt.Println(err)
return err
}
c.Start()
log.Infoln("设置定时任务")
return nil
}