第九十九章 初識模塊-簡單的注冊/登錄系統(tǒng) 下
(此章節(jié)已于2022年7月31日重寫)
在上一章,我們解決了一個世紀(jì)難題:輸入。這一章,我們將會嘗試實現(xiàn)『注冊』這個功能。
我們先理一下這個系統(tǒng)到底是怎樣的:
①有一個password觸發(fā)器,存儲著玩家的密碼,注冊時玩家要填寫的字段
?、谟幸粋€is_typed計分項,用來檢測玩家是否填寫了密碼
?、弁婕野聪掳粹o后,為玩家打開password觸發(fā)器,并指示玩家通過/trigger指令填寫密碼。玩家填寫密碼后,檢測玩家的密碼是否符合要求,如果符合則通過檢測并傳送走玩家,如果不符合則返回錯誤信息,并再次為玩家打開觸發(fā)器指示玩家填寫。
理清楚之后,我們就可以開始動工了。我們將會采用前幾章剛了解的『紅石邏輯組』作為基礎(chǔ)來建設(shè)這個系統(tǒng)。先搭建一個簡單的結(jié)構(gòu):
◎墻→A→B (插圖99-1)
◎······按鈕
→······紅石中繼器
首先,既然要『玩家按下按鈕后,為玩家打開password觸發(fā)器』,那么第一個命令方塊A就應(yīng)該填寫:
scoreboard players enable @p password
\\為最近的玩家開啟它的password計分項\\
命令方塊B用來實現(xiàn)『指示玩家通過/trigger指令填寫密碼』,因此填寫:
tellraw @p {“text“:“請運(yùn)行指令\“/trigger password set <密碼>\“輸入賬戶密碼來注冊“,“color“:“yellow“}
\\告訴最近的玩家『請運(yùn)行指令“/trigger password set <密碼>“輸入賬戶密碼來注冊』\\
然后呢?我們需要一個一直處于運(yùn)行狀態(tài)的紅石邏輯組來不斷檢測玩家是否已經(jīng)輸入密碼,所以我們要在旁邊搭建一個紅石脈沖并配上一些命令方塊:
脈沖→C→D→E (插圖99-2)
C:execute as @p store success score @s is_typed run scoreboard players enable @s password
\\檢測玩家是否輸入密碼\\
D:tellraw @p[scores={is_typed=1}]{“text“:“注冊成功,請記好你的密碼哦!“,“color“:“green“}
\\給已輸入密碼的玩家發(fā)送成功提示\\
E:execute as @p[scores={is_typed=1}] run tp @s 13 -60 10 180 0
\\把注冊成功的玩家傳送走\(yùn)\
這樣子,我們的Beta1.0注冊登錄系統(tǒng)就做好了!讓我們來試一試:
*按下按鈕*
請運(yùn)行指令“/trigger password set <密碼>“輸入賬戶密碼來注冊
*輸入指令:/trigger password set 114514*
已觸發(fā)[password](數(shù)值已設(shè)置為114514)
注冊成功,請記好你的密碼哦!
*被傳送走*
運(yùn)作得十分棒!但是,如果你再次嘗試使用trigger指令的話......
*輸入指令:/trigger password set 1919810*
已觸發(fā)[password](數(shù)值已設(shè)置為1919810)
注冊成功,請記好你的密碼哦!
?我不是注冊過了嗎?
沒錯,這個Beta1.0的系統(tǒng)漏洞百出,它起碼有這幾個問題:
①已注冊的玩家可再注冊
?、趐assword一直可以被修改
?、劭赡軣o法很好應(yīng)對多玩家情況
④系統(tǒng)運(yùn)作較慢
?、輰τ诤罄m(xù)擴(kuò)展出『登錄』功能不友好
為了解決這些問題,我們可以采用tag標(biāo)簽對玩家進(jìn)行標(biāo)記。那么我們會用到哪些tag標(biāo)簽?zāi)兀?p> ?對于注冊中的玩家,需要registering標(biāo)簽
?對于已經(jīng)注冊的玩家,需要registered標(biāo)簽
?對于處于登錄中的玩家,需要logging_in標(biāo)簽
?對于已經(jīng)登錄的玩家,需要logged_in標(biāo)簽
其中,register是注冊的意思,log in是登錄的意思。
我們需要在玩家剛剛開始注冊/登錄時給玩家添加上registering或logging_in標(biāo)簽以防止選擇到那些已經(jīng)登錄和注冊的人,給那些注冊成功的玩家添加上registered標(biāo)簽和logged_in標(biāo)簽并移除掉registering標(biāo)簽,給那些登錄成功的玩家添加上logged_in標(biāo)簽并移除掉logging_in。在后面,我們還會使用更多的標(biāo)簽來完善整個系統(tǒng)的運(yùn)作。
另外,我們還需要關(guān)閉成功注冊玩家的password觸發(fā)器以防止注冊了還能再修改password,還需要在每次紅石邏輯組結(jié)束運(yùn)行時重置每名玩家的is_typed的分?jǐn)?shù)值。前者我們可以通過execute以玩家為執(zhí)行者運(yùn)行一遍trigger password add 0來實現(xiàn),后者可以通過加上寫有『scoreboard players set @a is_typed 0』的命令方塊來實現(xiàn)。
讓我們在系統(tǒng)中加入標(biāo)簽進(jìn)行篩選,并加入上面的指令,看一看是否能夠解決一些問題:
◎墻→A→B→C(插圖:99-3)
脈沖→D→E→F→G→H→I→J
A:execute positioned ~~~-4 run tag @a[distance=..3,tag=!registered,tag=!logged_in] add registering
\\給未登錄且未注冊的玩家添加registering標(biāo)簽\\
B:scoreboard players enable @a[tag=registering] password
C:tellraw @a[tag=registering]{“text“:“請運(yùn)行指令\“/trigger password set <密碼>\“輸入賬戶密碼來注冊“,“color“:“yellow“}
D:execute as @a[tag=registering] store success score @s is_typed run scoreboard players enable @s password
E:execute as @a[tag=registering,scores={is_typed=1}] run tag @s add registered
\\給成功注冊的玩家添加registered標(biāo)簽\\
F:tellraw @a[tag=registering,scores={is_typed=1}]{“text“:“注冊成功,請記好你的密碼哦!“,“color“:“green“}
G:execute as @a[tag=registering,scores={is_typed=1}] run trigger password add 0
\\將成功注冊玩家的password觸發(fā)器使用一遍以關(guān)閉\\
H:execute as @a[tag=registering,scores={is_typed=1}] run tp @s 13 -60 10 180 0
I:execute as @a[tag=registering,scores={is_typed=1}] run tag @s remove registering
J:scoreboard players set @a is_typed 0
\\重置is_typed\\
現(xiàn)在,我們的『注冊/登錄系統(tǒng)』Beta2.0測試版出來了!讓我們測試一下:
n個『已將XXX的[is_typed]分?jǐn)?shù)設(shè)為0』
*按下按鈕*
已為XXX添加了標(biāo)簽'registering'
請運(yùn)行指令“/trigger password set <密碼>“輸入賬戶密碼來注冊
n個『已將XXX的[is_typed]分?jǐn)?shù)設(shè)為0』
*輸入密碼*
已觸發(fā)[password](數(shù)值已設(shè)置為1919810)
已為XXX啟用了觸發(fā)器[password]
已移除XXX的標(biāo)簽'registering'
n個『已將XXX的[is_typed]分?jǐn)?shù)設(shè)為0』
......
出BUG了,還是個很嚴(yán)重的BUG。
不要慌張,讓我們來排查一下到底是什么問題。
仔細(xì)閱讀上面的日志,你會發(fā)現(xiàn):
由于紅石邏輯組的特性,在過長的邏輯組中,執(zhí)行順序會難以把控,然后就出現(xiàn)了上面的問題。
那該怎么辦?
改用『純指令邏輯組』。
『純指令邏輯組』,其實是目前最常見的邏輯組。它有一個更加專業(yè)的說法:模塊。在本書中,它也被稱之為『命令塊鏈』。
我們其實已經(jīng)見過很多次『純指令邏輯組』了,它其實就是由一個脈沖或循環(huán)型命令方塊+一大串連鎖型命令方塊組成的。比如下面的這串命令方塊:
A→B→C→D→(插圖:99-4)
?。榱朔奖悖旅嫖叶紩Q這東西為『模塊』)
在這邊,箭頭代表著命令方塊的朝向,A為循環(huán)型,BCD均為連鎖。這些命令方塊的朝向使得它們環(huán)環(huán)相扣。
循環(huán)型命令方塊A是整個模塊的核心,它負(fù)責(zé)整個模塊的更新。如果A還是『始終活動』,那么A還具有維持整個模塊運(yùn)行的功能。我們從A是循環(huán)型這一點也不難看出,這個邏輯組還是個重復(fù)型邏輯組。
連鎖型命令方塊BCD是整個模塊的通路。相比紅石邏輯組通過紅石元件來控制執(zhí)行順序,模塊通路的執(zhí)行順序更加直觀也不容易出亂子——因為它是通過命令方塊的朝向來決定執(zhí)行順序。這也就是為什么在上面的模塊中,執(zhí)行順序是從左到右的原因。
模塊的難點在于對通路的理解,更確切地說是對『連鎖型命令方塊』運(yùn)作機(jī)制的理解。還記得我們在第二章提到的內(nèi)容嗎?讓我們回顧一下:
『青得一批的那個是鏈(又叫做連鎖),作用是你叫它動一下(接入紅石信號),它不會動。它只會在收到執(zhí)行信號時,將該執(zhí)行信號立馬傳遞給下一個它指向的鏈命令方塊,然后再根據(jù)當(dāng)前條件判斷是否要執(zhí)行。聽起來似乎有點復(fù)雜?舉個例子:
E→F→G→H→
其中,E是未被激活的脈沖命令塊,F(xiàn)GH三個命令方塊都是已被激活且無條件限制的鏈命令塊。當(dāng)E激活時,EFGH將會同時執(zhí)行指令,因為E激活時向F發(fā)出了執(zhí)行信號,F(xiàn)收到后也向G發(fā)出了信號,G也向H發(fā)出了信號,三個鏈命令方塊也都沒有條件限制。』
現(xiàn)在,讓我們仔細(xì)研究一下上面的EFGH為何會這樣子執(zhí)行。為了搞清楚為何這樣子,我們就得研究一個東西:
執(zhí)行信號
可以肯定的是,游戲本身并沒有『執(zhí)行信號』這東西,但為了方便大家理解,我就根據(jù)命令方塊的性質(zhì)總結(jié)出來了『執(zhí)行信號』這個東西。那么這東西有什么特別的呢?
脈沖型和循環(huán)型命令方塊,在被激活的同時不僅僅會嘗試運(yùn)行指令,還會產(chǎn)生執(zhí)行信號并嘗試將其傳遞給它所朝向的連鎖型命令方塊。
連鎖型命令方塊不管是無條件還是條件限制、需要紅石還是始終活動、有被激活還是沒被激活,只要它收到了執(zhí)行信號,那么它就一定會嘗試將該信號傳遞給它所朝向的下一個連鎖型命令方塊,當(dāng)然它在傳遞的同時也會根據(jù)當(dāng)前條件決定是否要運(yùn)行指令。
舉個簡單的例子:
甲→乙→丙→丁→(插圖:99-5)
甲:脈沖型,需要紅石,無條件,沒有寫指令
乙:連鎖型,沒有寫指令
丙:連鎖型,沒有寫指令
?。哼B鎖型,需要紅石,無條件,寫有/setblock ~~1 ~ diamond_block
當(dāng)我們同時激活甲和丁時,盡管甲乙丙都會因為沒有填寫指令而執(zhí)行失敗,但丁卻因為收到了由甲產(chǎn)生并經(jīng)過乙丙傳遞的執(zhí)行信號,加上本身已被激活且沒有條件限制,就執(zhí)行了指令,在上面放置了一個鉆石塊。
這就是執(zhí)行信號。但連鎖型命令方塊并不一定會在接收到執(zhí)行信號后立馬就執(zhí)行指令,它還會看一下情況:
?、偃绻陨砦幢患せ?p> →不會運(yùn)行指令,僅僅會傳遞執(zhí)行信號
?、谌绻陨硪驯患せ?p> →1.如果沒有條件限制
→→嘗試運(yùn)行指令,然后再傳遞執(zhí)行信號
→→否則不會運(yùn)行指令,僅僅會傳遞執(zhí)行信號
→2.如果有條件限制
→→如果正后方的命令方塊上一次執(zhí)行指令成功
→→→嘗試運(yùn)行指令,然后再傳遞執(zhí)行信號
→→→否則不會運(yùn)行指令,僅僅會傳遞執(zhí)行信號
舉個例子:
戊→己→庚→(插圖:99-6)
戊:脈沖、不受制約、需要紅石,填有『setblock ~~1 ~ minecraft:diamond_block』
己:連鎖、條件制約、始終活動,填有『say yes』
庚:連鎖、不受制約、始終活動,填有『say no』
當(dāng)我們第一次激活『戊』命令方塊時,戊就會在上方放一個鉆石塊,己由于戊執(zhí)行成功,就會發(fā)送『yes』的消息,庚由于不受制約所以肯定會發(fā)出『no』的消息,最終三個命令方塊都運(yùn)行了指令。
當(dāng)我們第二次激活『戊』命令方塊時,由于戊上方已經(jīng)有鉆石塊了,所以指令執(zhí)行失敗。己由于戊執(zhí)行失敗,自己也不會執(zhí)行。最終只有戊和庚執(zhí)行并且只有庚執(zhí)行成功。
如果你能看懂并理解上面的內(nèi)容,那么恭喜你,你已經(jīng)基本上掌握了連鎖型命令方塊的運(yùn)作機(jī)制,模塊本身最難以理解的點已被攻破?,F(xiàn)在讓我們回到注冊/登錄系統(tǒng)上,嘗試以模塊的形式替代原有的紅石邏輯組:
◎墻A→B→C→(插圖:99-7)
D→E→F→G→H→I→J→
A[脈][無][紅]——execute positioned ~~~-3 run tag @a[distance=..3,tag=!registered,tag=!logged_in] add registering
B[鏈][無][始]——同替代前
C[鏈][無][始]——同替代前
D[重][無][紅]
E[鏈][無][始]
F[鏈][無][始]
G[鏈][無][始]
H[鏈][無][始]
I[鏈][無][始]
J[鏈][無][始]
現(xiàn)在,我們系統(tǒng)的Beta3.0版本出來了,讓我們測試一下BUG有無解決:
*按下按鈕*
已為XXX添加了標(biāo)簽'registering'
請運(yùn)行指令“/trigger password set <密碼>“輸入賬戶密碼來注冊
n個『已將XXX的[is_typed]分?jǐn)?shù)設(shè)為0』
*輸入密碼*
已觸發(fā)[password](數(shù)值已設(shè)置為1919810)
已為XXX啟用了觸發(fā)器[password]
已為XXX添加了標(biāo)簽'registered'
注冊成功,請記好你的密碼哦!
已觸發(fā)[password](數(shù)值已增加0)
已將XXX傳送到 13.500000,-60.000000, 10.500000
已移除XXX的標(biāo)簽'registering'
n個『已將XXX的[is_typed]分?jǐn)?shù)設(shè)為0』
解決了?。。?p> 現(xiàn)在,我們已經(jīng)完成了這個系統(tǒng)的大半部分,接下來我們將會嘗試完成『檢測玩家的密碼是否符合要求,如果符合則通過檢測并傳送走玩家,如果不符合則返回錯誤信息,并再次為玩家打開觸發(fā)器指示玩家填寫』這個部分。
其實這個部分相當(dāng)簡單。比如我們想要玩家不能設(shè)定密碼為0,就可以這么干:
在D命令方塊后面插入兩個新的命令方塊,寫入以下內(nèi)容
execute as @a[tag=registering,scores={is_typed=1}] unless score @s password matches 0 run tag @s add correct_input
\\為密碼不是0的玩家添加標(biāo)簽correct_input(正確輸入)\\
execute as @a[tag=registering,scores={is_typed=1}] if score @s password matches 0 run tag @s add error_input
\\為密碼是0的玩家添加標(biāo)簽error_input(錯誤輸入)\\
修改E、F、G、H、I命令方塊的內(nèi)容為
execute as @a[tag=correct_input,tag=registering] run tag @s add registered
tellraw @a[tag=correct_input,tag=registering]{“text“:“注冊成功,請記好你的密碼哦!“,“color“:“green“}
execute as @a[tag=correct_input,tag=registering] run trigger password add 0
execute as @a[tag=correct_input,tag=registering] run tp @s 13 -60 10 180 0
execute as @a[tag=correct_input,tag=registering] run tag @s remove registering
在I后新增命令方塊3個,內(nèi)容為
execute as @a[tag=correct_input,tag=registered] run tag @s remove correct_input
execute as @a[tag=registering,tag=error_input] run tellraw @s {“text“:“請不要將0作為你的密碼,請重新輸入“,“color“:“red“}
execute as @a[tag=registering,tag=error_input] run tag @s remove error_input
讓我們測試一下:
......
*輸入密碼*
已觸發(fā)[password](數(shù)值已設(shè)置為0)
已為XXX啟用了觸發(fā)器[password]
已為XXX添加了標(biāo)簽'error_input'
請不要將0作為你的密碼,請重新輸入
已移除XXX的標(biāo)簽'error_input'
*再次輸入密碼*
已觸發(fā)[password](數(shù)值已設(shè)置為1)
已為XXX啟用了觸發(fā)器[password]
已為XXX添加了標(biāo)簽'correct_input'
已為XXX添加了標(biāo)簽'registered'
注冊成功,請記好你的密碼哦!
已觸發(fā)[password](數(shù)值已增加0)
已將XXX傳送到 13.500000,-60.000000, 10.500000
已移除XXX的標(biāo)簽'registering'
已移除XXX的標(biāo)簽'correct_input'
OK,完美運(yùn)行,這就是系統(tǒng)的Beta4.0版本。
只不過由于篇幅限制,我們就講到這里。接下來對于『登錄』功能甚至『登出』功能的實現(xiàn),請你自己獨立完成。這邊有幾個要求和提示:
?、俚卿浤K和注冊模塊要分開,但其實兩者的原理都差不多
②創(chuàng)建一個新的觸發(fā)器enter_password,用于登錄密碼的輸入
?、蹆?yōu)化模塊的運(yùn)行,使得玩家在按下按鈕后才會調(diào)用登錄和注冊模塊,并在沒有處于登錄/注冊中的玩家后停止模塊運(yùn)行(提示:setblock或fill紅石塊)
?、軇?chuàng)建一個新的觸發(fā)器,已登錄的玩家可以修改此觸發(fā)器到一個特定的值來退出登錄
⑤新玩家進(jìn)來后必須要出生在注冊/登錄房里
?、尬醋粉櫷婕业姆?jǐn)?shù)無法被比較。所以如果你拿未追蹤玩家的分?jǐn)?shù)來比較,由于沒有分?jǐn)?shù),所以游戲總會返回false(假)
你可以加QQ群或通過作家的話中的網(wǎng)盤鏈接獲取到我做的完整『注冊/登錄系統(tǒng)』的存檔(Minecraft Java1.19版本,非網(wǎng)易版)。
本章到此為止。