Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
S
srvpro2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
srvpro2
Commits
4af43c04
Commit
4af43c04
authored
Feb 16, 2026
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rework random duel
parent
19daed1d
Pipeline
#43256
passed with stages
in 2 minutes and 39 seconds
Changes
18
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
780 additions
and
77 deletions
+780
-77
AGENTS.md
AGENTS.md
+1
-0
src/client/client-handler.ts
src/client/client-handler.ts
+4
-0
src/client/client.ts
src/client/client.ts
+2
-0
src/constants/trans.ts
src/constants/trans.ts
+44
-0
src/feats/random-duel-events.ts
src/feats/random-duel-events.ts
+22
-0
src/feats/random-duel/provider.ts
src/feats/random-duel/provider.ts
+442
-8
src/feats/random-duel/utility/random-duel-discipline.ts
src/feats/random-duel/utility/random-duel-discipline.ts
+41
-0
src/feats/reconnect/index.ts
src/feats/reconnect/index.ts
+3
-1
src/feats/resource/badword-provider.ts
src/feats/resource/badword-provider.ts
+16
-1
src/feats/wait-for-player-provider.ts
src/feats/wait-for-player-provider.ts
+9
-0
src/feats/windbot/join-windbot-ai.ts
src/feats/windbot/join-windbot-ai.ts
+72
-56
src/join-handlers/join-blank-pass-random-duel.ts
src/join-handlers/join-blank-pass-random-duel.ts
+27
-0
src/join-handlers/join-blank-pass-windbot-ai.ts
src/join-handlers/join-blank-pass-windbot-ai.ts
+20
-0
src/join-handlers/join-handler-module.ts
src/join-handlers/join-handler-module.ts
+4
-0
src/join-handlers/random-duel-join-handler.ts
src/join-handlers/random-duel-join-handler.ts
+9
-3
src/room/room-event/on-room-leave-observer.ts
src/room/room-event/on-room-leave-observer.ts
+15
-1
src/room/room-event/on-room-leave-player.ts
src/room/room-event/on-room-leave-player.ts
+8
-0
src/room/room.ts
src/room/room.ts
+41
-7
No files found.
AGENTS.md
View file @
4af43c04
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
-
目录外引用:必须通过 index.ts 引用,如
`'../room'`
`'../client'`
(指向 index.ts)
-
目录外引用:必须通过 index.ts 引用,如
`'../room'`
`'../client'`
(指向 index.ts)
-
禁止直接引用具体文件:不要使用
`'../room/room'`
`'../client/client'`
这样的路径
-
禁止直接引用具体文件:不要使用
`'../room/room'`
`'../client/client'`
这样的路径
-
如果正在写的算法代码与 this 和业务无关,那么不要放在类方法里面,而是在 utility 目录新开一个 ts 文件放进去
-
如果正在写的算法代码与 this 和业务无关,那么不要放在类方法里面,而是在 utility 目录新开一个 ts 文件放进去
-
如果正在移植 srvpro 的功能,那么 i18n 必须严格和 srvpro 保持一致,不能改动 i18n 的 key 和 value。新功能或者原有功能的额外部分可以写新的。
## 模块结构
## 模块结构
...
...
src/client/client-handler.ts
View file @
4af43c04
...
@@ -45,6 +45,10 @@ export class ClientHandler {
...
@@ -45,6 +45,10 @@ export class ClientHandler {
client
.
vpass
=
vpass
||
''
;
client
.
vpass
=
vpass
||
''
;
return
next
();
return
next
();
})
})
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
client
.
roompass
=
msg
.
pass
||
''
;
return
next
();
})
.
middleware
(
.
middleware
(
YGOProCtosBase
,
YGOProCtosBase
,
async
(
msg
,
client
,
next
)
=>
{
async
(
msg
,
client
,
next
)
=>
{
...
...
src/client/client.ts
View file @
4af43c04
...
@@ -213,6 +213,8 @@ export class Client {
...
@@ -213,6 +213,8 @@ export class Client {
@
ClientRoomField
()
@
ClientRoomField
()
roomName
?:
string
;
roomName
?:
string
;
@
ClientRoomField
()
@
ClientRoomField
()
roompass
=
''
;
@
ClientRoomField
()
isHost
=
false
;
isHost
=
false
;
@
ClientRoomField
()
@
ClientRoomField
()
pos
=
-
1
;
pos
=
-
1
;
...
...
src/constants/trans.ts
View file @
4af43c04
...
@@ -55,6 +55,30 @@ export const TRANSLATIONS = {
...
@@ -55,6 +55,30 @@ export const TRANSLATIONS = {
'
Match mode room. Password S for single mode, T for tag mode.
'
,
'
Match mode room. Password S for single mode, T for tag mode.
'
,
random_duel_enter_room_tag
:
random_duel_enter_room_tag
:
'
Tag mode room. Password S for single mode, M for match mode.
'
,
'
Tag mode room. Password S for single mode, M for match mode.
'
,
random_banned_part1
:
'
You have been banned from the game due to
'
,
random_banned_part2
:
'
, it will last until
'
,
random_banned_part3
:
'
.
'
,
random_deprecated_part1
:
'
Because of your
'
,
random_deprecated_part2
:
'
, in recent games, you will only suffer other players who are under same punishment as you in
'
,
random_deprecated_part3
:
'
.
'
,
random_warn_part1
:
'
The system detects that recently you had
'
,
random_warn_part2
:
'
in recent games, you will be penalized after 3 offences
'
,
random_ban_reason_separator
:
'
/
'
,
random_ban_reason_flee
:
'
Flee
'
,
random_ban_reason_AFK
:
'
AFK
'
,
random_ban_reason_abuse
:
'
Abusing
'
,
random_ban_reason_zombie
:
'
Zombie
'
,
unwelcome_warn_part1
:
'
If you keep doing
'
,
unwelcome_warn_part2
:
'
, your opponent may leave you.
'
,
unwelcome_tip_part1
:
'
Your opponent did
'
,
unwelcome_tip_part2
:
'
, so you can leave the game without being punished.
'
,
banned_duel_tip
:
'
You are banned from the random duel system for sending inappropriate messages.
'
,
chat_banned
:
'
is banned from chat.
'
,
surrender_denied
:
"
Please don't surrender in the first 2 turns.
"
,
chat_disabled
:
'
Chat is disabled in this room.
'
,
chat_disabled
:
'
Chat is disabled in this room.
'
,
chat_warn_level1
:
'
Please avoid sensitive words.
'
,
chat_warn_level1
:
'
Please avoid sensitive words.
'
,
chat_warn_level2
:
'
Your message contains blocked words.
'
,
chat_warn_level2
:
'
Your message contains blocked words.
'
,
...
@@ -110,6 +134,26 @@ export const TRANSLATIONS = {
...
@@ -110,6 +134,26 @@ export const TRANSLATIONS = {
'
您进入了比赛模式房间,密码输入 S 进入单局模式,输入 T 进入双打模式。
'
,
'
您进入了比赛模式房间,密码输入 S 进入单局模式,输入 T 进入双打模式。
'
,
random_duel_enter_room_tag
:
random_duel_enter_room_tag
:
'
您进入了双打模式房间,密码输入 S 进入单局模式,输入 M 进入比赛模式。
'
,
'
您进入了双打模式房间,密码输入 S 进入单局模式,输入 M 进入比赛模式。
'
,
random_banned_part1
:
'
因为您近期在游戏中多次
'
,
random_banned_part2
:
'
,您已被禁止使用随机对战功能,将在
'
,
random_banned_part3
:
'
后解封
'
,
random_deprecated_part1
:
'
因为您近期在游戏中
'
,
random_deprecated_part2
:
'
,在
'
,
random_deprecated_part3
:
'
内您随机对战时只能遇到其他违规玩家。
'
,
random_warn_part1
:
'
系统检测到您近期在游戏中
'
,
random_warn_part2
:
'
,若您违规超过3次,将受到惩罚
'
,
random_ban_reason_separator
:
'
、
'
,
random_ban_reason_flee
:
'
强退
'
,
random_ban_reason_AFK
:
'
挂机
'
,
random_ban_reason_abuse
:
'
发言违规
'
,
random_ban_reason_zombie
:
'
挂房间
'
,
unwelcome_warn_part1
:
'
如果您经常
'
,
unwelcome_warn_part2
:
'
,您的对手可能会离你而去。
'
,
unwelcome_tip_part1
:
'
因为您的对手有
'
,
unwelcome_tip_part2
:
'
行为,现在您可以直接离开游戏或投降,不视为强退。
'
,
banned_duel_tip
:
'
您的发言存在严重不适当的内容,禁止您使用随机对战功能!
'
,
chat_banned
:
'
已被禁言!
'
,
surrender_denied
:
'
为保证双方玩家的游戏体验,随机对战中3回合后才能投降。
'
,
chat_disabled
:
'
本房间禁止聊天。
'
,
chat_disabled
:
'
本房间禁止聊天。
'
,
chat_warn_level1
:
'
请注意发言,敏感词已被替换。
'
,
chat_warn_level1
:
'
请注意发言,敏感词已被替换。
'
,
chat_warn_level2
:
'
消息包含敏感词,已被拦截。
'
,
chat_warn_level2
:
'
消息包含敏感词,已被拦截。
'
,
...
...
src/feats/random-duel-events.ts
0 → 100644
View file @
4af43c04
import
{
Client
}
from
'
../client
'
;
import
{
Room
}
from
'
../room
'
;
export
type
RandomDuelWaitTimeoutType
=
'
ready
'
|
'
hang
'
;
export
class
OnClientWaitTimeout
{
constructor
(
public
room
:
Room
,
public
client
:
Client
,
public
type
:
RandomDuelWaitTimeoutType
,
)
{}
}
export
class
OnClientBadwordViolation
{
constructor
(
public
client
:
Client
,
public
room
:
Room
|
undefined
,
public
message
:
string
,
public
level
:
number
,
public
replacedMessage
?:
string
,
)
{}
}
src/feats/random-duel/provider.ts
View file @
4af43c04
This diff is collapsed.
Click to expand it.
src/feats/random-duel/utility/random-duel-discipline.ts
0 → 100644
View file @
4af43c04
export
type
RandomDuelPunishReason
=
'
AFK
'
|
'
ABUSE
'
|
'
FLEE
'
|
'
ZOMBIE
'
;
export
const
punishReasonToI18nKey
=
(
reason
:
RandomDuelPunishReason
)
=>
{
if
(
reason
===
'
AFK
'
)
{
return
'
random_ban_reason_AFK
'
;
}
if
(
reason
===
'
ABUSE
'
)
{
return
'
random_ban_reason_abuse
'
;
}
if
(
reason
===
'
FLEE
'
)
{
return
'
random_ban_reason_flee
'
;
}
return
'
random_ban_reason_zombie
'
;
};
export
const
renderReasonText
=
(
reasons
:
RandomDuelPunishReason
[])
=>
{
const
entries
=
[...
new
Set
(
reasons
)].
map
(
(
reason
)
=>
`#{
${
punishReasonToI18nKey
(
reason
)}
}`
,
);
if
(
!
entries
.
length
)
{
return
`#{
${
punishReasonToI18nKey
(
'
ABUSE
'
)}
}`
;
}
return
entries
.
join
(
'
#{random_ban_reason_separator}
'
);
};
export
const
formatRemainText
=
(
expireAt
:
number
)
=>
{
const
remainMs
=
Math
.
max
(
0
,
expireAt
-
Date
.
now
());
const
remainMinutes
=
Math
.
max
(
1
,
Math
.
ceil
(
remainMs
/
60
_000
));
if
(
remainMinutes
>=
60
)
{
const
hours
=
Math
.
floor
(
remainMinutes
/
60
);
const
minutes
=
remainMinutes
%
60
;
if
(
minutes
<=
0
)
{
return
`
${
hours
}
h`
;
}
return
`
${
hours
}
h
${
minutes
}
m`
;
}
return
`
${
remainMinutes
}
m`
;
};
export
const
buildFleeFreeKey
=
(
roomName
:
string
,
ip
:
string
)
=>
`
${
roomName
}
:
${
ip
}
`
;
src/feats/reconnect/index.ts
View file @
4af43c04
...
@@ -838,7 +838,9 @@ export class Reconnect {
...
@@ -838,7 +838,9 @@ export class Reconnect {
const
matchCondition
=
const
matchCondition
=
room
.
isLooseReconnectRule
||
room
.
isLooseReconnectRule
||
player
.
ip
===
newClient
.
ip
||
player
.
ip
===
newClient
.
ip
||
(
newClient
.
vpass
&&
newClient
.
vpass
===
player
.
vpass
);
(
newClient
.
vpass
&&
newClient
.
vpass
===
player
.
vpass
&&
newClient
.
roompass
===
player
.
roompass
);
if
(
matchCondition
)
{
if
(
matchCondition
)
{
return
player
;
return
player
;
...
...
src/feats/resource/badword-provider.ts
View file @
4af43c04
...
@@ -4,6 +4,7 @@ import { Client } from '../../client';
...
@@ -4,6 +4,7 @@ import { Client } from '../../client';
import
{
Room
,
RoomManager
}
from
'
../../room
'
;
import
{
Room
,
RoomManager
}
from
'
../../room
'
;
import
{
escapeRegExp
}
from
'
../../utility/escape-regexp
'
;
import
{
escapeRegExp
}
from
'
../../utility/escape-regexp
'
;
import
{
ValueContainer
}
from
'
../../utility/value-container
'
;
import
{
ValueContainer
}
from
'
../../utility/value-container
'
;
import
{
OnClientBadwordViolation
}
from
'
../random-duel-events
'
;
import
{
BaseResourceProvider
}
from
'
./base-resource-provider
'
;
import
{
BaseResourceProvider
}
from
'
./base-resource-provider
'
;
import
{
isObjectRecord
}
from
'
./resource-util
'
;
import
{
isObjectRecord
}
from
'
./resource-util
'
;
import
{
BadwordsData
,
EMPTY_BADWORDS_DATA
}
from
'
./types
'
;
import
{
BadwordsData
,
EMPTY_BADWORDS_DATA
}
from
'
./types
'
;
...
@@ -71,7 +72,21 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> {
...
@@ -71,7 +72,21 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> {
const
room
=
client
.
roomName
const
room
=
client
.
roomName
?
this
.
roomManager
.
findByName
(
client
.
roomName
)
?
this
.
roomManager
.
findByName
(
client
.
roomName
)
:
undefined
;
:
undefined
;
const
filtered
=
await
this
.
filterText
(
msg
.
msg
,
room
,
client
);
const
originalMessage
=
msg
.
msg
;
const
filtered
=
await
this
.
filterText
(
originalMessage
,
room
,
client
);
if
(
filtered
.
level
>=
0
)
{
await
this
.
ctx
.
dispatch
(
new
OnClientBadwordViolation
(
client
,
room
,
originalMessage
,
filtered
.
level
,
filtered
.
message
!==
originalMessage
?
filtered
.
message
:
undefined
,
),
client
as
any
,
);
}
if
(
filtered
.
blocked
)
{
if
(
filtered
.
blocked
)
{
await
client
.
sendChat
(
'
#{chat_warn_level2}
'
,
ChatColor
.
RED
);
await
client
.
sendChat
(
'
#{chat_warn_level2}
'
,
ChatColor
.
RED
);
...
...
src/feats/wait-for-player-provider.ts
View file @
4af43c04
...
@@ -19,6 +19,7 @@ import {
...
@@ -19,6 +19,7 @@ import {
Room
,
Room
,
RoomManager
,
RoomManager
,
}
from
'
../room
'
;
}
from
'
../room
'
;
import
{
OnClientWaitTimeout
}
from
'
./random-duel-events
'
;
export
interface
WaitForPlayerConfig
{
export
interface
WaitForPlayerConfig
{
roomFilter
:
(
room
:
Room
)
=>
boolean
;
roomFilter
:
(
room
:
Room
)
=>
boolean
;
...
@@ -394,6 +395,10 @@ export class WaitForPlayerProvider {
...
@@ -394,6 +395,10 @@ export class WaitForPlayerProvider {
`
${
latestTarget
.
name
}
#{kicked_by_system}`
,
`
${
latestTarget
.
name
}
#{kicked_by_system}`
,
ChatColor
.
RED
,
ChatColor
.
RED
,
);
);
await
this
.
ctx
.
dispatch
(
new
OnClientWaitTimeout
(
room
,
latestTarget
,
'
ready
'
),
latestTarget
,
);
latestTarget
.
disconnect
();
latestTarget
.
disconnect
();
}
}
...
@@ -441,6 +446,10 @@ export class WaitForPlayerProvider {
...
@@ -441,6 +446,10 @@ export class WaitForPlayerProvider {
`
${
waitingPlayer
.
name
}
#{kicked_by_system}`
,
`
${
waitingPlayer
.
name
}
#{kicked_by_system}`
,
ChatColor
.
RED
,
ChatColor
.
RED
,
);
);
await
this
.
ctx
.
dispatch
(
new
OnClientWaitTimeout
(
room
,
waitingPlayer
,
'
hang
'
),
waitingPlayer
,
);
waitingPlayer
.
disconnect
();
waitingPlayer
.
disconnect
();
return
;
return
;
}
}
...
...
src/feats/windbot/join-windbot-ai.ts
View file @
4af43c04
import
{
ChatColor
,
YGOProCtosJoinGame
}
from
'
ygopro-msg-encode
'
;
import
{
ChatColor
,
YGOProCtosJoinGame
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../../app
'
;
import
{
Context
}
from
'
../../app
'
;
import
{
Client
}
from
'
../../client
'
;
import
{
WindBotProvider
}
from
'
./windbot-provider
'
;
import
{
WindBotProvider
}
from
'
./windbot-provider
'
;
import
{
RoomManager
}
from
'
../../room
'
;
import
{
RoomManager
}
from
'
../../room
'
;
import
{
MAX_ROOM_NAME_LENGTH
}
from
'
../../constants/room
'
;
import
{
MAX_ROOM_NAME_LENGTH
}
from
'
../../constants/room
'
;
...
@@ -19,71 +20,86 @@ export class JoinWindbotAi {
...
@@ -19,71 +20,86 @@ export class JoinWindbotAi {
return
;
return
;
}
}
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
msg
.
pass
=
(
msg
.
pass
||
''
).
trim
();
if
(
!
(
await
this
.
joinByPass
(
msg
.
pass
,
client
)))
{
if
(
!
msg
.
pass
||
!
msg
.
pass
.
toUpperCase
().
startsWith
(
'
AI
'
))
{
return
next
();
return
next
();
}
}
return
;
});
}
const
existingRoom
=
this
.
roomManager
.
findByName
(
msg
.
pass
);
async
joinByPass
(
pass
:
string
,
client
:
Client
)
{
if
(
existingRoom
)
{
const
normalizedPass
=
(
pass
||
''
).
trim
();
existingRoom
.
noHost
=
true
;
if
(
return
existingRoom
.
join
(
client
);
!
this
.
windbotProvider
.
enabled
||
}
!
normalizedPass
||
!
normalizedPass
.
toUpperCase
().
startsWith
(
'
AI
'
)
)
{
return
false
;
}
const
requestedBotName
=
this
.
parseRequestedBotName
(
msg
.
pass
);
const
existingRoom
=
this
.
roomManager
.
findByName
(
normalizedPass
);
if
(
if
(
existingRoom
)
{
requestedBotName
&&
existingRoom
.
noHost
=
true
;
!
this
.
windbotProvider
.
getBotByNameOrDeck
(
requestedBotName
)
await
existingRoom
.
join
(
client
);
)
{
return
true
;
return
client
.
die
(
'
#{windbot_deck_not_found}
'
,
ChatColor
.
RED
);
}
}
const
roomName
=
this
.
generateWindbotRoomName
(
msg
.
pass
);
const
requestedBotName
=
this
.
parseRequestedBotName
(
normalizedPass
);
if
(
!
roomName
)
{
if
(
return
client
.
die
(
'
#{create_room_failed}
'
,
ChatColor
.
RED
);
requestedBotName
&&
}
!
this
.
windbotProvider
.
getBotByNameOrDeck
(
requestedBotName
)
if
(
getDisplayLength
(
roomName
)
>
20
)
{
)
{
return
client
.
die
(
'
#{windbot_name_too_long}
'
,
ChatColor
.
RED
);
await
client
.
die
(
'
#{windbot_deck_not_found}
'
,
ChatColor
.
RED
);
}
return
true
;
}
const
room
=
await
this
.
roomManager
.
findOrCreateByName
(
roomName
,
{
const
roomName
=
this
.
generateWindbotRoomName
(
normalizedPass
);
rule
:
5
,
if
(
!
roomName
)
{
lflist
:
-
1
,
await
client
.
die
(
'
#{create_room_failed}
'
,
ChatColor
.
RED
);
time_limit
:
0
,
return
true
;
});
}
room
.
noHost
=
true
;
if
(
getDisplayLength
(
roomName
)
>
20
)
{
room
.
noReconnect
=
true
;
await
client
.
die
(
'
#{windbot_name_too_long}
'
,
ChatColor
.
RED
);
room
.
windbot
=
{
return
true
;
name
:
''
,
}
deck
:
''
,
};
const
windbotOptions
=
parseWindbotOptions
(
room
.
name
);
await
room
.
join
(
client
);
const
room
=
await
this
.
roomManager
.
findOrCreateByName
(
roomName
,
{
const
requestCount
=
room
.
isTag
?
3
:
1
;
rule
:
5
,
for
(
let
i
=
0
;
i
<
requestCount
;
i
+=
1
)
{
lflist
:
-
1
,
const
requestOk
=
await
this
.
windbotProvider
.
requestWindbotJoin
(
time_limit
:
0
,
room
,
});
requestedBotName
,
room
.
noHost
=
true
;
windbotOptions
,
room
.
noReconnect
=
true
;
);
room
.
windbot
=
{
if
(
!
requestOk
)
{
name
:
''
,
await
room
.
finalize
();
deck
:
''
,
return
;
};
}
const
windbotOptions
=
parseWindbotOptions
(
room
.
name
);
}
this
.
logger
.
debug
(
await
room
.
join
(
client
);
{
const
requestCount
=
room
.
isTag
?
3
:
1
;
player
:
client
.
name
,
for
(
let
i
=
0
;
i
<
requestCount
;
i
+=
1
)
{
roomName
:
room
.
name
,
const
requestOk
=
await
this
.
windbotProvider
.
requestWindbotJoin
(
botName
:
room
.
windbot
?.
name
,
room
,
requestCount
,
requestedBotName
,
},
windbotOptions
,
'
Created windbot room
'
,
);
);
return
;
if
(
!
requestOk
)
{
});
await
room
.
finalize
();
return
true
;
}
}
this
.
logger
.
debug
(
{
player
:
client
.
name
,
roomName
:
room
.
name
,
botName
:
room
.
windbot
?.
name
,
requestCount
,
},
'
Created windbot room
'
,
);
return
true
;
}
}
private
parseRequestedBotName
(
pass
:
string
)
{
private
parseRequestedBotName
(
pass
:
string
)
{
...
...
src/join-handlers/join-blank-pass-random-duel.ts
0 → 100644
View file @
4af43c04
import
{
ChatColor
,
YGOProCtosJoinGame
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../app
'
;
import
{
RandomDuelProvider
}
from
'
../feats
'
;
export
class
JoinBlankPassRandomDuel
{
private
randomDuelProvider
=
this
.
ctx
.
get
(()
=>
RandomDuelProvider
);
constructor
(
private
ctx
:
Context
)
{
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
msg
.
pass
=
(
msg
.
pass
||
''
).
trim
();
if
(
msg
.
pass
||
!
this
.
randomDuelProvider
.
enabled
)
{
return
next
();
}
const
result
=
await
this
.
randomDuelProvider
.
findOrCreateRandomRoom
(
''
,
client
.
ip
,
);
if
(
result
.
errorMessage
)
{
return
client
.
die
(
result
.
errorMessage
,
ChatColor
.
RED
);
}
if
(
!
result
.
room
)
{
return
client
.
die
(
'
#{create_room_failed}
'
,
ChatColor
.
RED
);
}
return
result
.
room
.
join
(
client
);
});
}
}
src/join-handlers/join-blank-pass-windbot-ai.ts
0 → 100644
View file @
4af43c04
import
{
YGOProCtosJoinGame
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../app
'
;
import
{
JoinWindbotAi
}
from
'
../feats/windbot
'
;
export
class
JoinBlankPassWindbotAi
{
private
joinWindbotAi
=
this
.
ctx
.
get
(()
=>
JoinWindbotAi
);
constructor
(
private
ctx
:
Context
)
{
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
msg
.
pass
=
(
msg
.
pass
||
''
).
trim
();
if
(
msg
.
pass
)
{
return
next
();
}
if
(
await
this
.
joinWindbotAi
.
joinByPass
(
'
AI
'
,
client
))
{
return
;
}
return
next
();
});
}
}
src/join-handlers/join-handler-module.ts
View file @
4af43c04
...
@@ -7,6 +7,8 @@ import { JoinFallback } from './fallback';
...
@@ -7,6 +7,8 @@ import { JoinFallback } from './fallback';
import
{
JoinPrechecks
}
from
'
./join-prechecks
'
;
import
{
JoinPrechecks
}
from
'
./join-prechecks
'
;
import
{
RandomDuelJoinHandler
}
from
'
./random-duel-join-handler
'
;
import
{
RandomDuelJoinHandler
}
from
'
./random-duel-join-handler
'
;
import
{
BadwordPlayerInfoChecker
}
from
'
./badword-player-info-checker
'
;
import
{
BadwordPlayerInfoChecker
}
from
'
./badword-player-info-checker
'
;
import
{
JoinBlankPassRandomDuel
}
from
'
./join-blank-pass-random-duel
'
;
import
{
JoinBlankPassWindbotAi
}
from
'
./join-blank-pass-windbot-ai
'
;
export
const
JoinHandlerModule
=
createAppContext
<
ContextState
>
()
export
const
JoinHandlerModule
=
createAppContext
<
ContextState
>
()
.
provide
(
ClientVersionCheck
)
.
provide
(
ClientVersionCheck
)
...
@@ -16,5 +18,7 @@ export const JoinHandlerModule = createAppContext<ContextState>()
...
@@ -16,5 +18,7 @@ export const JoinHandlerModule = createAppContext<ContextState>()
.
provide
(
RandomDuelJoinHandler
)
.
provide
(
RandomDuelJoinHandler
)
.
provide
(
JoinWindbotAi
)
.
provide
(
JoinWindbotAi
)
.
provide
(
JoinRoom
)
.
provide
(
JoinRoom
)
.
provide
(
JoinBlankPassRandomDuel
)
.
provide
(
JoinBlankPassWindbotAi
)
.
provide
(
JoinFallback
)
.
provide
(
JoinFallback
)
.
define
();
.
define
();
src/join-handlers/random-duel-join-handler.ts
View file @
4af43c04
...
@@ -11,18 +11,24 @@ export class RandomDuelJoinHandler {
...
@@ -11,18 +11,24 @@ export class RandomDuelJoinHandler {
}
}
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
this
.
ctx
.
middleware
(
YGOProCtosJoinGame
,
async
(
msg
,
client
,
next
)
=>
{
msg
.
pass
=
(
msg
.
pass
||
''
).
trim
();
msg
.
pass
=
(
msg
.
pass
||
''
).
trim
();
if
(
!
msg
.
pass
)
{
return
next
();
}
const
type
=
this
.
randomDuelProvider
.
resolveRandomType
(
msg
.
pass
);
const
type
=
this
.
randomDuelProvider
.
resolveRandomType
(
msg
.
pass
);
if
(
type
==
null
)
{
if
(
type
==
null
)
{
return
next
();
return
next
();
}
}
const
r
oom
=
await
this
.
randomDuelProvider
.
findOrCreateRandomRoom
(
const
r
esult
=
await
this
.
randomDuelProvider
.
findOrCreateRandomRoom
(
type
,
type
,
client
.
ip
,
client
.
ip
,
);
);
if
(
!
room
)
{
if
(
result
.
errorMessage
)
{
return
client
.
die
(
result
.
errorMessage
,
ChatColor
.
RED
);
}
if
(
!
result
.
room
)
{
return
client
.
die
(
'
#{create_room_failed}
'
,
ChatColor
.
RED
);
return
client
.
die
(
'
#{create_room_failed}
'
,
ChatColor
.
RED
);
}
}
return
room
.
join
(
client
);
return
r
esult
.
r
oom
.
join
(
client
);
});
});
}
}
}
}
src/room/room-event/on-room-leave-observer.ts
View file @
4af43c04
import
{
Room
}
from
'
../room
'
;
import
{
RoomEvent
}
from
'
./room-event
'
;
import
{
RoomEvent
}
from
'
./room-event
'
;
export
class
OnRoomLeaveObserver
extends
RoomEvent
{}
export
enum
RoomLeaveObserverReason
{
Disconnect
=
'
disconnect
'
,
ToDuelist
=
'
to_duelist
'
,
}
export
class
OnRoomLeaveObserver
extends
RoomEvent
{
constructor
(
room
:
Room
,
public
reason
:
RoomLeaveObserverReason
,
public
bySystem
=
false
,
)
{
super
(
room
);
}
}
src/room/room-event/on-room-leave-player.ts
View file @
4af43c04
import
{
Room
}
from
'
../room
'
;
import
{
Room
}
from
'
../room
'
;
import
{
RoomEvent
}
from
'
./room-event
'
;
import
{
RoomEvent
}
from
'
./room-event
'
;
export
enum
RoomLeavePlayerReason
{
Disconnect
=
'
disconnect
'
,
ToObserver
=
'
to_observer
'
,
SwitchPosition
=
'
switch_position
'
,
}
export
class
OnRoomLeavePlayer
extends
RoomEvent
{
export
class
OnRoomLeavePlayer
extends
RoomEvent
{
constructor
(
constructor
(
room
:
Room
,
room
:
Room
,
public
oldPos
:
number
,
public
oldPos
:
number
,
public
reason
:
RoomLeavePlayerReason
,
public
bySystem
=
false
,
)
{
)
{
super
(
room
);
super
(
room
);
}
}
...
...
src/room/room.ts
View file @
4af43c04
...
@@ -71,8 +71,14 @@ import { OnRoomLeave } from './room-event/on-room-leave';
...
@@ -71,8 +71,14 @@ import { OnRoomLeave } from './room-event/on-room-leave';
import
{
OnRoomWin
}
from
'
./room-event/on-room-win
'
;
import
{
OnRoomWin
}
from
'
./room-event/on-room-win
'
;
import
{
OnRoomJoinPlayer
}
from
'
./room-event/on-room-join-player
'
;
import
{
OnRoomJoinPlayer
}
from
'
./room-event/on-room-join-player
'
;
import
{
OnRoomJoinObserver
}
from
'
./room-event/on-room-join-observer
'
;
import
{
OnRoomJoinObserver
}
from
'
./room-event/on-room-join-observer
'
;
import
{
OnRoomLeavePlayer
}
from
'
./room-event/on-room-leave-player
'
;
import
{
import
{
OnRoomLeaveObserver
}
from
'
./room-event/on-room-leave-observer
'
;
OnRoomLeavePlayer
,
RoomLeavePlayerReason
,
}
from
'
./room-event/on-room-leave-player
'
;
import
{
OnRoomLeaveObserver
,
RoomLeaveObserverReason
,
}
from
'
./room-event/on-room-leave-observer
'
;
import
{
OnRoomMatchStart
}
from
'
./room-event/on-room-match-start
'
;
import
{
OnRoomMatchStart
}
from
'
./room-event/on-room-match-start
'
;
import
{
OnRoomGameStart
}
from
'
./room-event/on-room-game-start
'
;
import
{
OnRoomGameStart
}
from
'
./room-event/on-room-game-start
'
;
import
YGOProDeck
from
'
ygopro-deck-encode
'
;
import
YGOProDeck
from
'
ygopro-deck-encode
'
;
...
@@ -590,9 +596,24 @@ export class Room {
...
@@ -590,9 +596,24 @@ export class Room {
// 触发具体的离开事件
// 触发具体的离开事件
if
(
wasObserver
)
{
if
(
wasObserver
)
{
await
this
.
ctx
.
dispatch
(
new
OnRoomLeaveObserver
(
this
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomLeaveObserver
(
this
,
RoomLeaveObserverReason
.
Disconnect
,
_msg
.
bySystem
,
),
client
,
);
}
else
{
}
else
{
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
,
RoomLeavePlayerReason
.
Disconnect
,
_msg
.
bySystem
,
),
client
,
);
}
}
client
.
roomName
=
undefined
;
client
.
roomName
=
undefined
;
...
@@ -638,7 +659,10 @@ export class Room {
...
@@ -638,7 +659,10 @@ export class Room {
this
.
allPlayers
.
forEach
((
p
)
=>
p
.
send
(
this
.
watcherSizeMessage
));
this
.
allPlayers
.
forEach
((
p
)
=>
p
.
send
(
this
.
watcherSizeMessage
));
// 触发事件
// 触发事件
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
,
RoomLeavePlayerReason
.
ToObserver
),
client
,
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinObserver
(
this
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinObserver
(
this
),
client
);
}
}
...
@@ -675,7 +699,10 @@ export class Room {
...
@@ -675,7 +699,10 @@ export class Room {
this
.
allPlayers
.
forEach
((
p
)
=>
p
.
send
(
this
.
watcherSizeMessage
));
this
.
allPlayers
.
forEach
((
p
)
=>
p
.
send
(
this
.
watcherSizeMessage
));
// 触发事件
// 触发事件
await
this
.
ctx
.
dispatch
(
new
OnRoomLeaveObserver
(
this
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomLeaveObserver
(
this
,
RoomLeaveObserverReason
.
ToDuelist
),
client
,
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinPlayer
(
this
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinPlayer
(
this
),
client
);
}
else
if
(
this
.
isTag
)
{
}
else
if
(
this
.
isTag
)
{
// TAG 模式下,已经是玩家,切换到另一个空位
// TAG 模式下,已经是玩家,切换到另一个空位
...
@@ -708,7 +735,14 @@ export class Room {
...
@@ -708,7 +735,14 @@ export class Room {
await
client
.
sendTypeChange
();
await
client
.
sendTypeChange
();
// 触发事件 (玩家切换位置)
// 触发事件 (玩家切换位置)
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomLeavePlayer
(
this
,
oldPos
,
RoomLeavePlayerReason
.
SwitchPosition
,
),
client
,
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinPlayer
(
this
),
client
);
await
this
.
ctx
.
dispatch
(
new
OnRoomJoinPlayer
(
this
),
client
);
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment