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

匹配显示时间

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