Commit 5ece2fe2 authored by 神楽坂玲奈's avatar 神楽坂玲奈

匹配显示时间

parent 0b9a34ba
...@@ -103,6 +103,10 @@ form { ...@@ -103,6 +103,10 @@ form {
border-color: #008dbb; border-color: #008dbb;
} }
#action { #action, #match-time {
margin-bottom: .5rem; margin-bottom: .5rem;
}
#match-time .input-group-addon {
display: block;
} }
\ No newline at end of file
<div id="action"> <div *ngIf="!matching" id="action">
<button [disabled]="matching||!appsService.allReady(app)" (click)="request_match('athletic')" *ngIf="matching_arena != 'athletic'" type="button" class="btn btn-primary btn-sm"> <button [disabled]="!appsService.allReady(app)" (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)="cancel_match()" *ngIf="matching_arena == 'athletic'" type="button" class="btn btn-primary btn-sm">取消等待</button> <button i18n [disabled]="!appsService.allReady(app)" (click)="request_match('entertain')" type="button" class="btn btn-secondary btn-sm">娱乐匹配</button>
<button i18n [disabled]="matching||!appsService.allReady(app)" (click)="request_match('entertain')" *ngIf="matching_arena != '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)" (click)="cancel_match()" *ngIf="matching_arena == 'entertain'" type="button" class="btn btn-secondary btn-sm">取消等待</button>
<button i18n [disabled]="matching||!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)" 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-create-windbot">单人模式</button>
</div> </div>
<!-- 匹配中 -->
<div *ngIf="matching" id="match-time" class="input-group input-group-sm">
<span class="input-group-addon">
<i class="fa fa-futbol-o fa-spin" aria-hidden="true"></i>
<span i18n *ngIf="matching_arena == 'athletic'">竞技匹配</span>
<span i18n *ngIf="matching_arena == 'entertain'">娱乐匹配</span>
</span>
<span class="input-group-addon"><span i18n>预计时间</span> 03:00</span><span class="input-group-addon"><span i18n>实际时间</span> {{match_time | date:'mm:ss'}}</span>
<span class="input-group-btn"><button class="btn btn-secondary" type="button" [disabled]="!match_cancelable" (click)="cancel_match()">取消</button></span>
</div>
<div class="input-group input-group-sm"> <div class="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> </select> <span class="input-group-btn">
<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>
......
/** /**
* Created by zh99998 on 16/9/2. * Created by zh99998 on 16/9/2.
*/ */
import {Component, OnInit, ChangeDetectorRef, Input, EventEmitter, Output} from '@angular/core'; import {Component, OnInit, ChangeDetectorRef, Input, EventEmitter, Output, OnDestroy} from '@angular/core';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as child_process from 'child_process'; import * as child_process from 'child_process';
...@@ -16,6 +16,7 @@ import {ISubscription} from 'rxjs/Subscription'; ...@@ -16,6 +16,7 @@ import {ISubscription} from 'rxjs/Subscription';
import {AppsService} from './apps.service'; import {AppsService} from './apps.service';
import {SettingsService} from './settings.sevices'; import {SettingsService} from './settings.sevices';
import * as $ from 'jquery'; import * as $ from 'jquery';
import Timer = NodeJS.Timer;
interface SystemConf { interface SystemConf {
use_d3d: string; use_d3d: string;
...@@ -90,6 +91,7 @@ interface YGOProData { ...@@ -90,6 +91,7 @@ interface YGOProData {
let matching: ISubscription | undefined; let matching: ISubscription | undefined;
let matching_arena: string | undefined; let matching_arena: string | undefined;
let match_started_at: Date;
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
...@@ -97,7 +99,7 @@ let matching_arena: string | undefined; ...@@ -97,7 +99,7 @@ let matching_arena: string | undefined;
templateUrl: 'ygopro.component.html', templateUrl: 'ygopro.component.html',
styleUrls: ['ygopro.component.css'], styleUrls: ['ygopro.component.css'],
}) })
export class YGOProComponent implements OnInit { export class YGOProComponent implements OnInit, OnDestroy {
@Input() @Input()
app: App; app: App;
@Input() @Input()
...@@ -138,9 +140,12 @@ export class YGOProComponent implements OnInit { ...@@ -138,9 +140,12 @@ export class YGOProComponent implements OnInit {
matching: ISubscription | undefined; matching: ISubscription | undefined;
matching_arena: string | undefined; matching_arena: string | undefined;
match_time: number;
match_cancelable: boolean;
match_interval: Timer | undefined;
constructor(private http: Http, private appsService: AppsService, private loginService: LoginService, constructor (private http: Http, private appsService: AppsService, private loginService: LoginService,
private settingsService: SettingsService, private ref: ChangeDetectorRef) { private settingsService: SettingsService, private ref: ChangeDetectorRef) {
switch (process.platform) { switch (process.platform) {
case 'darwin': case 'darwin':
this.numfont = ['/System/Library/Fonts/SFNSTextCondensed-Bold.otf']; this.numfont = ['/System/Library/Fonts/SFNSTextCondensed-Bold.otf'];
...@@ -156,8 +161,14 @@ export class YGOProComponent implements OnInit { ...@@ -156,8 +161,14 @@ export class YGOProComponent implements OnInit {
break; break;
} }
this.matching = matching; if (matching) {
this.matching_arena = matching_arena; this.matching = matching;
this.matching_arena = matching_arena;
this.refresh_match();
this.match_interval = setInterval(() => {
this.refresh_match()
}, 1000)
}
if (this.settingsService.getLocale().startsWith('zh')) { if (this.settingsService.getLocale().startsWith('zh')) {
this.servers.push({ this.servers.push({
...@@ -177,7 +188,7 @@ export class YGOProComponent implements OnInit { ...@@ -177,7 +188,7 @@ export class YGOProComponent implements OnInit {
} }
async ngOnInit() { async ngOnInit () {
let locale: string; let locale: string;
if (this.settingsService.getLocale().startsWith('zh')) { if (this.settingsService.getLocale().startsWith('zh')) {
...@@ -235,7 +246,7 @@ export class YGOProComponent implements OnInit { ...@@ -235,7 +246,7 @@ export class YGOProComponent implements OnInit {
}); });
} }
async refresh() { async refresh () {
let decks = await this.get_decks(); let decks = await this.get_decks();
this.decks = decks; this.decks = decks;
let system_conf = await this.load_system_conf(); let system_conf = await this.load_system_conf();
...@@ -258,7 +269,7 @@ export class YGOProComponent implements OnInit { ...@@ -258,7 +269,7 @@ export class YGOProComponent implements OnInit {
} }
}; };
get_decks(): Promise<string[]> { get_decks (): Promise<string[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readdir(path.join(this.app.local!.path, 'deck'), (error, files) => { fs.readdir(path.join(this.app.local!.path, 'deck'), (error, files) => {
if (error) { if (error) {
...@@ -270,7 +281,7 @@ export class YGOProComponent implements OnInit { ...@@ -270,7 +281,7 @@ export class YGOProComponent implements OnInit {
}); });
} }
async get_font(files: string[]): Promise<string | undefined> { async get_font (files: string[]): Promise<string | undefined> {
for (let file of files) { for (let file of files) {
let found = await new Promise((resolve) => fs.access(file, fs.constants.R_OK, error => resolve(!error))); let found = await new Promise((resolve) => fs.access(file, fs.constants.R_OK, error => resolve(!error)));
if (found) { if (found) {
...@@ -279,14 +290,14 @@ export class YGOProComponent implements OnInit { ...@@ -279,14 +290,14 @@ export class YGOProComponent implements OnInit {
} }
} }
async delete_deck(deck: string) { async delete_deck (deck: string) {
if (confirm('确认删除?')) { if (confirm('确认删除?')) {
await new Promise(resolve => fs.unlink(path.join(this.app.local!.path, 'deck', deck + '.ydk'), resolve)); await new Promise(resolve => fs.unlink(path.join(this.app.local!.path, 'deck', deck + '.ydk'), resolve));
return this.refresh(); return this.refresh();
} }
} }
async fix_fonts(data: SystemConf) { async fix_fonts (data: SystemConf) {
if (!await this.get_font([data.numfont])) { if (!await this.get_font([data.numfont])) {
let font = await this.get_font(this.numfont); let font = await this.get_font(this.numfont);
if (font) { if (font) {
...@@ -302,7 +313,7 @@ export class YGOProComponent implements OnInit { ...@@ -302,7 +313,7 @@ export class YGOProComponent implements OnInit {
} }
}; };
load_system_conf(): Promise<SystemConf> { load_system_conf (): Promise<SystemConf> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readFile(this.system_conf, {encoding: 'utf-8'}, (error, data) => { fs.readFile(this.system_conf, {encoding: 'utf-8'}, (error, data) => {
if (error) { if (error) {
...@@ -313,7 +324,7 @@ export class YGOProComponent implements OnInit { ...@@ -313,7 +324,7 @@ export class YGOProComponent implements OnInit {
}); });
}; };
save_system_conf(data: SystemConf) { save_system_conf (data: SystemConf) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.writeFile(this.system_conf, ini.unsafe(ini.stringify(data, <EncodeOptions>{whitespace: true})), (error) => { fs.writeFile(this.system_conf, ini.unsafe(ini.stringify(data, <EncodeOptions>{whitespace: true})), (error) => {
if (error) { if (error) {
...@@ -324,7 +335,7 @@ export class YGOProComponent implements OnInit { ...@@ -324,7 +335,7 @@ export class YGOProComponent implements OnInit {
}); });
}; };
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;
...@@ -337,7 +348,7 @@ export class YGOProComponent implements OnInit { ...@@ -337,7 +348,7 @@ export class YGOProComponent implements OnInit {
return this.start_game(['-j']); return this.start_game(['-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;
...@@ -345,11 +356,11 @@ export class YGOProComponent implements OnInit { ...@@ -345,11 +356,11 @@ export class YGOProComponent implements OnInit {
return this.start_game(['-d']); return this.start_game(['-d']);
} }
join_windbot(name: string) { join_windbot (name: string) {
return this.join('AI#' + name, this.servers[0]); return this.join('AI#' + name, this.servers[0]);
} }
async start_game(args: string[]) { async start_game (args: string[]) {
let win = remote.getCurrentWindow(); let win = remote.getCurrentWindow();
win.minimize(); win.minimize();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
...@@ -361,7 +372,7 @@ export class YGOProComponent implements OnInit { ...@@ -361,7 +372,7 @@ export class YGOProComponent implements OnInit {
reject(error); reject(error);
win.restore(); win.restore();
}); });
child.on('exit', async(code, signal) => { child.on('exit', async (code, signal) => {
// error 触发之后还可能会触发exit,但是Promise只承认首次状态转移,因此这里无需重复判断是否已经error过。 // error 触发之后还可能会触发exit,但是Promise只承认首次状态转移,因此这里无需重复判断是否已经error过。
await this.refresh(); await this.refresh();
resolve(); resolve();
...@@ -370,7 +381,7 @@ export class YGOProComponent implements OnInit { ...@@ -370,7 +381,7 @@ export class YGOProComponent implements OnInit {
}); });
}; };
create_room(room: Room) { create_room (room: Room) {
let options_buffer = new Buffer(6); let options_buffer = new Buffer(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, 1); options_buffer.writeUInt8((room.private ? 2 : 1) << 4, 1);
...@@ -401,7 +412,7 @@ export class YGOProComponent implements OnInit { ...@@ -401,7 +412,7 @@ export class YGOProComponent implements OnInit {
this.join(password, this.servers[0]); this.join(password, this.servers[0]);
} }
join_room(room: Room) { join_room (room: Room) {
let options_buffer = new Buffer(6); let options_buffer = new Buffer(6);
options_buffer.writeUInt8(3 << 4, 1); options_buffer.writeUInt8(3 << 4, 1);
let checksum = 0; let checksum = 0;
...@@ -421,35 +432,57 @@ export class YGOProComponent implements OnInit { ...@@ -421,35 +432,57 @@ export class YGOProComponent implements OnInit {
this.join(password, room.server!); this.join(password, room.server!);
} }
request_match(arena = 'entertain') { request_match (arena = 'entertain') {
let headers = new Headers(); let headers = new Headers();
headers.append('Authorization', headers.append('Authorization',
'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64')); 'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64'));
let search = new URLSearchParams(); let search = new URLSearchParams();
search.set('arena', arena); search.set('arena', arena);
search.set('locale', this.settingsService.getLocale()); search.set('locale', this.settingsService.getLocale());
match_started_at = new Date();
this.matching_arena = matching_arena = arena; this.matching_arena = matching_arena = arena;
this.matching = matching = this.http.post('https://api.mycard.moe/ygopro/match', null, { this.matching = matching = this.http.post('https://api.mycard.moe/ygopro/match', null, {
headers: headers, headers: headers,
search: search search: search
}).map(response => response.json()) }).map(response => response.json())
.subscribe((data) => { .subscribe((data) => {
this.join(data['password'], { this.join(data['password'], {address: data['address'], port: data['port']});
address: data['address'],
port: data['port']
});
}, (error) => { }, (error) => {
alert(`匹配失败\n${error}`); alert(`匹配失败\n${error}`);
}, () => { }, () => {
this.matching = matching = undefined; this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined; this.matching_arena = matching_arena = undefined;
this.ref.detectChanges(); if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined
}
}); });
this.refresh_match();
this.match_interval = setInterval(() => {
this.refresh_match()
}, 1000)
} }
cancel_match() { cancel_match () {
this.matching!.unsubscribe(); this.matching!.unsubscribe();
this.matching = matching = undefined; this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined; this.matching_arena = matching_arena = undefined;
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined
}
}
ngOnDestroy () {
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined
}
}
refresh_match () {
this.match_time = new Date().getTime() - match_started_at.getTime();
this.match_cancelable = this.match_time <= 5000 || this.match_time >= 180000;
} }
} }
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