From 595f8acd105c72118a64689aee75bb51669195c6 Mon Sep 17 00:00:00 2001 From: Tamas Cseh Date: Tue, 19 Jan 2021 08:38:18 +0100 Subject: [PATCH] Add: countdown timer to lap limited multiplayer race events --- CHANGELOG.md | 5 +++ README.md | 1 + package-lock.json | 2 +- package.json | 2 +- projects/rf2-better-ui/src/app/app.module.ts | 7 +++- .../event-handler/event-handler.component.ts | 7 +++- .../garage-handler.component.ts | 5 +++ .../race-countdown-timer.component.html | 1 + .../race-countdown-timer.component.scss | 0 .../race-countdown-timer.component.spec.ts | 25 ++++++++++++ .../race-countdown-timer.component.ts | 30 ++++++++++++++ .../src/app/interfaces/game-phase.ts | 12 ++++++ .../src/app/interfaces/session-info.ts | 40 +++++++++++++++++++ 13 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.html create mode 100644 projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.scss create mode 100644 projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.spec.ts create mode 100644 projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.ts create mode 100644 projects/rf2-better-ui/src/app/interfaces/game-phase.ts create mode 100644 projects/rf2-better-ui/src/app/interfaces/session-info.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f89ec9..8b229b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [2.2.0] - 2021-01-19 +### Added +- Add countdown timer to lap limited multiplayer race events +- Support latest rFactor2 release + ## [2.1.0] - 2021-01-10 ### Added - Remember selected server filters diff --git a/README.md b/README.md index a462873..07fcddb 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ In this repository you can find small modifications for the new rFactor 2 UI - highlight current track in setup popup - disable opacity change animation - remember selected multiplayer server filters +- add countdown timer to lap limited multiplayer race events # How to patch UI files - Compile Better ui: `npm run build.all` diff --git a/package-lock.json b/package-lock.json index 62f504b..6c39477 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "rf2-better-ui", - "version": "2.1.0", + "version": "2.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4548118..9df0397 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rf2-better-ui", - "version": "2.1.0", + "version": "2.2.0", "scripts": { "ng": "ng", "start": "ng serve --live-reload=false", diff --git a/projects/rf2-better-ui/src/app/app.module.ts b/projects/rf2-better-ui/src/app/app.module.ts index 296f4c2..c11ba14 100644 --- a/projects/rf2-better-ui/src/app/app.module.ts +++ b/projects/rf2-better-ui/src/app/app.module.ts @@ -12,6 +12,7 @@ import { GarageHandlerComponent } from './components/garage-handler/garage-handl import { EventHandlerComponent } from './components/event-handler/event-handler.component'; import { SessionsHandlerComponent } from './components/sessions-handler/sessions-handler.component'; import { MultiplayerHandlerComponent } from './components/multiplayer-handler/multiplayer-handler.component'; +import { RaceCountdownTimerComponent } from './components/race-countdown-timer/race-countdown-timer.component'; @NgModule({ imports: [ @@ -27,7 +28,8 @@ import { MultiplayerHandlerComponent } from './components/multiplayer-handler/mu GarageHandlerComponent, EventHandlerComponent, SessionsHandlerComponent, - MultiplayerHandlerComponent + MultiplayerHandlerComponent, + RaceCountdownTimerComponent ], providers: [] }) @@ -59,6 +61,9 @@ export class AppModule implements DoBootstrap { const multiplayerHandlerWebComponent = createCustomElement(MultiplayerHandlerComponent, {injector}); customElements.define("rf-multiplayer-handler", multiplayerHandlerWebComponent); + + const raceCountDownTimerWebComponent = createCustomElement(RaceCountdownTimerComponent, {injector}); + customElements.define("rf-race-countdown-timer", raceCountDownTimerWebComponent); } ngDoBootstrap(appRef: ApplicationRef): void { diff --git a/projects/rf2-better-ui/src/app/components/event-handler/event-handler.component.ts b/projects/rf2-better-ui/src/app/components/event-handler/event-handler.component.ts index 8efb714..01f62d5 100644 --- a/projects/rf2-better-ui/src/app/components/event-handler/event-handler.component.ts +++ b/projects/rf2-better-ui/src/app/components/event-handler/event-handler.component.ts @@ -13,9 +13,14 @@ export class EventHandlerComponent implements OnInit, OnDestroy { private observer: MutationObserver; ngOnInit(): void { + waitForElement('nav em').then((e: Element) => { + const countDown: HTMLElement = document.createElement('rf-race-countdown-timer'); + e.parentElement.appendChild(countDown); + }); + // add rf-chat component to the DOM waitForElement('.camera-wrapper').then(() => { - this.tabHolder = document.querySelector("div[ng-if='eventCtrl.gameState.navigationState']"); + this.tabHolder = document.querySelector('div[ng-if=\'eventCtrl.gameState.navigationState\']'); this.injectChat(); this.observeTabChange(); }); diff --git a/projects/rf2-better-ui/src/app/components/garage-handler/garage-handler.component.ts b/projects/rf2-better-ui/src/app/components/garage-handler/garage-handler.component.ts index 86bd73c..70620dc 100644 --- a/projects/rf2-better-ui/src/app/components/garage-handler/garage-handler.component.ts +++ b/projects/rf2-better-ui/src/app/components/garage-handler/garage-handler.component.ts @@ -22,6 +22,11 @@ export class GarageHandlerComponent implements OnInit { } ngOnInit(): void { + waitForElement('nav em').then((e: Element) => { + const countDown: HTMLElement = document.createElement('rf-race-countdown-timer'); + e.parentElement.appendChild(countDown); + }); + this.listItems = document.querySelectorAll('main section div.thumbnail'); this.findSetupButtons(); diff --git a/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.html b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.html new file mode 100644 index 0000000..07861c0 --- /dev/null +++ b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.html @@ -0,0 +1 @@ +{{time}}s diff --git a/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.scss b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.spec.ts b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.spec.ts new file mode 100644 index 0000000..85db9ed --- /dev/null +++ b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RaceCountdownTimerComponent } from './race-countdown-timer.component'; + +describe('RaceCountdownTimerComponent', () => { + let component: RaceCountdownTimerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ RaceCountdownTimerComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RaceCountdownTimerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.ts b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.ts new file mode 100644 index 0000000..e7d1c4b --- /dev/null +++ b/projects/rf2-better-ui/src/app/components/race-countdown-timer/race-countdown-timer.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable, timer } from 'rxjs'; +import { filter, map, switchMap } from 'rxjs/operators'; +import { SessionInfo } from '../../interfaces/session-info'; +import { GamePhase } from '../../interfaces/game-phase'; + +@Component({ + selector: 'rf-race-countdown-timer', + templateUrl: './race-countdown-timer.component.html', + styleUrls: ['./race-countdown-timer.component.scss'] +}) +export class RaceCountdownTimerComponent implements OnInit { + + public timeLeft$: Observable; + + constructor(private http: HttpClient) { + } + + ngOnInit(): void { + this.timeLeft$ = timer(1, 1000).pipe( + switchMap(() => this.http.get('/rest/watch/sessionInfo')), + filter((info: SessionInfo) => info.session.startsWith('RACE') // race session + && info.gamePhase === GamePhase.BEFORE // before formation lap start + && info.maximumLaps < 1500), // lap limited race + map((info: SessionInfo) => Math.round(info.endEventTime - info.currentEventTime)) + ); + } + +} diff --git a/projects/rf2-better-ui/src/app/interfaces/game-phase.ts b/projects/rf2-better-ui/src/app/interfaces/game-phase.ts new file mode 100644 index 0000000..2ee5f50 --- /dev/null +++ b/projects/rf2-better-ui/src/app/interfaces/game-phase.ts @@ -0,0 +1,12 @@ +export enum GamePhase { + BEFORE, + RECONNAISSANCE, + WALKTHROUGH, + FORMATION, + COUNTDOWN, + GREEN, + SAFETY_CAR, + RED, + CHECKERED, + INVALID +} diff --git a/projects/rf2-better-ui/src/app/interfaces/session-info.ts b/projects/rf2-better-ui/src/app/interfaces/session-info.ts new file mode 100644 index 0000000..9386a62 --- /dev/null +++ b/projects/rf2-better-ui/src/app/interfaces/session-info.ts @@ -0,0 +1,40 @@ +import { GamePhase } from './game-phase'; + +export interface SessionInfo { + trackName: string; + session: string; + currentEventTime: number; + endEventTime: number; + maximumLaps: number; + lapDistance: number; + numberOfVehicles: number; + gamePhase: GamePhase; + yellowFlagState: string; + sectorFlag: string[]; + startLightFrame: number; + numRedLights: number; + inRealtime: boolean; + playerName: string; + playerFileName: string; + darkCloud: number; + raining: number; + ambientTemp: number; + trackTemp: number; + windSpeed: { + x: number; + y: number; + z: number; + velocity: number; + }; + + minPathWetness: number; + averagePathWetness: number; + maxPathWetness: number; + gameMode: string; + passwordProtected: boolean; + serverPort: number; + maxPlayers: number; + serverName: string; + startEventTime: number; + raceCompletion: any; +}