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
86b0f261
Commit
86b0f261
authored
Feb 15, 2026
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tag spawn 3 bots
parent
9c10c96b
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
114 additions
and
64 deletions
+114
-64
src/room/default-hostinfo-provder.ts
src/room/default-hostinfo-provder.ts
+2
-3
src/room/index.ts
src/room/index.ts
+1
-0
src/windbot/index.ts
src/windbot/index.ts
+1
-0
src/windbot/join-windbot-ai.ts
src/windbot/join-windbot-ai.ts
+15
-8
src/windbot/join-windbot-token.ts
src/windbot/join-windbot-token.ts
+4
-4
src/windbot/utility/index.ts
src/windbot/utility/index.ts
+3
-0
src/windbot/utility/parse-rule-prefix.ts
src/windbot/utility/parse-rule-prefix.ts
+7
-0
src/windbot/utility/parse-windbot-options.ts
src/windbot/utility/parse-windbot-options.ts
+18
-0
src/windbot/utility/types.ts
src/windbot/utility/types.ts
+16
-0
src/windbot/windbot-provider.ts
src/windbot/windbot-provider.ts
+47
-49
No files found.
src/room/default-hostinfo-provder.ts
View file @
86b0f261
...
@@ -74,11 +74,10 @@ export class DefaultHostInfoProvider {
...
@@ -74,11 +74,10 @@ export class DefaultHostInfoProvider {
}
}
const
rulePrefix
=
name
.
match
(
/
(
.+
)
#/
);
const
rulePrefix
=
name
.
match
(
/
(
.+
)
#/
);
if
(
!
rulePrefix
)
{
const
rule
=
rulePrefix
?
rulePrefix
[
1
].
toUpperCase
()
:
''
;
if
(
!
rule
)
{
return
hostinfo
;
return
hostinfo
;
}
}
const
rule
=
rulePrefix
[
1
].
toUpperCase
();
if
(
/
(
^|,|,
)(
M|MATCH
)(
,|,|$
)
/
.
test
(
rule
))
{
if
(
/
(
^|,|,
)(
M|MATCH
)(
,|,|$
)
/
.
test
(
rule
))
{
hostinfo
.
mode
=
setWinMatchCountBits
(
hostinfo
.
mode
,
2
);
hostinfo
.
mode
=
setWinMatchCountBits
(
hostinfo
.
mode
,
2
);
}
}
...
...
src/room/index.ts
View file @
86b0f261
export
*
from
'
./room
'
;
export
*
from
'
./room
'
;
export
*
from
'
./room-manager
'
;
export
*
from
'
./room-manager
'
;
export
*
from
'
./room-event/on-room-finalize
'
;
export
*
from
'
./room-event/on-room-finalize
'
;
export
*
from
'
./default-hostinfo-provder
'
;
src/windbot/index.ts
View file @
86b0f261
...
@@ -3,3 +3,4 @@ export * from './windbot-spawner';
...
@@ -3,3 +3,4 @@ export * from './windbot-spawner';
export
*
from
'
./join-windbot-ai
'
;
export
*
from
'
./join-windbot-ai
'
;
export
*
from
'
./join-windbot-token
'
;
export
*
from
'
./join-windbot-token
'
;
export
*
from
'
./windbot-module
'
;
export
*
from
'
./windbot-module
'
;
export
*
from
'
./utility
'
;
src/windbot/join-windbot-ai.ts
View file @
86b0f261
...
@@ -3,6 +3,7 @@ import { Context } from '../app';
...
@@ -3,6 +3,7 @@ import { Context } from '../app';
import
{
WindBotProvider
}
from
'
./windbot-provider
'
;
import
{
WindBotProvider
}
from
'
./windbot-provider
'
;
import
{
RoomManager
}
from
'
../room
'
;
import
{
RoomManager
}
from
'
../room
'
;
import
{
fillRandomString
}
from
'
../utility/fill-random-string
'
;
import
{
fillRandomString
}
from
'
../utility/fill-random-string
'
;
import
{
parseWindbotOptions
}
from
'
./utility
'
;
const
getDisplayLength
=
(
text
:
string
)
=>
const
getDisplayLength
=
(
text
:
string
)
=>
text
.
replace
(
/
[^\x
00-
\x
ff
]
/g
,
'
00
'
).
length
;
text
.
replace
(
/
[^\x
00-
\x
ff
]
/g
,
'
00
'
).
length
;
...
@@ -52,16 +53,21 @@ export class JoinWindbotAi {
...
@@ -52,16 +53,21 @@ export class JoinWindbotAi {
room
.
windbot
=
{
room
.
windbot
=
{
name
:
''
,
name
:
''
,
deck
:
''
,
deck
:
''
,
}
};
const
windbotOptions
=
parseWindbotOptions
(
room
.
name
);
await
room
.
join
(
client
);
await
room
.
join
(
client
);
const
requestOk
=
await
this
.
windbotProvider
.
requestWindbotJoin
(
const
requestCount
=
room
.
isTag
?
3
:
1
;
room
,
for
(
let
i
=
0
;
i
<
requestCount
;
i
+=
1
)
{
requestedBotName
,
const
requestOk
=
await
this
.
windbotProvider
.
requestWindbotJoin
(
);
room
,
if
(
!
requestOk
)
{
requestedBotName
,
await
room
.
finalize
();
windbotOptions
,
return
;
);
if
(
!
requestOk
)
{
await
room
.
finalize
();
return
;
}
}
}
this
.
logger
.
debug
(
this
.
logger
.
debug
(
...
@@ -69,6 +75,7 @@ export class JoinWindbotAi {
...
@@ -69,6 +75,7 @@ export class JoinWindbotAi {
player
:
client
.
name
,
player
:
client
.
name
,
roomName
:
room
.
name
,
roomName
:
room
.
name
,
botName
:
room
.
windbot
?.
name
,
botName
:
room
.
windbot
?.
name
,
requestCount
,
},
},
'
Created windbot room
'
,
'
Created windbot room
'
,
);
);
...
...
src/windbot/join-windbot-token.ts
View file @
86b0f261
...
@@ -20,18 +20,18 @@ export class JoinWindbotToken {
...
@@ -20,18 +20,18 @@ export class JoinWindbotToken {
}
}
const
token
=
msg
.
pass
.
slice
(
'
AIJOIN#
'
.
length
);
const
token
=
msg
.
pass
.
slice
(
'
AIJOIN#
'
.
length
);
const
roomName
=
this
.
windbotProvider
.
consumeJoinToken
(
token
);
const
tokenData
=
this
.
windbotProvider
.
consumeJoinToken
(
token
);
if
(
!
roomName
)
{
if
(
!
tokenData
)
{
return
client
.
die
(
'
#{invalid_password_not_found}
'
,
ChatColor
.
RED
);
return
client
.
die
(
'
#{invalid_password_not_found}
'
,
ChatColor
.
RED
);
}
}
const
room
=
this
.
roomManager
.
findByName
(
roomName
);
const
room
=
this
.
roomManager
.
findByName
(
tokenData
.
roomName
);
if
(
!
room
)
{
if
(
!
room
)
{
return
client
.
die
(
'
#{invalid_password_not_found}
'
,
ChatColor
.
RED
);
return
client
.
die
(
'
#{invalid_password_not_found}
'
,
ChatColor
.
RED
);
}
}
client
.
isInternal
=
true
;
client
.
isInternal
=
true
;
client
.
windbot
=
room
.
windbot
;
client
.
windbot
=
tokenData
.
windbot
;
return
room
.
join
(
client
);
return
room
.
join
(
client
);
});
});
}
}
...
...
src/windbot/utility/index.ts
0 → 100644
View file @
86b0f261
export
*
from
'
./types
'
;
export
*
from
'
./parse-rule-prefix
'
;
export
*
from
'
./parse-windbot-options
'
;
src/windbot/utility/parse-rule-prefix.ts
0 → 100644
View file @
86b0f261
export
const
parseRulePrefix
=
(
name
:
string
)
=>
{
const
rulePrefix
=
name
.
match
(
/
(
.+
)
#/
);
if
(
!
rulePrefix
)
{
return
''
;
}
return
rulePrefix
[
1
].
toUpperCase
();
};
src/windbot/utility/parse-windbot-options.ts
0 → 100644
View file @
86b0f261
import
type
{
RequestWindbotJoinOptions
}
from
'
./types
'
;
import
{
parseRulePrefix
}
from
'
./parse-rule-prefix
'
;
export
const
parseWindbotOptions
=
(
name
:
string
):
RequestWindbotJoinOptions
=>
{
const
rule
=
parseRulePrefix
(
name
);
const
options
:
RequestWindbotJoinOptions
=
{};
if
(
!
rule
)
{
return
options
;
}
if
(
/
(
^|,|,
)(
SS|SCISSORS
)(
,|,|$
)
/
.
test
(
rule
))
{
options
.
hand
=
1
;
}
else
if
(
/
(
^|,|,
)(
ROCK
)(
,|,|$
)
/
.
test
(
rule
))
{
options
.
hand
=
2
;
}
else
if
(
/
(
^|,|,
)(
PAPER
)(
,|,|$
)
/
.
test
(
rule
))
{
options
.
hand
=
3
;
}
return
options
;
};
src/windbot/utility/types.ts
0 → 100644
View file @
86b0f261
export
interface
WindbotData
{
name
:
string
;
deck
:
string
;
dialog
?:
string
;
hidden
?:
boolean
;
deckcode
?:
string
;
}
export
interface
RequestWindbotJoinOptions
{
hand
?:
1
|
2
|
3
;
}
export
interface
WindbotJoinTokenData
{
roomName
:
string
;
windbot
:
WindbotData
;
}
src/windbot/windbot-provider.ts
View file @
86b0f261
...
@@ -3,14 +3,11 @@ import * as fs from 'node:fs/promises';
...
@@ -3,14 +3,11 @@ import * as fs from 'node:fs/promises';
import
{
ChatColor
}
from
'
ygopro-msg-encode
'
;
import
{
ChatColor
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../app
'
;
import
{
Context
}
from
'
../app
'
;
import
{
OnRoomFinalize
,
Room
}
from
'
../room
'
;
import
{
OnRoomFinalize
,
Room
}
from
'
../room
'
;
import
type
{
export
interface
WindbotData
{
RequestWindbotJoinOptions
,
name
:
string
;
WindbotData
,
deck
:
string
;
WindbotJoinTokenData
,
dialog
?:
string
;
}
from
'
./utility
'
;
hidden
?:
boolean
;
deckcode
?:
string
;
}
declare
module
'
../client
'
{
declare
module
'
../client
'
{
interface
Client
{
interface
Client
{
...
@@ -36,8 +33,8 @@ export class WindBotProvider {
...
@@ -36,8 +33,8 @@ export class WindBotProvider {
public
botlistPath
=
this
.
ctx
.
config
.
getString
(
'
WINDBOT_BOTLIST
'
);
public
botlistPath
=
this
.
ctx
.
config
.
getString
(
'
WINDBOT_BOTLIST
'
);
private
bots
:
WindbotData
[]
=
[];
private
bots
:
WindbotData
[]
=
[];
private
token
RoomMap
=
new
Map
<
string
,
string
>
();
private
token
DataMap
=
new
Map
<
string
,
WindbotJoinTokenData
>
();
private
roomTokenMap
=
new
Map
<
string
,
string
>
();
private
roomTokenMap
=
new
Map
<
string
,
Set
<
string
>
>
();
constructor
(
private
ctx
:
Context
)
{
constructor
(
private
ctx
:
Context
)
{
if
(
!
this
.
enabled
)
{
if
(
!
this
.
enabled
)
{
...
@@ -73,60 +70,70 @@ export class WindBotProvider {
...
@@ -73,60 +70,70 @@ export class WindBotProvider {
return
this
.
bots
.
find
((
bot
)
=>
bot
.
name
===
name
||
bot
.
deck
===
name
);
return
this
.
bots
.
find
((
bot
)
=>
bot
.
name
===
name
||
bot
.
deck
===
name
);
}
}
issueJoinToken
(
roomName
:
string
)
{
issueJoinToken
(
roomName
:
string
,
windbot
:
WindbotData
)
{
const
oldToken
=
this
.
roomTokenMap
.
get
(
roomName
);
if
(
oldToken
)
{
this
.
tokenRoomMap
.
delete
(
oldToken
);
}
let
token
=
''
;
let
token
=
''
;
do
{
do
{
token
=
cryptoRandomString
({
token
=
cryptoRandomString
({
length
:
12
,
length
:
12
,
type
:
'
alphanumeric
'
,
type
:
'
alphanumeric
'
,
});
});
}
while
(
this
.
token
Room
Map
.
has
(
token
));
}
while
(
this
.
token
Data
Map
.
has
(
token
));
this
.
logger
.
debug
(
this
.
logger
.
debug
(
{
roomName
,
token
},
{
roomName
,
token
},
'
Issuing windbot join token for room
'
,
'
Issuing windbot join token for room
'
,
);
);
this
.
tokenRoomMap
.
set
(
token
,
roomName
);
this
.
tokenDataMap
.
set
(
token
,
{
this
.
roomTokenMap
.
set
(
roomName
,
token
);
roomName
,
windbot
:
{
...
windbot
},
});
let
roomTokens
=
this
.
roomTokenMap
.
get
(
roomName
);
if
(
!
roomTokens
)
{
roomTokens
=
new
Set
<
string
>
();
this
.
roomTokenMap
.
set
(
roomName
,
roomTokens
);
}
roomTokens
.
add
(
token
);
return
token
;
return
token
;
}
}
consumeJoinToken
(
token
:
string
)
{
consumeJoinToken
(
token
:
string
)
{
const
roomName
=
this
.
tokenRoom
Map
.
get
(
token
);
const
data
=
this
.
tokenData
Map
.
get
(
token
);
this
.
logger
.
debug
({
roomName
,
token
},
'
Consuming windbot join token
'
);
this
.
logger
.
debug
({
roomName
:
data
?.
roomName
,
token
},
'
Consuming windbot join token
'
);
if
(
!
roomName
)
{
if
(
!
data
)
{
return
undefined
;
return
undefined
;
}
}
this
.
tokenRoomMap
.
delete
(
token
);
this
.
tokenDataMap
.
delete
(
token
);
const
mappedToken
=
this
.
roomTokenMap
.
get
(
roomName
);
const
roomTokens
=
this
.
roomTokenMap
.
get
(
data
.
roomName
);
if
(
mappedToken
===
token
)
{
if
(
roomTokens
)
{
this
.
roomTokenMap
.
delete
(
roomName
);
roomTokens
.
delete
(
token
);
if
(
roomTokens
.
size
===
0
)
{
this
.
roomTokenMap
.
delete
(
data
.
roomName
);
}
}
}
return
roomName
;
return
data
;
}
}
deleteRoomToken
(
roomName
:
string
)
{
deleteRoomToken
(
roomName
:
string
)
{
const
token
=
this
.
roomTokenMap
.
get
(
roomName
);
const
roomTokens
=
this
.
roomTokenMap
.
get
(
roomName
);
if
(
!
token
)
{
if
(
!
roomTokens
)
{
return
;
return
;
}
}
this
.
roomTokenMap
.
delete
(
roomName
);
this
.
roomTokenMap
.
delete
(
roomName
);
const
mappedRoomName
=
this
.
tokenRoomMap
.
get
(
token
);
for
(
const
token
of
roomTokens
)
{
if
(
mappedRoomName
===
roomName
)
{
const
mappedData
=
this
.
tokenDataMap
.
get
(
token
);
this
.
tokenRoomMap
.
delete
(
token
);
if
(
mappedData
?.
roomName
===
roomName
)
{
this
.
tokenDataMap
.
delete
(
token
);
}
}
}
}
}
async
requestWindbotJoin
(
room
:
Room
,
botname
?:
string
)
{
async
requestWindbotJoin
(
const
roomWindbot
=
room
:
Room
,
this
.
isValidBot
(
room
.
windbot
)
&&
room
.
windbot
?
room
.
windbot
:
undefined
;
botname
?:
string
,
options
:
RequestWindbotJoinOptions
=
{},
)
{
const
bot
=
const
bot
=
(
botname
&&
this
.
getBotByNameOrDeck
(
botname
))
||
roomWindbot
||
this
.
getRandomBot
();
(
botname
&&
this
.
getBotByNameOrDeck
(
botname
))
||
this
.
getRandomBot
();
if
(
!
bot
)
{
if
(
!
bot
)
{
await
room
.
sendChat
(
'
#{windbot_deck_not_found}
'
,
ChatColor
.
RED
);
await
room
.
sendChat
(
'
#{windbot_deck_not_found}
'
,
ChatColor
.
RED
);
return
false
;
return
false
;
...
@@ -138,7 +145,7 @@ export class WindBotProvider {
...
@@ -138,7 +145,7 @@ export class WindBotProvider {
};
};
}
}
Object
.
assign
(
room
.
windbot
,
bot
);
Object
.
assign
(
room
.
windbot
,
bot
);
const
token
=
this
.
issueJoinToken
(
room
.
name
);
const
token
=
this
.
issueJoinToken
(
room
.
name
,
bot
);
let
url
:
URL
;
let
url
:
URL
;
try
{
try
{
...
@@ -164,6 +171,9 @@ export class WindBotProvider {
...
@@ -164,6 +171,9 @@ export class WindBotProvider {
if
(
bot
.
deckcode
)
{
if
(
bot
.
deckcode
)
{
url
.
searchParams
.
set
(
'
deckcode
'
,
bot
.
deckcode
);
url
.
searchParams
.
set
(
'
deckcode
'
,
bot
.
deckcode
);
}
}
if
(
options
.
hand
)
{
url
.
searchParams
.
set
(
'
hand
'
,
options
.
hand
.
toString
());
}
this
.
logger
.
debug
(
this
.
logger
.
debug
(
{
url
:
url
.
toString
(),
roomName
:
room
.
name
},
{
url
:
url
.
toString
(),
roomName
:
room
.
name
},
...
@@ -187,18 +197,6 @@ export class WindBotProvider {
...
@@ -187,18 +197,6 @@ export class WindBotProvider {
}
}
}
}
private
isValidBot
(
bot
:
WindbotData
|
undefined
,
):
bot
is
WindbotData
{
return
!!
(
bot
&&
typeof
bot
.
name
===
'
string
'
&&
bot
.
name
.
length
&&
typeof
bot
.
deck
===
'
string
'
&&
bot
.
deck
.
length
);
}
private
async
loadBotList
()
{
private
async
loadBotList
()
{
try
{
try
{
const
text
=
await
fs
.
readFile
(
this
.
botlistPath
,
'
utf-8
'
);
const
text
=
await
fs
.
readFile
(
this
.
botlistPath
,
'
utf-8
'
);
...
...
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