Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mycard Mobile
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
MyCard
Mycard Mobile
Commits
4012759d
Commit
4012759d
authored
Aug 24, 2021
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'multiserver'
parents
9d1505fc
4ce5ee7a
Pipeline
#4954
passed with stages
in 5 minutes and 46 seconds
Changes
14
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
158 additions
and
81 deletions
+158
-81
src/app/app.module.ts
src/app/app.module.ts
+4
-2
src/app/lobby/lobby.component.html
src/app/lobby/lobby.component.html
+4
-4
src/app/lobby/lobby.component.ts
src/app/lobby/lobby.component.ts
+6
-1
src/app/room-list/room-list.component.ts
src/app/room-list/room-list.component.ts
+1
-1
src/app/server-select/server-select.component.css
src/app/server-select/server-select.component.css
+20
-0
src/app/server-select/server-select.component.html
src/app/server-select/server-select.component.html
+8
-0
src/app/server-select/server-select.component.ts
src/app/server-select/server-select.component.ts
+17
-0
src/app/toolbar/toolbar.component.css
src/app/toolbar/toolbar.component.css
+4
-0
src/app/toolbar/toolbar.component.html
src/app/toolbar/toolbar.component.html
+1
-0
src/app/watch/watch.component.ts
src/app/watch/watch.component.ts
+1
-1
src/app/windbot/windbot.component.html
src/app/windbot/windbot.component.html
+1
-1
src/app/ygopro.service.ts
src/app/ygopro.service.ts
+84
-64
src/assets/Spinner-1s-200px.svg
src/assets/Spinner-1s-200px.svg
+3
-2
src/polyfills.ts
src/polyfills.ts
+4
-5
No files found.
src/app/app.module.ts
View file @
4012759d
import
{
ErrorHandler
,
isDevMode
,
NgModule
,
Provider
}
from
'
@angular/core
'
;
import
{
ErrorHandler
,
NgModule
,
Provider
}
from
'
@angular/core
'
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
import
{
MatAutocompleteModule
,
MatAutocompleteModule
,
...
@@ -41,6 +41,7 @@ import * as Raven from 'raven-js';
...
@@ -41,6 +41,7 @@ import * as Raven from 'raven-js';
import
{
DecksComponent
}
from
'
./decks/decks.component
'
;
import
{
DecksComponent
}
from
'
./decks/decks.component
'
;
import
{
ConfirmDialogComponent
}
from
'
./confirm-dialog/confirm-dialog.component
'
;
import
{
ConfirmDialogComponent
}
from
'
./confirm-dialog/confirm-dialog.component
'
;
import
{
LogoutDialogComponent
}
from
'
./logout-dialog/logout-dialog.component
'
;
import
{
LogoutDialogComponent
}
from
'
./logout-dialog/logout-dialog.component
'
;
import
{
ServerSelectComponent
}
from
'
./server-select/server-select.component
'
;
export
class
RavenErrorHandler
implements
ErrorHandler
{
export
class
RavenErrorHandler
implements
ErrorHandler
{
handleError
(
err
:
any
):
void
{
handleError
(
err
:
any
):
void
{
...
@@ -69,7 +70,8 @@ if (environment.production) {
...
@@ -69,7 +70,8 @@ if (environment.production) {
ResultDialogComponent
,
ResultDialogComponent
,
DecksComponent
,
DecksComponent
,
ConfirmDialogComponent
,
ConfirmDialogComponent
,
LogoutDialogComponent
LogoutDialogComponent
,
ServerSelectComponent
],
],
imports
:
[
imports
:
[
BrowserModule
,
BrowserModule
,
...
...
src/app/lobby/lobby.component.html
View file @
4012759d
...
@@ -46,16 +46,16 @@
...
@@ -46,16 +46,16 @@
<br>
娱乐匹配
<br>
娱乐匹配
</button>
</button>
</mat-grid-tile>
</mat-grid-tile>
<mat-grid-tile><a
mat-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms"
>
<mat-grid-tile><a
mat-raised-button
color=
"primary"
(click)=
'reloadServers(["custom"])'
routerLink=
"/ygopro/rooms"
>
<mat-icon>
games
</mat-icon>
<mat-icon>
games
</mat-icon>
<br>
房间列表
</a></mat-grid-tile>
<br>
房间列表
</a></mat-grid-tile>
<mat-grid-tile><a
mat-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms/new"
>
<mat-grid-tile><a
mat-raised-button
color=
"primary"
(click)=
'reloadServers(["custom"])'
routerLink=
"/ygopro/rooms/new"
>
<mat-icon>

</mat-icon>
<!--add_box-->
<mat-icon>

</mat-icon>
<!--add_box-->
<br>
创建房间
</a></mat-grid-tile>
<br>
创建房间
</a></mat-grid-tile>
<mat-grid-tile><a
mat-raised-button
routerLink=
"/ygopro/windbot"
>
<mat-grid-tile><a
mat-raised-button
(click)=
'reloadServers(["windbot"])'
routerLink=
"/ygopro/windbot"
>
<mat-icon>

</mat-icon>
<!-- airplanemode_active -->
<mat-icon>

</mat-icon>
<!-- airplanemode_active -->
<br>
单人模式
</a></mat-grid-tile>
<br>
单人模式
</a></mat-grid-tile>
<mat-grid-tile><a
mat-raised-button
routerLink=
"/ygopro/watch"
>
<mat-grid-tile><a
mat-raised-button
(click)=
'reloadServers(["replay"])'
routerLink=
"/ygopro/watch"
>
<mat-icon>

</mat-icon>
<!--remove_red_eye-->
<mat-icon>

</mat-icon>
<!--remove_red_eye-->
<br>
观战
</a></mat-grid-tile>
<br>
观战
</a></mat-grid-tile>
<!--<mat-grid-tile>-->
<!--<mat-grid-tile>-->
...
...
src/app/lobby/lobby.component.ts
View file @
4012759d
...
@@ -4,13 +4,14 @@ import { environment } from '../../environments/environment';
...
@@ -4,13 +4,14 @@ import { environment } from '../../environments/environment';
import
{
LoginService
}
from
'
../login.service
'
;
import
{
LoginService
}
from
'
../login.service
'
;
import
{
routerTransition
}
from
'
../router.animations
'
;
import
{
routerTransition
}
from
'
../router.animations
'
;
import
{
StorageService
}
from
'
../storage.service
'
;
import
{
StorageService
}
from
'
../storage.service
'
;
import
{
YGOProService
}
from
'
../ygopro.service
'
;
import
{
YGOProService
,
Server
}
from
'
../ygopro.service
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
distinctUntilChanged
,
filter
,
map
,
switchMap
}
from
'
rxjs/internal/operators
'
;
import
{
distinctUntilChanged
,
filter
,
map
,
switchMap
}
from
'
rxjs/internal/operators
'
;
import
{
MatDialog
}
from
'
@angular/material
'
;
import
{
MatDialog
}
from
'
@angular/material
'
;
import
{
LogoutDialogComponent
}
from
'
../logout-dialog/logout-dialog.component
'
;
import
{
LogoutDialogComponent
}
from
'
../logout-dialog/logout-dialog.component
'
;
@
Component
({
@
Component
({
selector
:
'
app-lobby
'
,
selector
:
'
app-lobby
'
,
templateUrl
:
'
lobby.component.html
'
,
templateUrl
:
'
lobby.component.html
'
,
...
@@ -57,6 +58,10 @@ export class LobbyComponent {
...
@@ -57,6 +58,10 @@ export class LobbyComponent {
}
}
}
}
reloadServers
(
fields
:
(
keyof
Server
)[])
{
this
.
ygopro
.
reloadSelectableServers
(
s
=>
fields
.
some
((
field
)
=>
!!
s
[
field
]));
}
search
(
key
:
string
)
{
search
(
key
:
string
)
{
const
url
=
new
URL
(
'
http://www.ourocg.cn/S.aspx
'
);
const
url
=
new
URL
(
'
http://www.ourocg.cn/S.aspx
'
);
url
.
searchParams
.
set
(
'
key
'
,
key
);
url
.
searchParams
.
set
(
'
key
'
,
key
);
...
...
src/app/room-list/room-list.component.ts
View file @
4012759d
...
@@ -15,7 +15,7 @@ export class RoomListComponent implements OnInit {
...
@@ -15,7 +15,7 @@ export class RoomListComponent implements OnInit {
@
HostBinding
(
'
@routerTransition
'
)
animation
;
@
HostBinding
(
'
@routerTransition
'
)
animation
;
displayedColumns
=
[
'
title
'
,
'
users
'
,
'
mode
'
,
'
extra
'
];
displayedColumns
=
[
'
title
'
,
'
users
'
,
'
mode
'
,
'
extra
'
];
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
.
servers
.
filter
(
server
=>
server
.
custom
!
)
);
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
);
constructor
(
public
login
:
LoginService
,
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{}
constructor
(
public
login
:
LoginService
,
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{}
...
...
src/app/server-select/server-select.component.css
0 → 100644
View file @
4012759d
mat-form-field
{
width
:
100px
;
}
mat-select
::ng-deep
.mat-select-arrow-wrapper
{
transform
:
initial
;
}
mat-form-field
::ng-deep
.mat-form-field-underline
{
display
:
none
;
}
mat-form-field
::ng-deep
.mat-form-field-wrapper
,
mat-form-field
::ng-deep
.mat-form-field-flex
{
padding
:
initial
;
}
mat-form-field
::ng-deep
.mat-form-field-infix
{
padding
:
initial
;
border
:
initial
;
}
src/app/server-select/server-select.component.html
0 → 100644
View file @
4012759d
环境:
<mat-form-field
appearance=
'standard'
>
<mat-select
[formControl]=
'ygopro.serverForm'
[(ngModel)]=
'ygopro.currentServer'
>
<mat-option
*ngFor=
'let server of ygopro.selectableServers'
[value]=
'server'
>
{{server.name}}
</mat-option>
</mat-select>
</mat-form-field>
src/app/server-select/server-select.component.ts
0 → 100644
View file @
4012759d
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
YGOProService
}
from
'
../ygopro.service
'
;
@
Component
({
selector
:
'
app-server-select
'
,
templateUrl
:
'
./server-select.component.html
'
,
styleUrls
:
[
'
./server-select.component.css
'
]
})
export
class
ServerSelectComponent
implements
OnInit
{
constructor
(
public
ygopro
:
YGOProService
)
{
}
ngOnInit
()
{
}
}
src/app/toolbar/toolbar.component.css
View file @
4012759d
...
@@ -2,3 +2,7 @@ button {
...
@@ -2,3 +2,7 @@ button {
margin-left
:
-8px
;
margin-left
:
-8px
;
margin-right
:
24px
;
margin-right
:
24px
;
}
}
span
{
flex
:
1
}
src/app/toolbar/toolbar.component.html
View file @
4012759d
...
@@ -3,4 +3,5 @@
...
@@ -3,4 +3,5 @@
<mat-icon>
arrow_back
</mat-icon>
<mat-icon>
arrow_back
</mat-icon>
</button>
</button>
<span><ng-content></ng-content></span>
<span><ng-content></ng-content></span>
<app-server-select></app-server-select>
</mat-toolbar>
</mat-toolbar>
src/app/watch/watch.component.ts
View file @
4012759d
...
@@ -14,7 +14,7 @@ export class WatchComponent implements OnInit {
...
@@ -14,7 +14,7 @@ export class WatchComponent implements OnInit {
@
HostBinding
(
'
@routerTransition
'
)
animation
;
@
HostBinding
(
'
@routerTransition
'
)
animation
;
displayedColumns
=
[
'
mode
'
,
'
title
'
,
'
users
'
,
'
extra
'
];
displayedColumns
=
[
'
mode
'
,
'
title
'
,
'
users
'
,
'
extra
'
];
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
.
servers
,
'
started
'
);
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
,
'
started
'
);
constructor
(
public
login
:
LoginService
,
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{}
constructor
(
public
login
:
LoginService
,
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{}
...
...
src/app/windbot/windbot.component.html
View file @
4012759d
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
<mat-icon
mat-list-icon
>

</mat-icon>
<!-- airplanemode_active -->
<mat-icon
mat-list-icon
>

</mat-icon>
<!-- airplanemode_active -->
<h4
mat-line
>
随机
</h4>
<h4
mat-line
>
随机
</h4>
</mat-list-item>
</mat-list-item>
<mat-list-item
*ngFor=
"let windbot of
ygopro.windbot | async
"
(click)=
"ygopro.join_windbot(windbot)"
>
<mat-list-item
*ngFor=
"let windbot of
(ygopro.currentServer ? ygopro.currentServer.windbot : [])
"
(click)=
"ygopro.join_windbot(windbot)"
>
<img
mat-list-icon
[src]=
"login.avatar(windbot)"
>
<img
mat-list-icon
[src]=
"login.avatar(windbot)"
>
<h4
mat-line
>
{{windbot}}
</h4>
<h4
mat-line
>
{{windbot}}
</h4>
</mat-list-item>
</mat-list-item>
...
...
src/app/ygopro.service.ts
View file @
4012759d
...
@@ -9,8 +9,9 @@ import { MatchDialogComponent } from './match-dialog/match-dialog.component';
...
@@ -9,8 +9,9 @@ import { MatchDialogComponent } from './match-dialog/match-dialog.component';
import
{
ResultDialogComponent
}
from
'
./result-dialog/result-dialog.component
'
;
import
{
ResultDialogComponent
}
from
'
./result-dialog/result-dialog.component
'
;
import
{
StorageService
}
from
'
./storage.service
'
;
import
{
StorageService
}
from
'
./storage.service
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
catchError
,
filter
,
map
,
mergeMap
,
publishLast
,
refCount
,
scan
,
startWith
}
from
'
rxjs/internal/operators
'
;
import
{
catchError
,
filter
,
map
,
mergeMap
,
publishLast
,
refCount
,
scan
,
startWith
,
switchMap
,
tap
}
from
'
rxjs/internal/operators
'
;
import
{
webSocket
}
from
'
rxjs/webSocket
'
;
import
{
webSocket
}
from
'
rxjs/webSocket
'
;
import
{
FormControl
}
from
'
@angular/forms
'
;
export
interface
User
{
export
interface
User
{
admin
:
boolean
;
admin
:
boolean
;
...
@@ -119,8 +120,8 @@ export interface Points {
...
@@ -119,8 +120,8 @@ export interface Points {
export
class
YGOProService
{
export
class
YGOProService
{
news
:
Promise
<
News
[]
>
;
news
:
Promise
<
News
[]
>
;
topics
:
Promise
<
any
[]
>
;
topics
:
Promise
<
any
[]
>
;
windbot
:
Promise
<
string
[]
>
;
points
=
new
BehaviorSubject
<
Points
|
undefined
>
(
undefined
);
points
=
new
BehaviorSubject
<
Points
|
undefined
>
(
undefined
);
serverForm
=
new
FormControl
();
readonly
default_options
:
Options
=
{
readonly
default_options
:
Options
=
{
mode
:
1
,
mode
:
1
,
...
@@ -136,27 +137,25 @@ export class YGOProService {
...
@@ -136,27 +137,25 @@ export class YGOProService {
time_limit
:
180
,
time_limit
:
180
,
auto_death
:
false
auto_death
:
false
};
};
readonly
servers
:
Server
[]
=
[
serversPromise
:
Promise
<
Server
[]
>
;
{
servers
:
Server
[]
=
[];
id
:
'
tiramisu
'
,
selectableServers
:
Server
[]
=
[];
url
:
'
wss://tiramisu.mycard.moe:7923
'
,
currentServer
:
Server
;
address
:
'
tiramisu.mycard.moe
'
,
port
:
7911
,
custom
:
true
,
replay
:
true
},
{
id
:
'
tiramisu-athletic
'
,
url
:
'
wss://tiramisu.mycard.moe:8923
'
,
address
:
'
tiramisu.mycard.moe
'
,
port
:
8911
,
custom
:
false
,
replay
:
true
}
];
constructor
(
private
login
:
LoginService
,
private
http
:
HttpClient
,
private
dialog
:
MatDialog
,
private
storage
:
StorageService
)
{
constructor
(
private
login
:
LoginService
,
private
http
:
HttpClient
,
private
dialog
:
MatDialog
,
private
storage
:
StorageService
)
{
const
app
=
this
.
http
.
get
<
App
[]
>
(
'
https://sapi.moecube.com:444/apps.json
'
).
pipe
(
map
(
apps
=>
apps
.
find
(
_app
=>
_app
.
id
===
'
ygopro
'
)
!
),
publishLast
(),
refCount
());
const
app
=
this
.
http
.
get
<
App
[]
>
(
'
https://sapi.moecube.com:444/apps.json
'
).
pipe
(
map
(
apps
=>
apps
.
find
(
_app
=>
_app
.
id
===
'
ygopro
'
)
!
),
publishLast
(),
refCount
()
);
this
.
serversPromise
=
app
.
pipe
(
map
(
_app
=>
_app
.
data
.
servers
)).
toPromise
();
this
.
serversPromise
.
then
(
servers
=>
{
this
.
servers
=
servers
;
this
.
reloadSelectableServers
();
});
this
.
news
=
app
this
.
news
=
app
.
pipe
(
.
pipe
(
map
(
_app
=>
map
(
_app
=>
...
@@ -171,7 +170,7 @@ export class YGOProService {
...
@@ -171,7 +170,7 @@ export class YGOProService {
)
)
)
)
.
toPromise
();
.
toPromise
();
this
.
windbot
=
app
.
pipe
(
map
(
_app
=>
(
<
YGOProData
>
_app
.
data
).
windbot
[
'
zh-CN
'
])).
toPromise
();
//
this.windbot = app.pipe(map(_app => (<YGOProData>_app.data).windbot['zh-CN'])).toPromise();
this
.
topics
=
this
.
http
this
.
topics
=
this
.
http
.
get
<
TopResponse
>
(
'
https://ygobbs.com/top/quarterly.json
'
)
.
get
<
TopResponse
>
(
'
https://ygobbs.com/top/quarterly.json
'
)
...
@@ -246,6 +245,19 @@ export class YGOProService {
...
@@ -246,6 +245,19 @@ export class YGOProService {
});
});
}
}
reloadSelectableServers
(
condition
:
(
server
:
Server
)
=>
boolean
=
()
=>
true
)
{
this
.
selectableServers
=
this
.
servers
.
filter
(
s
=>
{
if
(
s
.
hidden
)
{
return
false
;
}
return
condition
(
s
);
});
if
(
!
this
.
currentServer
||
!
this
.
selectableServers
.
includes
(
this
.
currentServer
))
{
this
.
currentServer
=
this
.
selectableServers
[
0
];
this
.
serverForm
.
setValue
(
this
.
currentServer
);
}
}
async
request_match
(
arena
:
string
)
{
async
request_match
(
arena
:
string
)
{
const
data
=
await
this
.
dialog
const
data
=
await
this
.
dialog
.
open
(
MatchDialogComponent
,
{
data
:
arena
,
disableClose
:
true
})
.
open
(
MatchDialogComponent
,
{
data
:
arena
,
disableClose
:
true
})
...
@@ -259,15 +271,14 @@ export class YGOProService {
...
@@ -259,15 +271,14 @@ export class YGOProService {
create_room
(
room
:
Room
,
host_password
:
string
)
{
create_room
(
room
:
Room
,
host_password
:
string
)
{
const
options_buffer
=
Buffer
.
alloc
(
6
);
const
options_buffer
=
Buffer
.
alloc
(
6
);
// 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit
// 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit
options_buffer
.
writeUInt8
(((
room
.
private
?
2
:
1
)
<<
4
)
|
options_buffer
.
writeUInt8
(((
room
.
private
?
2
:
1
)
<<
4
)
|
(
room
.
options
.
duel_rule
<<
1
)
|
(
room
.
options
.
auto_death
?
0x1
:
0
),
1
);
(
room
.
options
.
duel_rule
<<
1
)
|
(
room
.
options
.
auto_death
?
0x1
:
0
),
1
);
options_buffer
.
writeUInt8
(
options_buffer
.
writeUInt8
(
room
.
options
.
rule
<<
5
|
(
room
.
options
.
rule
<<
5
)
|
room
.
options
.
mode
<<
3
|
(
room
.
options
.
mode
<<
3
)
|
(
room
.
options
.
no_check_deck
?
1
<<
1
:
0
)
|
(
room
.
options
.
no_check_deck
?
1
<<
1
:
0
)
|
(
room
.
options
.
no_shuffle_deck
?
1
:
0
)
(
room
.
options
.
no_shuffle_deck
?
1
:
0
),
,
2
);
2
);
options_buffer
.
writeUInt16LE
(
room
.
options
.
start_lp
,
3
);
options_buffer
.
writeUInt16LE
(
room
.
options
.
start_lp
,
3
);
options_buffer
.
writeUInt8
((
room
.
options
.
start_hand
<<
4
)
|
room
.
options
.
draw_count
,
5
);
options_buffer
.
writeUInt8
((
room
.
options
.
start_hand
<<
4
)
|
room
.
options
.
draw_count
,
5
);
let
checksum
=
0
;
let
checksum
=
0
;
...
@@ -276,7 +287,7 @@ export class YGOProService {
...
@@ -276,7 +287,7 @@ export class YGOProService {
}
}
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
const
secret
=
this
.
login
.
user
.
external_id
%
65535
+
1
;
const
secret
=
(
this
.
login
.
user
.
external_id
%
65535
)
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
}
}
...
@@ -291,7 +302,7 @@ export class YGOProService {
...
@@ -291,7 +302,7 @@ export class YGOProService {
// body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`
// body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`
// });
// });
// }
// }
this
.
join
(
password
,
this
.
servers
[
0
]
);
this
.
join
(
password
,
this
.
currentServer
);
}
}
join_room
(
room
:
Room
)
{
join_room
(
room
:
Room
)
{
...
@@ -303,7 +314,7 @@ export class YGOProService {
...
@@ -303,7 +314,7 @@ export class YGOProService {
}
}
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
const
secret
=
this
.
login
.
user
.
external_id
%
65535
+
1
;
const
secret
=
(
this
.
login
.
user
.
external_id
%
65535
)
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
}
}
...
@@ -322,21 +333,21 @@ export class YGOProService {
...
@@ -322,21 +333,21 @@ export class YGOProService {
}
}
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0xff
,
0
);
const
secret
=
this
.
login
.
user
.
external_id
%
65535
+
1
;
const
secret
=
(
this
.
login
.
user
.
external_id
%
65535
)
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
options_buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
);
}
}
const
name
=
options_buffer
.
toString
(
'
base64
'
)
+
password
.
replace
(
/
\s
/
,
String
.
fromCharCode
(
0xfeff
));
const
name
=
options_buffer
.
toString
(
'
base64
'
)
+
password
.
replace
(
/
\s
/
,
String
.
fromCharCode
(
0xfeff
));
this
.
join
(
name
,
this
.
servers
[
0
]
);
this
.
join
(
name
,
this
.
currentServer
);
}
}
async
join_windbot
(
name
?:
string
)
{
async
join_windbot
(
name
?:
string
)
{
if
(
!
name
)
{
if
(
!
name
)
{
name
=
sample
(
await
this
.
windbot
);
name
=
sample
(
this
.
currentServer
.
windbot
!
);
}
}
return
this
.
join
(
'
AI#
'
+
name
,
this
.
servers
[
0
]
);
return
this
.
join
(
'
AI#
'
+
name
,
this
.
currentServer
);
}
}
join
(
password
:
string
,
server
:
Server
)
{
join
(
password
:
string
,
server
:
Server
)
{
...
@@ -414,6 +425,10 @@ export class YGOProService {
...
@@ -414,6 +425,10 @@ export class YGOProService {
alert
(
JSON
.
stringify
({
method
:
'
share
'
,
params
:
[
text
]
}));
alert
(
JSON
.
stringify
({
method
:
'
share
'
,
params
:
[
text
]
}));
}
}
}
}
isRoomAvailableToDisplay
(
r
:
Room
)
{
return
(
r
.
arena
&&
this
.
currentServer
&&
this
.
currentServer
.
id
===
'
tiramisu
'
)
||
r
.
server
===
this
.
currentServer
;
}
}
}
type
Message
=
type
Message
=
...
@@ -427,41 +442,47 @@ export class RoomListDataSource extends DataSource<Room> {
...
@@ -427,41 +442,47 @@ export class RoomListDataSource extends DataSource<Room> {
empty
=
new
EventEmitter
();
empty
=
new
EventEmitter
();
error
=
new
EventEmitter
();
error
=
new
EventEmitter
();
constructor
(
private
servers
:
Server
[]
,
private
type
=
'
waiting
'
)
{
constructor
(
private
ygopro
:
YGOProService
,
private
type
=
'
waiting
'
)
{
super
();
super
();
}
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect
():
Observable
<
Room
[]
>
{
connect
():
Observable
<
Room
[]
>
{
this
.
loading
.
emit
(
true
);
this
.
loading
.
emit
(
true
);
return
combineLatest
(
this
.
servers
.
map
(
server
=>
{
return
this
.
ygopro
.
serverForm
.
valueChanges
.
pipe
(
const
url
=
new
URL
(
server
.
url
!
);
this
.
ygopro
.
serverForm
.
value
?
startWith
(
this
.
ygopro
.
serverForm
.
value
)
:
tap
(),
url
.
searchParams
.
set
(
'
filter
'
,
this
.
type
);
switchMap
(
env
=>
// 协议处理
combineLatest
(
return
webSocket
<
Message
>
(
url
.
toString
()).
pipe
(
[
env
].
filter
(
s
=>
s
.
url
&&
(
s
.
custom
||
s
.
replay
)).
map
(
server
=>
{
scan
((
rooms
:
Room
[],
message
:
Message
,
index
:
number
)
=>
{
const
url
=
new
URL
(
server
.
url
!
);
switch
(
message
.
event
)
{
url
.
searchParams
.
set
(
'
filter
'
,
this
.
type
);
case
'
init
'
:
// 协议处理
return
message
.
data
.
map
(
room
=>
({
server
:
server
,
...
room
}));
return
webSocket
<
Message
>
(
url
.
toString
()).
pipe
(
case
'
create
'
:
scan
((
rooms
:
Room
[],
message
:
Message
,
index
:
number
)
=>
{
return
rooms
.
concat
({
server
:
server
,
...
message
.
data
});
switch
(
message
.
event
)
{
case
'
update
'
:
case
'
init
'
:
Object
.
assign
(
rooms
.
find
(
room
=>
room
.
id
===
message
.
data
.
id
),
message
.
data
);
return
message
.
data
.
map
(
room
=>
({
server
:
server
,
...
room
}));
return
rooms
;
case
'
create
'
:
case
'
delete
'
:
return
rooms
.
concat
({
server
:
server
,
...
message
.
data
});
return
rooms
.
filter
(
room
=>
room
.
id
!==
message
.
data
);
case
'
update
'
:
}
Object
.
assign
(
rooms
.
find
(
room
=>
room
.
id
===
message
.
data
.
id
),
message
.
data
);
},
[])
return
rooms
;
);
case
'
delete
'
:
})
return
rooms
.
filter
(
room
=>
room
.
id
!==
message
.
data
);
).
pipe
(
}
},
[])
);
})
)
),
// 把多个服务器的数据拼接起来
// 把多个服务器的数据拼接起来
map
((
sources
:
Room
[][])
=>
(
<
Room
[]
>
[]).
concat
(...
sources
)),
map
((
sources
:
Room
[][])
=>
(
<
Room
[]
>
[]).
concat
(...
sources
)),
// 筛选一下房间,只扔进去当前房间或者竞技匹配的
// 房间排序
// 房间排序
map
(
rooms
=>
map
(
rooms
=>
sortBy
(
rooms
,
room
=>
{
// TODO: reload server on change
sortBy
(
rooms
.
filter
(
r
=>
this
.
ygopro
.
isRoomAvailableToDisplay
(
r
)),
room
=>
{
if
(
room
.
arena
===
'
athletic
'
)
{
if
(
room
.
arena
===
'
athletic
'
)
{
return
0
;
return
0
;
}
else
if
(
room
.
arena
===
'
entertain
'
)
{
}
else
if
(
room
.
arena
===
'
entertain
'
)
{
...
@@ -474,10 +495,9 @@ export class RoomListDataSource extends DataSource<Room> {
...
@@ -474,10 +495,9 @@ export class RoomListDataSource extends DataSource<Room> {
})
})
),
),
// loading、empty、error
// loading、empty、error
filter
(
rooms
=>
{
tap
(
rooms
=>
{
this
.
loading
.
emit
(
false
);
this
.
loading
.
emit
(
false
);
this
.
empty
.
emit
(
rooms
.
length
===
0
);
this
.
empty
.
emit
(
rooms
.
length
===
0
);
return
true
;
}),
}),
catchError
(
error
=>
{
catchError
(
error
=>
{
this
.
loading
.
emit
(
false
);
this
.
loading
.
emit
(
false
);
...
...
src/assets/Spinner-1s-200px.svg
View file @
4012759d
<svg
class=
"lds-spinner"
width=
"200px"
height=
"200px"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
viewBox=
"0 0 100 100"
preserveAspectRatio=
"xMidYMid"
style=
"background: none;"
><g
transform=
"rotate(0 50 50)"
>
<svg
class=
'lds-spinner'
width=
'200px'
height=
'200px'
xmlns=
'http://www.w3.org/2000/svg'
viewBox=
'0 0 100 100'
preserveAspectRatio=
'xMidYMid'
style=
'background: none;'
><g
transform=
"rotate(0 50 50)"
>
<rect
x=
"47"
y=
"24"
rx=
"9.4"
ry=
"4.8"
width=
"6"
height=
"12"
fill=
"#4b99ea"
>
<rect
x=
"47"
y=
"24"
rx=
"9.4"
ry=
"4.8"
width=
"6"
height=
"12"
fill=
"#4b99ea"
>
<animate
attributeName=
"opacity"
values=
"1;0"
keyTimes=
"0;1"
dur=
"1s"
begin=
"-0.9166666666666666s"
repeatCount=
"indefinite"
></animate>
<animate
attributeName=
"opacity"
values=
"1;0"
keyTimes=
"0;1"
dur=
"1s"
begin=
"-0.9166666666666666s"
repeatCount=
"indefinite"
></animate>
</rect>
</rect>
...
@@ -46,4 +47,4 @@
...
@@ -46,4 +47,4 @@
<rect
x=
"47"
y=
"24"
rx=
"9.4"
ry=
"4.8"
width=
"6"
height=
"12"
fill=
"#4b99ea"
>
<rect
x=
"47"
y=
"24"
rx=
"9.4"
ry=
"4.8"
width=
"6"
height=
"12"
fill=
"#4b99ea"
>
<animate
attributeName=
"opacity"
values=
"1;0"
keyTimes=
"0;1"
dur=
"1s"
begin=
"0s"
repeatCount=
"indefinite"
></animate>
<animate
attributeName=
"opacity"
values=
"1;0"
keyTimes=
"0;1"
dur=
"1s"
begin=
"0s"
repeatCount=
"indefinite"
></animate>
</rect>
</rect>
</g></svg>
</g></svg>
\ No newline at end of file
src/polyfills.ts
View file @
4012759d
...
@@ -44,6 +44,10 @@
...
@@ -44,6 +44,10 @@
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
// import 'core-js/es7/reflect';
// import 'core-js/es7/reflect';
import
'
core-js/fn/symbol/async-iterator
'
;
import
'
core-js/fn/symbol/async-iterator
'
;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import
'
zone.js/dist/zone
'
;
// Included with Angular CLI.
/**
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Required to support Web Animations `@angular/platform-browser/animations`.
...
@@ -66,11 +70,6 @@ import 'core-js/fn/symbol/async-iterator';
...
@@ -66,11 +70,6 @@ import 'core-js/fn/symbol/async-iterator';
*/
*/
// (window as any).__Zone_enable_cross_context_check = true;
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import
'
zone.js/dist/zone
'
;
// Included with Angular CLI.
/***************************************************************************************************
/***************************************************************************************************
* APPLICATION IMPORTS
* APPLICATION IMPORTS
*/
*/
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