最近在開(kāi)發(fā)蘑菇博客的時(shí)候,需要啟動(dòng)的服務(wù)比較多,比如nginx,solr,redis,mysql等,我就想著在Windows平臺(tái)能不能編寫個(gè)腳本,讓它們一鍵啟動(dòng)
當(dāng)然小伙伴可以把它們注冊(cè)成系統(tǒng)服務(wù),然后設(shè)置開(kāi)機(jī)自啟,更加省時(shí)省力,現(xiàn)在做的是將他們寫在bat腳本上
# /b 代表后臺(tái)啟動(dòng)
start /b server
我們首先創(chuàng)建一個(gè) startup.bat文件,然后輸出下面的內(nèi)容
start /d java -jar zipkin.jar
這樣他就會(huì)幫我們啟動(dòng)zipikin服務(wù)了,我們?cè)O(shè)置多個(gè),即可完成項(xiàng)目的一鍵啟動(dòng)
start java -jar E:/Software/Zipkin/zipkin.jar
start E:/Software/nginx/nginx.exe
start E:/Software/redis/Redis-x64-3.2.100/redis-server.exe
start E:/Software/xampp/tomcat/bin/startup.bat
start E:/Software/xampp/mysql/bin/mysqld.exe
本教程為新手學(xué)習(xí)python教程
廢話少說(shuō),下面開(kāi)始python教程
我們先用tkinter搭建好腳本的基本界面
私信小編01即可獲取大量Python學(xué)習(xí)資源
import tkinter as tk#[size=3]首先導(dǎo)入tkinter,需要事先用pip安裝進(jìn)python里(方法自行百度)[/size]
def init_window():
global cs,wd
wd = tk.Tk()
cs = tk.Canvas(wd,
width = 800,
height = 500,
bg = 'white')
wd.minsize(800, 500) # 最小尺寸
wd.maxsize(800, 500)#最大尺寸,使最大化失效
wd.title('DDTHelper')
pic = tk.PhotoImage(file="pic.png")#設(shè)置背景圖片,最好是800*500和png格式的
cs.create_image(400,250,image = pic)
cs.pack()
bt = tk.Button(wd,
text='初始化',
bg=('white'),
font=('微軟雅黑',20),
width=155,
height=48,
command=BT_onCreat)
bt.pack()
cs.create_window(530,70,
width=155,
height=48,
window=bt)
wd.mainloop()
def BT_onCreat():
print("初始化。。。")
#入口,這行代碼需要一直都待在腳本的最底下
#設(shè)置字典
hwnd_title = dict()
init_window()
(不過(guò)在圖片上疊加控件其實(shí)有更好的方案,使控件的背景為透明的,但是那篇文章的代碼運(yùn)行不來(lái))
運(yùn)行效果
現(xiàn)在我們?yōu)辄c(diǎn)擊 初始化 按鈕添加一些事項(xiàng)
讓他在被點(diǎn)擊的時(shí)候識(shí)別當(dāng)前的游戲窗口
(因?yàn)槲矣玫氖?6jb大廳登錄的游戲,抓取句柄的時(shí)候可以根據(jù)他的title來(lái)區(qū)別游戲窗口)
這里我偷了個(gè)懶,利用該登錄器游戲窗口的title來(lái)獲取
更改上面的導(dǎo)入庫(kù)和 BT_onCreat()方法
import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn#需要事先用pip安裝pywin32插件進(jìn)python里(方法自行百度)
def init_window():
global cs,wd
wd = tk.Tk()
cs = tk.Canvas(wd,
width = 800,
height = 500,
bg = 'white')
wd.minsize(800, 500) # 最小尺寸
wd.maxsize(800, 500)#最大尺寸,使最大化失效
wd.title('DDTHelper')
pic = tk.PhotoImage(file="pic.png")#設(shè)置背景圖片,最好是800*500和png格式的
cs.create_image(400,250,image = pic)
cs.pack()
bt = tk.Button(wd,
text='初始化',
bg=('white'),
font=('微軟雅黑',20),
width=155,
height=48,
command=BT_onCreat)
bt.pack()
cs.create_window(530,70,
width=155,
height=48,
window=bt)
wd.mainloop()
def BT_onCreat():
global is_run,Znum,t1,t2,t3
Znum = 0#當(dāng)前已經(jīng)登陸的游戲賬號(hào)數(shù)量
wg.EnumWindows(get_all_hwnd, 0)
for h,t in hwnd_title.items():
if "4399" in t:#根據(jù)title里包含的 4399 來(lái)提取游戲窗口
hwnd = t.split("|")[3]
name = t.split("|")[2]
print("賬號(hào):" + name + "句柄:" + hwnd)
Znum = Znum + 1
hwnd = int(hwnd)#將句柄轉(zhuǎn)化為int,因?yàn)榫浔菑臉?biāo)題獲取的string,導(dǎo)致了類型錯(cuò)誤,我就是被這個(gè)坑了好久。。
if Znum==1:#為每一個(gè)游戲界面創(chuàng)建一個(gè)單獨(dú)的操作線程,為了方便用global傳遞,沒(méi)有用exec。
t1 = xc.Thread(target=Con,args=(hwnd,name,Znum))
elif Znum==2:
t2 = xc.Thread(target=Con,args=(hwnd,name,Znum))
elif Znum==3:
t3 = xc.Thread(target=Con,args=(hwnd,name,Znum))
init_control(Znum,name)
#下面再添加幾個(gè)方法進(jìn)去
#獲取句柄用的
def get_all_hwnd(hwnd,mouse):
if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
#為每一個(gè)線程創(chuàng)建一個(gè)對(duì)應(yīng)的控件來(lái)控制線程的運(yùn)行
def init_control(Znum,name):
global cs,wd,v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
if Znum==1:
v1=tk.IntVar()
tx1=tk.StringVar()
txn1=tk.StringVar()
elif Znum==2:
v2=tk.IntVar()
tx2=tk.StringVar()
txn2=tk.StringVar()
elif Znum==3:
v3=tk.IntVar()
tx3=tk.StringVar()
txn3=tk.StringVar()
exec('tx{}.set("未運(yùn)行")'.format(Znum))
exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
exec('cb{}.pack()'.format(Znum))
exec('lb{}.pack()'.format(Znum))
exec('lbn{}.pack()'.format(Znum))
Ytmp=Znum*100
Ytmp=Ytmp+70
exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
Ytmp=Ytmp+40
exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
#線程方法
def Con(hwnd,name,xc):
print("啟動(dòng)成功")
#多選框點(diǎn)擊事件
def BT_onRun1():
global v1,tx1,t1,ct1
if v1.get()==1:#判斷是否被選中
ct1=0
tx1.set('正運(yùn)行')
t1.start()
else:
ct1=1#用來(lái)控制線程終止
tx1.set('未運(yùn)行')
def BT_onRun2():
global v2,tx2,ct2
if v2.get()==1:#判斷是否被選中
ct2=0
tx2.set('正運(yùn)行')
t2.start()
else:
ct2 = 1
tx2.set('未運(yùn)行')
def BT_onRun3():
global v3,tx3,ct3
if v3.get()==1:#判斷是否被選中
ct3=0
tx3.set('正運(yùn)行')
t3.start()
else:
ct3=1
tx3.set('未運(yùn)行')
#入口,這行代碼需要一直都待在腳本的最底下
#設(shè)置字典
hwnd_title = dict()
init_window()
運(yùn)行后,點(diǎn)擊初始化的效果
可以看到,當(dāng)只有一個(gè)游戲窗口的時(shí)候,腳本就自動(dòng)識(shí)別出了該游戲窗口。(目前最多識(shí)別3個(gè),且不能二次點(diǎn)擊初始化,否則會(huì)報(bào)錯(cuò)。聽(tīng)說(shuō)用exce動(dòng)態(tài)封裝線程時(shí)可以用dict來(lái)接收,而目前二次識(shí)別也有了大致方案)
并在勾選 未運(yùn)行 旁邊的 框框 時(shí),運(yùn)行對(duì)應(yīng)的線程。
接下來(lái)就要到腳本的線程模塊了,而有過(guò)py基礎(chǔ)的人都知道,py的線程是沒(méi)有stopThread的
但我們將要實(shí)現(xiàn)如何控制腳本執(zhí)行游戲操作的線程,讓它收放自如
下面教程開(kāi)始
因?yàn)榻酉聛?lái)的腳本是精簡(jiǎn)過(guò)的,和上次帖子略有不同,以這次帖子為準(zhǔn)
我們先像上個(gè)帖子一樣搭建好一個(gè)界面的代碼,以此作為平臺(tái)
import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn,multiprocessing as jc
def init_window():
global cs,wd
wd = tk.Tk()
cs = tk.Canvas(wd,
width = 800,
height = 500,
bg = 'white')
wd.minsize(800, 500) # 最小尺寸
wd.maxsize(800, 500)
wd.title('DDTHelper')
pic = tk.PhotoImage(file="pic.png")
cs.create_image(400,250,image = pic)
cs.pack()
bt = tk.Button(wd,
text='初始化',
bg=('white'),
font=('微軟雅黑',20),
width=155,
height=48,
command=BT_onCreat)
bt.pack()
cs.create_window(530,70,
width=155,
height=48,
window=bt)
wd.mainloop()
def init_control(Znum,name):
global v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
if Znum==1:
v1=tk.IntVar()
tx1=tk.StringVar()
#txn1=tk.StringVar()
elif Znum==2:
v2=tk.IntVar()
tx2=tk.StringVar()
#txn2=tk.StringVar()
elif Znum==3:
v3=tk.IntVar()
tx3=tk.StringVar()
#txn3=tk.StringVar()
exec('tx{}.set("未運(yùn)行")'.format(Znum))
exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
#exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
exec('cb{}.pack()'.format(Znum))
exec('lb{}.pack()'.format(Znum))
#exec('lbn{}.pack()'.format(Znum))
Ytmp=Znum*100
Ytmp=Ytmp+70
exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
Ytmp=Ytmp+40
#exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
def BT_onCreat():
global Znum,D1,D2,D3,conT
Znum = 0
wg.EnumWindows(get_all_hwnd, 0)
conT=jc.Manager().Array("i",[3,0,0,0])#用來(lái)控制進(jìn)程
#lock = jc.Lock()#用來(lái)給進(jìn)程運(yùn)行順序排序,防止顯示錯(cuò)亂,打包成exe時(shí)可以去除(如果出現(xiàn)錯(cuò)誤 windos 什么的就改成lock = jc.Manager.Lock() 這樣就可以了,或者刪掉Manager)
#lock不穩(wěn)定,棄用
for h,t in hwnd_title.items():
if "4399" in t:
hwnd = t.split("|")[3]
name = t.split("|")[2]
print("賬號(hào):" + name + "句柄:" + hwnd)
Znum = Znum + 1
hwnd = int(hwnd)
init_control(Znum,name)
if Znum==1:
D1 = jc.Manager().Array("i",[1,hwnd])
elif Znum==2:
D2 = jc.Manager().Array("i",[2,hwnd])
elif Znum==3:
D3 = jc.Manager().Array("i",[3,hwnd])
def get_all_hwnd(hwnd,mouse):
if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
def Con(data,conT):
#l.acquire()#鎖
#try:
print("運(yùn)行成功")
#finally:
#l.release()
def onRunMan(Znum):
if onRunMan2(Znum) == 1:
conT[Znum]=0
exec('p{} = jc.Process(target=Con,args=(D{},conT))'.format(Znum,Znum))
exec('p{}.daemon=True'.format(Znum))
exec('tx{}.set("運(yùn)行中")'.format(Znum))
exec('p{}.start()'.format(Znum))
else:
conT[Znum]=1
exec('tx{}.set("未運(yùn)行")'.format(Znum))
def onRunMan2(Znum):
if Znum ==1:
return v1.get()
elif Znum == 2:
return v2.get()
elif Znum ==3:
return v3.get()
def BT_onRun1():
onRunMan(1)
def BT_onRun2():
onRunMan(2)
def BT_onRun3():
onRunMan(3)
if __name__ == '__main__':
hwnd_title = dict()
init_window()
成功識(shí)別后,我們勾上運(yùn)行的鉤子
成功的話會(huì)在終端顯示 成功運(yùn)行
這次我在onCreat方法里封裝需要發(fā)送給進(jìn)程的數(shù)據(jù)
然后在onRunMain中動(dòng)態(tài)拼裝進(jìn)程并啟動(dòng)它
再讓產(chǎn)生的子進(jìn)程來(lái)生成守護(hù)線程,讓守護(hù)線程去操控游戲
然后子進(jìn)程循環(huán)檢測(cè)我們是不是發(fā)出了停止命令,如果線程檢測(cè)到我們發(fā)出了停止的命令
自身的代碼就執(zhí)行完了,然后帶動(dòng)他產(chǎn)生的守護(hù)線程也被kill掉了。
這樣就可以實(shí)現(xiàn)多線程的隨時(shí)停止了
代碼還巧妙借用了exec指令的“特性”:輸出變量只能在該方法內(nèi)可見(jiàn),一旦該方法被重啟,變量就沒(méi)了
也就是說(shuō),如果我們直接用 p1 = jc.Process(target=Con,args=(D1,conT))來(lái)產(chǎn)生進(jìn)程
那么在進(jìn)程結(jié)束后,需要用 del p1來(lái)清除掉進(jìn)程的“尸體”,然后再重新創(chuàng)建它
設(shè)置的Con方法代碼,讓它會(huì)自己生產(chǎn)守護(hù)線程
def Con(hwnd,Znum,conT,l):
#設(shè)置守護(hù)線程
time.sleep(1)
exec('t{} = xc.Thread(target=RunMain,args=(hwnd,Znum))'.format(Znum))#依靠Znum(游戲賬號(hào)分配到的id)來(lái)動(dòng)態(tài)生成不同的線程
exec('t{}.setDaemon(True)'.format(Znum))
exec('t{}.start()'.format(Znum))
while True:#開(kāi)始接收我們是否發(fā)出了停止的命令
if conT[Znum] == 0:
time.sleep(1)
else:
break
print('進(jìn)程' + str(Znum) +':已退出')
再補(bǔ)充它生產(chǎn)出的子線程所執(zhí)行的方法(不可用)
def RunMain(hwnd,Znum):
RM=0#運(yùn)行次數(shù),因?yàn)橛枚噙M(jìn)程后無(wú)法向用戶節(jié)目輸出,所以已棄用
hdc=wg.GetWindowDC(int(hwnd))#獲取目標(biāo)頁(yè)游(flash)的hdc,用來(lái)獲取指定坐標(biāo)的顏色
while True:
while str(wg.GetPixel(hdc,919,280))!=str(10248996):#檢測(cè)游戲角色是否處在房間界面(初始需要用戶手動(dòng)將游戲角色進(jìn)入房間界面),用于檢測(cè)游戲角色是否退出了副本回到了游戲房間
print("房間")
doClick(hwnd,5,5)
time.sleep(1)
if Chose_FB(hwnd,hdc) == 1:#查看當(dāng)前兩個(gè)副本中又那個(gè)副本開(kāi)放,其實(shí)這個(gè)設(shè)計(jì)并不合理,如果當(dāng)前沒(méi)副本開(kāi)放就出bug了,不過(guò)我只會(huì)在有副本開(kāi)放才會(huì)運(yùn)行這個(gè)腳本對(duì)吧-,-
FB_MS(hwnd,hdc)#啟動(dòng)1號(hào)副本方案
else:
FB_JD(hwnd,hdc)#二號(hào)副本方案
RM = RM + 1
當(dāng)然,,現(xiàn)在由于主題和篇幅原因,我就不補(bǔ)充副本的流程方法了, 但這樣可能會(huì)導(dǎo)致運(yùn)行時(shí)報(bào)錯(cuò)
我們可以將它刪減成
def RunMain(hwnd,Znum):
white True:
print("我在運(yùn)行")
time.sleep(1)
這樣在勾選運(yùn)行的時(shí)候,
終端就會(huì)不停地顯示 我在運(yùn)行
直到我們把運(yùn)行的鉤子取消后,就不會(huì)再顯示了(線程被kill掉了)
熟悉按鍵精靈的大佬們都應(yīng)該用過(guò)一個(gè)叫大漠的插件
但先講不依賴大漠的情況下,用微軟官方的指令來(lái)實(shí)現(xiàn)腳本的操作
import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn,multiprocessing as jc
def init_window():
global cs,wd
wd = tk.Tk()
cs = tk.Canvas(wd,
width = 800,
height = 500,
bg = 'white')
wd.minsize(800, 500) # 最小尺寸
wd.maxsize(800, 500)
wd.title('DDTHelper')
pic = tk.PhotoImage(file="pic.png")
cs.create_image(400,250,image = pic)
cs.pack()
bt = tk.Button(wd,
text='初始化',
bg=('white'),
font=('微軟雅黑',20),
width=155,
height=48,
command=BT_onCreat)
bt.pack()
cs.create_window(530,70,
width=155,
height=48,
window=bt)
wd.mainloop()
def init_control(Znum,name):
global v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
if Znum==1:
v1=tk.IntVar()
tx1=tk.StringVar()
#txn1=tk.StringVar()
elif Znum==2:
v2=tk.IntVar()
tx2=tk.StringVar()
#txn2=tk.StringVar()
elif Znum==3:
v3=tk.IntVar()
tx3=tk.StringVar()
#txn3=tk.StringVar()
exec('tx{}.set("未運(yùn)行")'.format(Znum))
exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
#exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
exec('cb{}.pack()'.format(Znum))
exec('lb{}.pack()'.format(Znum))
#exec('lbn{}.pack()'.format(Znum))
Ytmp=Znum*100
Ytmp=Ytmp+70
exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
Ytmp=Ytmp+40
#exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
def BT_onCreat():
global Znum,D1,D2,D3,conT
Znum = 0
wg.EnumWindows(get_all_hwnd, 0)
conT = jc.Manager().Array("i",[3,0,0,0])
for h,t in hwnd_title.items():
if "4399" in t:
hwnd = t.split("|")[3]
name = t.split("|")[2]
print("賬號(hào):" + name + "句柄:" + hwnd)
Znum = Znum + 1
hwnd = int(hwnd)
init_control(Znum,name)
if Znum == 1:
D1 = jc.Manager().Array("i",[1,hwnd])
elif Znum == 2:
D2 = jc.Manager().Array("i",[2,hwnd])
elif Znum == 3:
D3 = jc.Manager().Array("i",[3,hwnd])
def get_all_hwnd(hwnd,mouse):
if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
def all_run(Znum):
while Znum >0:
exec('t{}.start()'.format(Znum))
Znum = Znum - 1
#操作類--------------------------------------------------------------------------------------------------------------
def climb(hwnd,jl,fx):
if fx==1:#右邊
#適應(yīng)方向及防止無(wú)效
wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
#1.3=1屏距
wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
time.sleep(jl*1.3)
wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
else:
#適應(yīng)方向及防止無(wú)效
wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
#1.3=1屏距
wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
time.sleep(jl*1.3)
wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
def doAngle(hwnd,jd):
for i in range(jd):
time.sleep(0.05)
wa.SendMessage(hwnd,wn.WM_KEYDOWN,87,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,87,None)
def doClick(hwnd,cx,cy):
long_position = wa.MAKELONG(cx, cy)
wa.SendMessage(hwnd, wn.WM_LBUTTONDOWN, wn.MK_LBUTTON, long_position)
wa.SendMessage(hwnd, wn.WM_LBUTTONUP, wn.MK_LBUTTON, long_position)
def doFire(hwnd,ld):
wa.SendMessage(hwnd,wn.WM_KEYFIRST,66,None)#先摁大
wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#先摁技能
wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)
wa.SendMessage(hwnd,wn.WM_KEYFIRST,98,None)
wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)#11大招
wa.SendMessage(hwnd,wn.WM_KEYFIRST,100,None)
wa.SendMessage(hwnd,wn.WM_KEYDOWN,32,None)
time.sleep(ld * 0.04)
wa.SendMessage(hwnd,wn.WM_KEYUP,32,None)
#游戲流程處理類---------------------------------------------------------------------------------------------------------
def Chose_FB(hwnd,hdc):
doClick(hwnd,600,200)#打開(kāi)菜單
time.sleep(1)
doClick(hwnd,626,188)#單人副本
time.sleep(1)
while True:
doClick(hwnd,5,5)
if str(wg.GetPixel(hdc,244,237))==str(2041582):
doClick(hwnd,289,243)#魔石
FBn=1
break
elif str(wg.GetPixel(hdc,337,278))==str(13298869):
doClick(hwnd,292,299)#技能丹
FBn=2
break
time.sleep(1)
doClick(hwnd,726,501)#難度
time.sleep(1)
doClick(hwnd,504,563)#確定
time.sleep(1)
doClick(hwnd,951,491)
return(FBn)
def FB_MS(hwnd,hdc):
time.sleep(24)
while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測(cè)
doClick(hwnd,5,5)
time.sleep(0.5)
while True:
doClick(hwnd,5,5)
colx=wg.GetPixel(hdc,917,486)
if str(colx)==str(36645):
print("位置1")
JD=18
break
else:
print("位置2")
climb(hwnd,0.5,0)
JD=25
break
wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#波谷專用
wa.SendMessage(hwnd,wn.WM_KEYFIRST,80,None)#第一次pass
time.sleep(5)
for i in range(2):
while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測(cè)
doClick(hwnd,5,5)
time.sleep(0.5)
wa.SendMessage(hwnd, wn.WM_KEYDOWN, 65, None)
wa.SendMessage(hwnd, wn.WM_KEYUP, 65, None)
doFire(hwnd,20)
time.sleep(6)
doAngle(hwnd,JD)
time.sleep(10)
while True:
#回合循環(huán)
cs = 0
while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測(cè)
if cs>=20:#超時(shí)退出
break
else:
doClick(hwnd,5,5)
time.sleep(1)
cs=cs+1
#退出
if cs==20:
print("退出副本")
break
else:
doFire(hwnd,20)
def FB_JD(hwnd,hdc):
while True:
cs = 0
cg = 0
while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測(cè)
if cs>=20:#超時(shí)退出
cg=1
cs=0
break
else:
doClick(hwnd,5,5)
time.sleep(1)
cs=cs+1
if cg==1:
break
else:
doFire(hwnd,60)
#程序流程模塊類----------------------------------------------------------------------------------------------------------
def RunMain(hwnd):
RM=0
hdc=wg.GetWindowDC(hwnd)
while True:
while str(wg.GetPixel(hdc,919,280))!=str(10248996):#房間檢測(cè)
print("房間")
doClick(hwnd,5,5)
time.sleep(1)
if Chose_FB(hwnd,hdc) == 1:
FB_MS(hwnd,hdc)
else:
FB_JD(hwnd,hdc)
RM = RM + 1
def Con(Data,conT):
#設(shè)置守護(hù)線程
Znum = Data[0]
print(str(Data[0]))
hwnd = Data[1]
time.sleep(1)
exec('t{} = xc.Thread(target=RunMain,args=(hwnd,))'.format(Znum))
exec('t{}.setDaemon(True)'.format(Znum))
exec('t{}.start()'.format(Znum))
while True:
if conT[Znum] == 0:
time.sleep(1)
else:
break
print('進(jìn)程' + str(Znum) +':已退出')
def onRunMan(Znum):
if onRunMan2(Znum) == 1:
conT[Znum]=0
exec('tx{}.set("運(yùn)行中")'.format(Znum))
exec('p{} = jc.Process(target=Con,args=(D{},conT))'.format(Znum,Znum))
exec('p{}.daemon=True'.format(Znum))
exec('p{}.start()'.format(Znum))
else:
conT[Znum]=1
#exec('del p{}'.format(Znum))
exec('tx{}.set("未運(yùn)行")'.format(Znum))
def onRunMan2(Znum):
if Znum ==1:
return v1.get()
elif Znum == 2:
return v2.get()
elif Znum ==3:
return v3.get()
def onRunMan3(Znum):
if Znum ==1:
if p1.is_alive:
return(1)
else:
return(0)
elif Znum == 2:
if p2.is_alive:
return(1)
else:
return(0)
elif Znum ==3:
if p3.is_alive:
return(1)
else:
return(0)
def BT_onRun1():
onRunMan(1)
def BT_onRun2():
onRunMan(2)
def BT_onRun3():
onRunMan(3)
if __name__ == '__main__':
hwnd_title = dict()
init_window()
我已經(jīng)將模塊代碼用--區(qū)分開(kāi)來(lái)
之前我們講過(guò)了 窗口界面 和 程序線程
重點(diǎn)在于 操作類
負(fù)責(zé)向指定游戲窗口發(fā)生鼠標(biāo)點(diǎn)擊命令的方法
def doClick(hwnd,cx,cy):
long_position = wa.MAKELONG(cx, cy)#模擬鼠標(biāo)指針 傳送到指定坐標(biāo)
wa.SendMessage(hwnd, wn.WM_LBUTTONDOWN, wn.MK_LBUTTON, long_position)#模擬鼠標(biāo)按下
wa.SendMessage(hwnd, wn.WM_LBUTTONUP, wn.MK_LBUTTON, long_position)#模擬鼠標(biāo)彈起
這個(gè)方法把原本復(fù)雜的代碼壓縮了,于是我們要點(diǎn)擊游戲界面的時(shí)候,就可以調(diào)用該方法來(lái)實(shí)現(xiàn),比如
doClick(目標(biāo)窗口句柄,x坐標(biāo),y坐標(biāo))
是不是就有內(nèi)味了?
再看看其他方法
def climb(hwnd,jl,fx):
if fx==1:#右邊
#適應(yīng)方向及防止無(wú)效
wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
#1.3秒=1屏距
wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
time.sleep(jl*1.3)
wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
else:
#適應(yīng)方向及防止無(wú)效
wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
#1.3=1屏距
wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
time.sleep(jl*1.3)
wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
def doAngle(hwnd,jd):
for i in range(jd):
time.sleep(0.05)
wa.SendMessage(hwnd,wn.WM_KEYDOWN,87,None)
wa.SendMessage(hwnd,wn.WM_KEYUP,87,None)
def doFire(hwnd,ld):
wa.SendMessage(hwnd,wn.WM_KEYFIRST,66,None)#先摁大招
wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#先摁技能
wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)
wa.SendMessage(hwnd,wn.WM_KEYFIRST,98,None)#如果有大招,
wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)#11大招
wa.SendMessage(hwnd,wn.WM_KEYFIRST,100,None)
wa.SendMessage(hwnd,wn.WM_KEYDOWN,32,None)#空格蓄力
time.sleep(ld * 0.04)#每蓄力1力度約用時(shí)0.04秒,受游戲延遲和電腦性能會(huì)有誤差,總體可以接受,也可以改成識(shí)別力度條(更精準(zhǔn),但因?yàn)榱Χ葪l顏色不純干擾暫且擱置方案)
wa.SendMessage(hwnd,wn.WM_KEYUP,32,None)#松開(kāi)空格
這里的方法基本都是發(fā)送一些鍵盤操作的集合
比如說(shuō)
方法climb是用來(lái)控制游戲中人物的爬行,
方法doAngle是用來(lái)調(diào)整游戲中人物發(fā)射炮彈的角度
方法doFire就是操作游戲人物發(fā)動(dòng)攻擊
總結(jié)以上方法,模擬鍵盤按鍵有3條指令
wa.SendMessage(游戲窗口句柄,wn.WM_KEYDOWN,按鍵碼,None)
wa.SendMessage(游戲窗口句柄,wn.WM_KEYUP,按鍵碼,None)
wa.SendMessage(游戲窗口句柄,wn.WM_KEYFIRST,按鍵碼,None)
它們分別是向游戲窗口發(fā)送 摁下指定按鍵 彈起指定按鍵 和集合摁下和彈起一體的 點(diǎn)擊指定按鍵
但需要注意的是
如果需要重復(fù)點(diǎn)擊一個(gè)按鍵的時(shí)候,千萬(wàn)不要用 點(diǎn)擊指定按鍵 這個(gè)代碼
這樣會(huì)產(chǎn)生一個(gè)bug,相當(dāng)于按下了按鍵卻沒(méi)有彈起,導(dǎo)致失控
需要像doAngle方法那樣,使用按下和彈起來(lái)保證不會(huì)出bug
然后再到游戲取色
因?yàn)闆](méi)有提取的必要,我就沒(méi)有單獨(dú)分離出來(lái)
取色需要用到hdc(想知道hdc的可以去百度 hdc和hwnd)
hdc=wg.GetWindowDC(int(hwnd))
↑利用hwnd來(lái)獲取hdc
color = wg.GetPixel(hdc,x坐標(biāo),y坐標(biāo))
↑獲取指定點(diǎn)的顏色
細(xì)心的小伙伴們可以發(fā)現(xiàn)
在每個(gè)獲取顏色的代碼附近都有doClick的調(diào)用
那是因?yàn)榉乐褂脩酎c(diǎn)擊了游戲界面后又點(diǎn)擊了其他地方,導(dǎo)致游戲窗口失焦,所以使用doClick強(qiáng)制激活窗口
這里需要注意一點(diǎn)
因?yàn)檫@個(gè)游戲官方允許使用腳本,所以微軟官方的指令是可以用的
否則的話可以嘗試用大漠插件或者別的插件來(lái)發(fā)送硬件級(jí)別的模擬按鍵信息
下面講解調(diào)用大漠插件的方法
大漠插件下載:點(diǎn)我下載
注意:大漠插件是32位的,所以調(diào)用時(shí)必須使用32位的py,不然會(huì)報(bào)錯(cuò)
下載好后把里面的dm.dll放在和腳本同一個(gè)目錄下
使用
import win32com.client
dm = win32com.client.Dispatch('dm.dmsoft') #調(diào)用大漠插件
print(dm.ver())#輸出版本號(hào)
就可以成功地調(diào)用大漠插件并輸出版本號(hào)
綁定窗口
dm_ret = dm.BindWindow(hwnd,"gdi", "windows", "windows", 0)
綁定字典
dm.setDict(0, '字典.txt')#把字典文件放到和腳本同一個(gè)目錄下
dm.useDict(0)
可以說(shuō),在成功注冊(cè)了大漠插件后
它的使用代碼基本和它里面自帶的說(shuō)明書里面的使用代碼一致了
需要的小伙伴可以多看看它自帶的說(shuō)明書
不過(guò)dm.dll經(jīng)常被defender報(bào)毒。。。導(dǎo)致我想用都用不了
雖然大漠的識(shí)別系統(tǒng)很強(qiáng)大,但畢竟是閉源付費(fèi),還強(qiáng)制得換成32位python。。
還是少用為妙