Commit 9372c2cd authored by nanahira's avatar nanahira

Merge branch 'v3-multiserver' into v3

parents dd4db6b7 fe181673
...@@ -58,6 +58,25 @@ ...@@ -58,6 +58,25 @@
/*margin-bottom: 1em;*/ /*margin-bottom: 1em;*/
/*}*/ /*}*/
.small-gutters {
margin-right: -5px;
margin-left: 0px;
}
.small-gutters > .col, .small-gutters > [class*="col-"] {
padding-right: 5px;
padding-left: 0px;
}
.small-gutters > .col-sm-4 {
flex: 0 0 40%;
max-width: 40%;
}
.small-gutters > .col-sm-8 {
flex: 0 0 60%;
max-width: 60%;
}
dl { dl {
margin-bottom: 0; margin-bottom: 0;
} }
......
<div *ngIf="!matching" id="action"> <div *ngIf="!matching" id="action">
<button [disabled]="!appsService.allReady(app)" (click)="request_match('athletic')" type="button" class="btn btn-primary btn-sm"> <button [disabled]="!appsService.allReady(app) || currentServer.id !== 'tiramisu'" (click)="request_match('athletic')" type="button" class="btn btn-primary btn-sm">
<i class="fa fa-play" aria-hidden="true"></i> <span i18n>竞技匹配</span></button> <i class="fa fa-play" aria-hidden="true"></i> <span i18n>竞技匹配</span></button>
<button i18n [disabled]="!appsService.allReady(app)" (click)="request_match('entertain')" type="button" class="btn btn-secondary btn-sm">娱乐匹配</button> <button i18n [disabled]="!appsService.allReady(app) || currentServer.id !== 'tiramisu'" (click)="request_match('entertain')" type="button" class="btn btn-secondary btn-sm">娱乐匹配</button>
<button i18n [disabled]="!appsService.allReady(app)" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-list-modal">自定义游戏</button> <button i18n [disabled]="!appsService.allReady(app) || !currentServer.custom" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-list-modal">自定义游戏</button>
<button i18n [disabled]="!appsService.allReady(app)" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-create-windbot">单人模式</button> <button i18n [disabled]="!appsService.allReady(app) || !currentServer.windbot" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-create-windbot">单人模式</button>
<button i18n [disabled]="!appsService.allReady(app)" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-replay-modal">观战录像</button> <button i18n [disabled]="!appsService.allReady(app)" type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#game-replay-modal">观战录像</button>
</div> </div>
<!-- 匹配中 --> <!-- 匹配中 -->
...@@ -17,16 +17,24 @@ ...@@ -17,16 +17,24 @@
<span class="input-group-btn"><button i18n class="btn btn-secondary" type="button" [disabled]="!match_cancelable" (click)="cancel_match()">取消</button></span> <span class="input-group-btn"><button i18n class="btn btn-secondary" type="button" [disabled]="!match_cancelable" (click)="cancel_match()">取消</button></span>
</div> </div>
<div class="input-group input-group-sm"> <div class="row small-gutters">
<div class="col-sm-4 input-group input-group-sm">
<label i18n class="input-group-addon" id="server-label">环境</label>
<select class="form-control form-control-sm" id="selectServer" name="server" [disabled]="!appsService.allReady(app)" [(ngModel)]="currentServer">
<option *ngFor="let server of selectableServers" [ngValue]="server">{{server.name}}</option>
</select>
</div>
<div class="col-sm-8 input-group input-group-sm">
<label i18n class="input-group-addon" id="basic-addon1">卡组</label> <label i18n class="input-group-addon" id="basic-addon1">卡组</label>
<select class="form-control form-control-sm" id="exampleSelect1" name="deck" [(ngModel)]="current_deck"> <select class="form-control form-control-sm" id="exampleSelect1" name="deck" [(ngModel)]="current_deck">
<option *ngFor="let deck of decks" [ngValue]="deck">{{deck}}</option> <option *ngFor="let deck of decks" [ngValue]="deck">{{deck}}</option>
</select> <span class="input-group-btn"> </select> <span class="input-group-btn">
<button id="edit_deck_button" i18n [disabled]="!appsService.allReady(app)" class="btn btn-secondary btn-sm" (click)="edit_deck(current_deck)">编辑</button> <button id="edit_deck_button" i18n [disabled]="!appsService.allReady(app)" class="btn btn-secondary btn-sm" (click)="edit_deck(current_deck)">编辑</button>
</span> </span>
</div>
</div> </div>
<div class="modal fade" id="game-create-windbot" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal fade" id="game-create-windbot" *ngIf="currentServer.windbot" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
...@@ -67,7 +75,7 @@ ...@@ -67,7 +75,7 @@
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let room of rooms" class="room" (click)="join_room(room)"> <tr *ngFor="let room of rooms_show" class="room" (click)="join_room(room)">
<td class="title">{{room.title}}</td> <td class="title">{{room.title}}</td>
<td class="users"> <td class="users">
<img *ngFor="let user of room.users" class="avatar rounded" [src]="'https://ygobbs.com/user_avatar/ygobbs.com/' + user.username + '/25/1.png'" data-toggle="tooltip" data-placement="bottom" [title]="user.username" (error)="avatar_fallback($event)"> <img *ngFor="let user of room.users" class="avatar rounded" [src]="'https://ygobbs.com/user_avatar/ygobbs.com/' + user.username + '/25/1.png'" data-toggle="tooltip" data-placement="bottom" [title]="user.username" (error)="avatar_fallback($event)">
......
...@@ -47,12 +47,15 @@ interface SystemConf { ...@@ -47,12 +47,15 @@ interface SystemConf {
} }
interface Server { interface Server {
id?: string; id: string;
name?: string;
url?: string; url?: string;
address: string; address: string;
port: number; port: number;
hidden?: boolean;
custom?: boolean; custom?: boolean;
replay?: boolean; replay?: boolean;
windbot?: string[];
} }
interface Room { interface Room {
...@@ -93,7 +96,7 @@ export interface Points { ...@@ -93,7 +96,7 @@ export interface Points {
} }
interface YGOProData { interface YGOProData {
windbot: { [locale: string]: string[] }; servers: Server[]
} }
...@@ -129,10 +132,22 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -129,10 +132,22 @@ export class YGOProComponent implements OnInit, OnDestroy {
youtube: ElementRef; youtube: ElementRef;
// points: Points; // points: Points;
windbot: string[]; // ["琪露诺", "谜之剑士LV4", "复制植物", "尼亚"]; get windbot() {
return this.currentServer.windbot;
}
servers: Server[];
selectableServers: Server[];
servers: Server[] = []; //selectingServerId: string;
currentServer: Server;
/*reloadCurrentServer() {
this.currentServer = this.servers.find(s => s.id === this.selectingServerId);
}*/
// tslint:disable-next-line:member-ordering
rooms_loading = true; rooms_loading = true;
default_options: Options = { default_options: Options = {
...@@ -153,6 +168,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -153,6 +168,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
room: Room = {title: this.loginService.user.username + '的房间', options: Object.assign({}, this.default_options)}; room: Room = {title: this.loginService.user.username + '的房间', options: Object.assign({}, this.default_options)};
rooms: Room[] = []; rooms: Room[] = [];
rooms_show: Room[];
connections: WebSocket[] = []; connections: WebSocket[] = [];
replay_connections: WebSocket[] = []; replay_connections: WebSocket[] = [];
...@@ -216,45 +232,17 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -216,45 +232,17 @@ export class YGOProComponent implements OnInit, OnDestroy {
this.refresh_match(); this.refresh_match();
}, 1000); }, 1000);
} }
}
// if (this.settingsService.getLocale().startsWith('zh')) { refresh_rooms() {
this.servers.push({ this.rooms_show = this.rooms.filter((room) => room.server === this.currentServer);
id: 'tiramisu',
url: 'wss://tiramisu.mycard.moe:7923',
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
});
/*} else {
this.servers.push({
id: 'mercury-us-1-athletic',
url: 'wss://mercury-us-1.mycard.moe:7923',
address: 'mercury-us-1.mycard.moe',
port: 7911,
custom: true,
replay: true
}, {
id: 'mercury-us-1',
url: 'wss://mercury-us-1.mycard.moe:7923',
address: 'mercury-us-1.mycard.moe',
port: 8911,
custom: false,
replay: true
});
}*/
} }
refresh_replay_rooms() { refresh_replay_rooms() {
this.replay_rooms_show = this.replay_rooms.filter((room) => { this.replay_rooms_show = this.replay_rooms.filter((room) => {
if (!room.arena && room.server && room.server !== this.currentServer) {
return false;
}
return ((this.replay_rooms_filter.athletic && room.arena === 'athletic') || return ((this.replay_rooms_filter.athletic && room.arena === 'athletic') ||
(this.replay_rooms_filter.entertain && room.arena === 'entertain') || (this.replay_rooms_filter.entertain && room.arena === 'entertain') ||
(this.replay_rooms_filter.single && room.options.mode === 0 && !room.arena && !room.id!.startsWith('AI#')) || (this.replay_rooms_filter.single && room.options.mode === 0 && !room.arena && !room.id!.startsWith('AI#')) ||
...@@ -283,6 +271,10 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -283,6 +271,10 @@ export class YGOProComponent implements OnInit, OnDestroy {
} }
async ngOnInit() { async ngOnInit() {
this.servers = (<YGOProData>this.app.data).servers;
this.selectableServers = this.servers.filter(s => !s.hidden);
this.currentServer = this.selectableServers[0];
//this.reloadCurrentServer();
let locale: string; let locale: string;
if (this.settingsService.getLocale().startsWith('zh')) { if (this.settingsService.getLocale().startsWith('zh')) {
...@@ -290,7 +282,6 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -290,7 +282,6 @@ export class YGOProComponent implements OnInit, OnDestroy {
} else { } else {
locale = 'en-US'; locale = 'en-US';
} }
this.windbot = (<YGOProData>this.app.data).windbot[locale];
this.system_conf = path.join(this.app.local!.path, 'system.conf'); this.system_conf = path.join(this.app.local!.path, 'system.conf');
await this.refresh(); await this.refresh();
...@@ -305,10 +296,12 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -305,10 +296,12 @@ export class YGOProComponent implements OnInit, OnDestroy {
let connection = new WebSocket(url.toString()); let connection = new WebSocket(url.toString());
connection.onclose = (event: CloseEvent) => { connection.onclose = (event: CloseEvent) => {
this.rooms = this.rooms.filter(room => room.server !== server); this.rooms = this.rooms.filter(room => room.server !== server);
this.refresh_rooms();
}; };
connection.onerror = (event: ErrorEvent) => { connection.onerror = (event: ErrorEvent) => {
console.log('error', server.id, event); console.log('error', server.id, event);
this.rooms = this.rooms.filter(room => room.server !== server); this.rooms = this.rooms.filter(room => room.server !== server);
this.refresh_rooms();
}; };
connection.onmessage = (event) => { connection.onmessage = (event) => {
let message = JSON.parse(event.data); let message = JSON.parse(event.data);
...@@ -328,6 +321,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -328,6 +321,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
case 'delete': case 'delete':
this.rooms.splice(this.rooms.findIndex(room => room.server === server && room.id === message.data), 1); this.rooms.splice(this.rooms.findIndex(room => room.server === server && room.id === message.data), 1);
} }
this.refresh_rooms();
this.ref.detectChanges(); this.ref.detectChanges();
}; };
return connection; return connection;
...@@ -503,7 +497,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -503,7 +497,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
}; };
async join(name: string, server: Server) { async join(name: string, server: Server) {
let system_conf = await this.load_system_conf(); /*let system_conf = await this.load_system_conf();
await this.fix_fonts(system_conf); await this.fix_fonts(system_conf);
system_conf.lastdeck = this.current_deck; system_conf.lastdeck = this.current_deck;
system_conf.lastip = server.address; system_conf.lastip = server.address;
...@@ -511,22 +505,22 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -511,22 +505,22 @@ export class YGOProComponent implements OnInit, OnDestroy {
system_conf.lastport = server.port.toString(); system_conf.lastport = server.port.toString();
system_conf.roompass = name; system_conf.roompass = name;
system_conf.nickname = this.loginService.user.username; system_conf.nickname = this.loginService.user.username;
await this.save_system_conf(system_conf); await this.save_system_conf(system_conf);*/
return this.start_game(['-j']); return this.start_game(['-h', server.address, '-p', server.port.toString(), '-w', name, '-n', this.loginService.user.username, '-d', this.current_deck, '-j']);
}; };
async edit_deck(deck: string) { async edit_deck(deck: string) {
let system_conf = await this.load_system_conf(); /*let system_conf = await this.load_system_conf();
await this.fix_fonts(system_conf); await this.fix_fonts(system_conf);
system_conf.lastdeck = deck; system_conf.lastdeck = deck;
await this.save_system_conf(system_conf); await this.save_system_conf(system_conf);*/
return this.start_game(['-d', deck]); return this.start_game(['-d', deck]);
} }
async watch_replay(replay: string) { async watch_replay(replay: string) {
let system_conf = await this.load_system_conf(); /*let system_conf = await this.load_system_conf();
await this.fix_fonts(system_conf); await this.fix_fonts(system_conf);
await this.save_system_conf(system_conf); await this.save_system_conf(system_conf);*/
return this.start_game(['-r', path.join('replay', replay + '.yrp')]); return this.start_game(['-r', path.join('replay', replay + '.yrp')]);
} }
...@@ -534,7 +528,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -534,7 +528,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
if (!name) { if (!name) {
name = this.windbot[Math.floor(Math.random() * this.windbot.length)]; name = this.windbot[Math.floor(Math.random() * this.windbot.length)];
} }
return this.join('AI#' + name, this.servers[0]); return this.join('AI#' + name, this.currentServer);
} }
async start_game(args: string[]) { async start_game(args: string[]) {
...@@ -666,7 +660,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -666,7 +660,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。` body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`
}); });
} }
this.join(password, this.servers[0]); this.join(password, this.currentServer);
} }
copy(text: string, event: Event) { copy(text: string, event: Event) {
...@@ -712,7 +706,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -712,7 +706,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
let name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xFEFF)); let name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xFEFF));
this.join(name, this.servers[0]); this.join(name, this.currentServer);
} }
request_match(arena = 'entertain') { request_match(arena = 'entertain') {
...@@ -729,7 +723,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -729,7 +723,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
} }
}).map(response => response.json()) }).map(response => response.json())
.subscribe((data) => { .subscribe((data) => {
this.join(data['password'], {address: data['address'], port: data['port']}); this.join(data['password'], {id: '_match', address: data['address'], port: data['port']});
}, (error) => { }, (error) => {
alert(`匹配失败`); alert(`匹配失败`);
this.matching = matching = undefined; this.matching = matching = undefined;
......
...@@ -79,6 +79,7 @@ System.config({ ...@@ -79,6 +79,7 @@ System.config({
'tether': 'npm:tether/dist/js/tether.min.js', 'tether': 'npm:tether/dist/js/tether.min.js',
'bootstrap': 'npm:bootstrap/dist/js/bootstrap.min.js', 'bootstrap': 'npm:bootstrap/dist/js/bootstrap.min.js',
'reconnecting-websocket': 'npm:reconnecting-websocket/dist/index.js', 'reconnecting-websocket': 'npm:reconnecting-websocket/dist/index.js',
'popper.js': 'npm:popper.js/dist/umd/popper.min.js',
// 'typeahead.js': '@node/typeahead.js' // 'typeahead.js': '@node/typeahead.js'
'raven-js': 'npm:raven-js' 'raven-js': 'npm:raven-js'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment