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
91dcb148
Commit
91dcb148
authored
Feb 16, 2026
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add menu
parent
4af43c04
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
545 additions
and
8 deletions
+545
-8
config.example.yaml
config.example.yaml
+11
-0
package-lock.json
package-lock.json
+4
-4
package.json
package.json
+1
-1
src/client/client-handler.ts
src/client/client-handler.ts
+14
-0
src/client/index.ts
src/client/index.ts
+1
-0
src/config.ts
src/config.ts
+9
-0
src/constants/trans.ts
src/constants/trans.ts
+26
-0
src/feats/index.ts
src/feats/index.ts
+1
-0
src/feats/welcome.ts
src/feats/welcome.ts
+16
-3
src/join-handlers/join-blank-pass-menu.ts
src/join-handlers/join-blank-pass-menu.ts
+399
-0
src/join-handlers/join-handler-module.ts
src/join-handlers/join-handler-module.ts
+2
-0
src/room/index.ts
src/room/index.ts
+1
-0
src/utility/index.ts
src/utility/index.ts
+1
-0
src/utility/panel-pagination.ts
src/utility/panel-pagination.ts
+59
-0
No files found.
config.example.yaml
View file @
91dcb148
...
...
@@ -63,6 +63,17 @@ randomDuelDisableChat: 0
randomDuelReadyTime
:
20
randomDuelHangTimeout
:
90
sideTimeoutMinutes
:
3
enableMenu
:
0
menu
:
"
#{menu_random_duel}"
:
"
"
"
#{menu_random_duel_match}"
:
M
"
#{menu_ai_duel}"
:
AI
"
#{menu_more}"
:
"
#{menu_random_duel_single}"
:
S
"
#{menu_random_duel_tag}"
:
T
"
#{menu_ai_duel_match}"
:
AI,M
"
#{menu_ai_duel_tag}"
:
AI,T
"
#{menu_return}"
:
{}
hostinfoLflist
:
0
hostinfoRule
:
0
hostinfoMode
:
0
...
...
package-lock.json
View file @
91dcb148
...
...
@@ -17,7 +17,7 @@
"https-proxy-agent"
:
"^7.0.6"
,
"ipaddr.js"
:
"^2.3.0"
,
"koishipro-core.js"
:
"^1.3.4"
,
"nfkit"
:
"^1.0.3
2
"
,
"nfkit"
:
"^1.0.3
3
"
,
"p-queue"
:
"6.6.2"
,
"pg"
:
"^8.18.0"
,
"pino"
:
"^10.3.1"
,
...
...
@@ -5330,9 +5330,9 @@
"license"
:
"MIT"
},
"node_modules/nfkit"
:
{
"version"
:
"1.0.3
2
"
,
"resolved"
:
"https://registry.npmjs.org/nfkit/-/nfkit-1.0.3
2
.tgz"
,
"integrity"
:
"sha512-
y+UoxDBs6JV4CSBZkidBGK4GfzJ1Qev8uU4m4oClWGs09oxOCh6TQqnOGRaZY1yCmD8yzYcED+8waSMU4WS5fg
=="
,
"version"
:
"1.0.3
3
"
,
"resolved"
:
"https://registry.npmjs.org/nfkit/-/nfkit-1.0.3
3
.tgz"
,
"integrity"
:
"sha512-
mhF4ZAoGUD3cI0sB/+qH2AothZG2j5y18FkyTKF6etR6nod8jBJWQ5hAr3Q6HnaWlG3HpUKN5i1wfZqQP6hyZw
=="
,
"license"
:
"MIT"
},
"node_modules/node-int64"
:
{
...
...
package.json
View file @
91dcb148
...
...
@@ -70,7 +70,7 @@
"
https-proxy-agent
"
:
"
^7.0.6
"
,
"
ipaddr.js
"
:
"
^2.3.0
"
,
"
koishipro-core.js
"
:
"
^1.3.4
"
,
"
nfkit
"
:
"
^1.0.3
2
"
,
"
nfkit
"
:
"
^1.0.3
3
"
,
"
p-queue
"
:
"
6.6.2
"
,
"
pg
"
:
"
^8.18.0
"
,
"
pino
"
:
"
^10.3.1
"
,
...
...
src/client/client-handler.ts
View file @
91dcb148
...
...
@@ -52,6 +52,14 @@ export class ClientHandler {
.
middleware
(
YGOProCtosBase
,
async
(
msg
,
client
,
next
)
=>
{
const
bypassEstablished
=
msg
instanceof
YGOProCtosJoinGame
&&
msg
.
bypassEstablished
;
if
(
bypassEstablished
)
{
delete
msg
.
bypassEstablished
;
return
next
();
}
const
isPreHandshakeMsg
=
[
YGOProCtosExternalAddress
,
YGOProCtosPlayerInfo
,
...
...
@@ -125,3 +133,9 @@ export class ClientHandler {
});
}
}
declare
module
'
ygopro-msg-encode
'
{
interface
YGOProCtosJoinGame
{
bypassEstablished
?:
boolean
;
}
}
src/client/index.ts
View file @
91dcb148
export
*
from
'
./client
'
;
export
*
from
'
./client-handler
'
;
export
*
from
'
./chnroute
'
;
export
*
from
'
./i18n
'
;
src/config.ts
View file @
91dcb148
...
...
@@ -152,6 +152,15 @@ export const defaultConfig = {
// Room hostinfo defaults expanded into HOSTINFO_* keys.
// Format: each HOSTINFO_* value is a string; numeric fields use integer strings.
// Unit note: HOSTINFO_TIME_LIMIT is in seconds (s).
// Enable blank-pass panel menu.
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
ENABLE_MENU
:
'
0
'
,
// Blank-pass panel definition in JSON object format.
// Format: {"Display Text": "ROOM_PASS"}.
// - key: text shown to client; supports i18n placeholder like "#{menu_random_duel}".
// - value(string): equivalent room password, then redispatches CTOS_JOIN_GAME with this pass.
// - value(object): submenu; empty object {} means "return to previous level".
MENU
:
'
{"#{menu_random_duel}":"","#{menu_random_duel_match}":"M","#{menu_ai_duel}":"AI","#{menu_more}":{"#{menu_random_duel_single}":"S","#{menu_random_duel_tag}":"T","#{menu_ai_duel_match}":"AI,M","#{menu_ai_duel_tag}":"AI,T","#{menu_return}":{}}}
'
,
...(
Object
.
fromEntries
(
Object
.
entries
(
DefaultHostinfo
).
map
(([
key
,
value
])
=>
[
`HOSTINFO_
${
key
.
toUpperCase
()}
`
,
...
...
src/constants/trans.ts
View file @
91dcb148
...
...
@@ -82,6 +82,19 @@ export const TRANSLATIONS = {
chat_disabled
:
'
Chat is disabled in this room.
'
,
chat_warn_level1
:
'
Please avoid sensitive words.
'
,
chat_warn_level2
:
'
Your message contains blocked words.
'
,
menu_random_duel
:
'
Random Duel
'
,
menu_random_duel_match
:
'
Random Duel (Match)
'
,
menu_ai_duel
:
'
AI Duel
'
,
menu_more
:
'
More
'
,
menu_random_duel_single
:
'
Random Duel (Single)
'
,
menu_random_duel_tag
:
'
Random Duel (Tag)
'
,
menu_ai_duel_match
:
'
AI Duel (Match)
'
,
menu_ai_duel_tag
:
'
AI Duel (Tag)
'
,
menu_return
:
'
Return
'
,
menu_match_random_duel
:
'
Match Random Duel
'
,
menu_single_random_duel
:
'
Single Random Duel
'
,
menu_prev_page
:
'
Previous Page
'
,
menu_next_page
:
'
Next Page
'
,
},
'
zh-CN
'
:
{
update_required
:
'
请更新你的客户端版本
'
,
...
...
@@ -157,5 +170,18 @@ export const TRANSLATIONS = {
chat_disabled
:
'
本房间禁止聊天。
'
,
chat_warn_level1
:
'
请注意发言,敏感词已被替换。
'
,
chat_warn_level2
:
'
消息包含敏感词,已被拦截。
'
,
menu_random_duel
:
'
随机对战
'
,
menu_random_duel_match
:
'
随机对战(比赛)
'
,
menu_ai_duel
:
'
人机对战
'
,
menu_more
:
'
更多
'
,
menu_random_duel_single
:
'
随机对战(单局)
'
,
menu_random_duel_tag
:
'
随机对战(双打)
'
,
menu_ai_duel_match
:
'
人机对战(比赛)
'
,
menu_ai_duel_tag
:
'
人机对战(双打)
'
,
menu_return
:
'
返回
'
,
menu_match_random_duel
:
'
随机对战(比赛)
'
,
menu_single_random_duel
:
'
随机对战(单局)
'
,
menu_prev_page
:
'
上一页
'
,
menu_next_page
:
'
下一页
'
,
},
};
src/feats/index.ts
View file @
91dcb148
export
*
from
'
./client-version-check
'
;
export
*
from
'
./welcome
'
;
export
*
from
'
./random-duel
'
;
export
*
from
'
./reconnect
'
;
export
*
from
'
./wait-for-player-provider
'
;
...
...
src/feats/welcome.ts
View file @
91dcb148
import
{
ChatColor
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../app
'
;
import
{
Client
}
from
'
../client
'
;
import
{
OnRoomJoin
}
from
'
../room/room-event/on-room-join
'
;
declare
module
'
../room
'
{
...
...
@@ -9,15 +10,19 @@ declare module '../room' {
}
}
declare
module
'
../client
'
{
interface
Client
{
configWelcomeSent
?:
boolean
;
}
}
export
class
Welcome
{
private
welcomeMessage
=
this
.
ctx
.
config
.
getString
(
'
WELCOME
'
);
constructor
(
private
ctx
:
Context
)
{
this
.
ctx
.
middleware
(
OnRoomJoin
,
async
(
event
,
client
,
next
)
=>
{
const
room
=
event
.
room
;
if
(
this
.
welcomeMessage
)
{
await
client
.
sendChat
(
this
.
welcomeMessage
,
ChatColor
.
GREEN
);
}
await
this
.
sendConfigWelcome
(
client
);
if
(
room
.
welcome
)
{
await
client
.
sendChat
(
room
.
welcome
,
ChatColor
.
BABYBLUE
);
}
...
...
@@ -27,4 +32,12 @@ export class Welcome {
return
next
();
});
}
async
sendConfigWelcome
(
client
:
Client
)
{
if
(
!
this
.
welcomeMessage
||
client
.
configWelcomeSent
)
{
return
;
}
client
.
configWelcomeSent
=
true
;
await
client
.
sendChat
(
this
.
welcomeMessage
,
ChatColor
.
GREEN
);
}
}
src/join-handlers/join-blank-pass-menu.ts
0 → 100644
View file @
91dcb148
This diff is collapsed.
Click to expand it.
src/join-handlers/join-handler-module.ts
View file @
91dcb148
...
...
@@ -9,6 +9,7 @@ import { RandomDuelJoinHandler } from './random-duel-join-handler';
import
{
BadwordPlayerInfoChecker
}
from
'
./badword-player-info-checker
'
;
import
{
JoinBlankPassRandomDuel
}
from
'
./join-blank-pass-random-duel
'
;
import
{
JoinBlankPassWindbotAi
}
from
'
./join-blank-pass-windbot-ai
'
;
import
{
JoinBlankPassMenu
}
from
'
./join-blank-pass-menu
'
;
export
const
JoinHandlerModule
=
createAppContext
<
ContextState
>
()
.
provide
(
ClientVersionCheck
)
...
...
@@ -18,6 +19,7 @@ export const JoinHandlerModule = createAppContext<ContextState>()
.
provide
(
RandomDuelJoinHandler
)
.
provide
(
JoinWindbotAi
)
.
provide
(
JoinRoom
)
.
provide
(
JoinBlankPassMenu
)
.
provide
(
JoinBlankPassRandomDuel
)
.
provide
(
JoinBlankPassWindbotAi
)
.
provide
(
JoinFallback
)
...
...
src/room/index.ts
View file @
91dcb148
...
...
@@ -17,3 +17,4 @@ export * from './room-event/on-room-siding-ready';
export
*
from
'
./room-event/on-room-siding-start
'
;
export
*
from
'
./room-event/on-room-win
'
;
export
*
from
'
./default-hostinfo-provder
'
;
export
*
from
'
./default-hostinfo
'
;
src/utility/index.ts
0 → 100644
View file @
91dcb148
export
*
from
'
./panel-pagination
'
;
src/utility/panel-pagination.ts
0 → 100644
View file @
91dcb148
export
type
PanelPageLayout
=
{
pageStarts
:
number
[];
pageIndex
:
number
;
pageStart
:
number
;
isFirstPage
:
boolean
;
isLastPage
:
boolean
;
};
function
resolvePageIndex
(
pageStarts
:
number
[],
requestedStart
:
number
)
{
if
(
!
pageStarts
.
length
)
{
return
0
;
}
if
(
requestedStart
<=
pageStarts
[
0
])
{
return
0
;
}
for
(
let
i
=
pageStarts
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
requestedStart
>=
pageStarts
[
i
])
{
return
i
;
}
}
return
0
;
}
export
function
buildPanelPageStarts
(
totalEntries
:
number
)
{
if
(
totalEntries
<=
4
)
{
return
[
0
];
}
const
pageStarts
=
[
0
];
const
lastPageStart
=
totalEntries
-
3
;
let
cursor
=
3
;
while
(
cursor
<
lastPageStart
)
{
pageStarts
.
push
(
cursor
);
cursor
+=
2
;
}
if
(
pageStarts
[
pageStarts
.
length
-
1
]
!==
lastPageStart
)
{
pageStarts
.
push
(
lastPageStart
);
}
return
pageStarts
;
}
export
function
resolvePanelPageLayout
(
totalEntries
:
number
,
requestedStart
:
number
,
):
PanelPageLayout
{
const
pageStarts
=
buildPanelPageStarts
(
totalEntries
);
const
pageIndex
=
resolvePageIndex
(
pageStarts
,
requestedStart
);
const
pageStart
=
pageStarts
[
pageIndex
]
||
0
;
return
{
pageStarts
,
pageIndex
,
pageStart
,
isFirstPage
:
pageIndex
===
0
,
isLastPage
:
pageIndex
===
pageStarts
.
length
-
1
,
};
}
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