mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Feature/snake (#1256)
* snake game Co-authored-by: Drew Ansbacher <drew@start9labs.com>
This commit is contained in:
95
frontend/assets/img/icons/bitcoin.svg
Normal file
95
frontend/assets/img/icons/bitcoin.svg
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="23px"
|
||||
height="23px"
|
||||
viewBox="0 0 1 1"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
id="svg2"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="bitcoin-logo-noshadow.svg">
|
||||
<metadata
|
||||
id="metadata22">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1447"
|
||||
inkscape:window-height="861"
|
||||
id="namedview20"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.921875"
|
||||
inkscape:cx="212.51437"
|
||||
inkscape:cy="233.24617"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" />
|
||||
<!-- Android launcher icons: viewBox="-0.045 -0.045 1.09 1.09" -->
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="_drop-shadow"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur
|
||||
in="SourceAlpha"
|
||||
result="blur-out"
|
||||
stdDeviation="1"
|
||||
id="feGaussianBlur7" />
|
||||
<feBlend
|
||||
in="SourceGraphic"
|
||||
in2="blur-out"
|
||||
mode="normal"
|
||||
id="feBlend9" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="coin-gradient"
|
||||
x1="0%"
|
||||
y1="0%"
|
||||
x2="0%"
|
||||
y2="100%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:#f9aa4b"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:#f7931a"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g
|
||||
transform="scale(0.015625)"
|
||||
id="g16">
|
||||
<path
|
||||
id="coin"
|
||||
d="m 63.0359,39.741 c -4.274,17.143 -21.637,27.576 -38.782,23.301 -17.138,-4.274 -27.571,-21.638 -23.295,-38.78 4.272,-17.145 21.635,-27.579 38.775,-23.305 17.144,4.274 27.576,21.64 23.302,38.784 z"
|
||||
style="fill:url(#coin-gradient)" />
|
||||
<path
|
||||
id="symbol"
|
||||
d="m 46.1009,27.441 c 0.637,-4.258 -2.605,-6.547 -7.038,-8.074 l 1.438,-5.768 -3.511,-0.875 -1.4,5.616 c -0.923,-0.23 -1.871,-0.447 -2.813,-0.662 l 1.41,-5.653 -3.509,-0.875 -1.439,5.766 c -0.764,-0.174 -1.514,-0.346 -2.242,-0.527 l 0.004,-0.018 -4.842,-1.209 -0.934,3.75 c 0,0 2.605,0.597 2.55,0.634 1.422,0.355 1.679,1.296 1.636,2.042 l -1.638,6.571 c 0.098,0.025 0.225,0.061 0.365,0.117 -0.117,-0.029 -0.242,-0.061 -0.371,-0.092 l -2.296,9.205 c -0.174,0.432 -0.615,1.08 -1.609,0.834 0.035,0.051 -2.552,-0.637 -2.552,-0.637 l -1.743,4.019 4.569,1.139 c 0.85,0.213 1.683,0.436 2.503,0.646 l -1.453,5.834 3.507,0.875 1.439,-5.772 c 0.958,0.26 1.888,0.5 2.798,0.726 l -1.434,5.745 3.511,0.875 1.453,-5.823 c 5.987,1.133 10.489,0.676 12.384,-4.739 1.527,-4.36 -0.076,-6.875 -3.226,-8.515 2.294,-0.529 4.022,-2.038 4.483,-5.155 z m -8.022,11.249 c -1.085,4.36 -8.426,2.003 -10.806,1.412 l 1.928,-7.729 c 2.38,0.594 10.012,1.77 8.878,6.317 z m 1.086,-11.312 c -0.99,3.966 -7.1,1.951 -9.082,1.457 l 1.748,-7.01 c 1.982,0.494 8.365,1.416 7.334,5.553 z"
|
||||
style="fill:#ffffff" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
BIN
frontend/assets/img/icons/snek.png
Normal file
BIN
frontend/assets/img/icons/snek.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -62,6 +62,17 @@
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
</ion-item-group>
|
||||
<img
|
||||
(click)="openSnek()"
|
||||
style="
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
bottom: 90px;
|
||||
right: 20px;
|
||||
width: 25px;
|
||||
"
|
||||
src="assets/img/icons/snek.png"
|
||||
/>
|
||||
<div
|
||||
style="
|
||||
text-align: center;
|
||||
|
||||
@@ -32,6 +32,7 @@ import { LocalStorageService } from './services/local-storage.service'
|
||||
import { EOSService } from './services/eos.service'
|
||||
import { MarketplaceService } from './pages/marketplace-routes/marketplace.service'
|
||||
import { OSWelcomePage } from './modals/os-welcome/os-welcome.page'
|
||||
import { SnakePage } from './modals/snake/snake.page'
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -39,6 +40,14 @@ import { OSWelcomePage } from './modals/os-welcome/os-welcome.page'
|
||||
styleUrls: ['app.component.scss'],
|
||||
})
|
||||
export class AppComponent {
|
||||
code = {
|
||||
s: false,
|
||||
n: false,
|
||||
e: false,
|
||||
k: false,
|
||||
unlocked: false,
|
||||
}
|
||||
|
||||
@HostListener('document:keydown.enter', ['$event'])
|
||||
@debounce()
|
||||
handleKeyboardEvent() {
|
||||
@@ -48,6 +57,29 @@ export class AppComponent {
|
||||
if (elem) elem.click()
|
||||
}
|
||||
|
||||
@HostListener('document:keypress', ['$event'])
|
||||
async keyPress(e: KeyboardEvent) {
|
||||
if (e.repeat || this.code.unlocked) return
|
||||
if (this.code[e.key] === false) {
|
||||
this.code[e.key] = true
|
||||
}
|
||||
if (
|
||||
Object.entries(this.code)
|
||||
.filter(([key, value]) => key.length === 1)
|
||||
.map(([key, value]) => value)
|
||||
.reduce((a, b) => a && b)
|
||||
) {
|
||||
await this.openSnek()
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('document:keyup', ['$event'])
|
||||
keyUp(e: KeyboardEvent) {
|
||||
if (this.code[e.key]) {
|
||||
this.code[e.key] = false
|
||||
}
|
||||
}
|
||||
|
||||
ServerStatus = ServerStatus
|
||||
showMenu = false
|
||||
selectedIndex = 0
|
||||
@@ -238,6 +270,42 @@ export class AppComponent {
|
||||
}
|
||||
}
|
||||
|
||||
async openSnek() {
|
||||
this.code.unlocked = true
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: SnakePage,
|
||||
cssClass: 'snake-modal',
|
||||
backdropDismiss: false,
|
||||
})
|
||||
|
||||
modal.onDidDismiss().then(async ret => {
|
||||
this.code.unlocked = false
|
||||
if (
|
||||
ret.data.highScore &&
|
||||
(ret.data.highScore >
|
||||
this.patch.data.ui.gaming?.snake?.['high-score'] ||
|
||||
!this.patch.data.ui.gaming?.snake?.['high-score'])
|
||||
) {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
cssClass: 'loader',
|
||||
message: 'Saving High Score...',
|
||||
})
|
||||
await loader.present()
|
||||
try {
|
||||
await this.embassyApi.setDbValue({
|
||||
pointer: '/gaming',
|
||||
value: { snake: { 'high-score': ret.data.highScore } },
|
||||
})
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
this.loadingCtrl.dismiss()
|
||||
}
|
||||
}
|
||||
})
|
||||
modal.present()
|
||||
}
|
||||
// should wipe cache independant of actual BE logout
|
||||
private async logout() {
|
||||
this.embassyApi.logout({})
|
||||
|
||||
11
frontend/projects/ui/src/app/modals/snake/snake.module.ts
Normal file
11
frontend/projects/ui/src/app/modals/snake/snake.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { SnakePage } from './snake.page'
|
||||
|
||||
@NgModule({
|
||||
declarations: [SnakePage],
|
||||
imports: [CommonModule, IonicModule],
|
||||
exports: [SnakePage],
|
||||
})
|
||||
export class SnakePageModule {}
|
||||
23
frontend/projects/ui/src/app/modals/snake/snake.page.html
Normal file
23
frontend/projects/ui/src/app/modals/snake/snake.page.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Play Snek!</ion-title>
|
||||
<ion-title slot="end">Score: {{ score }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
<div class="canvas-center" style="width: 100%">
|
||||
<canvas id="game"> </canvas>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ion-toolbar>
|
||||
<ion-title slot="start">High Score: {{ highScore }}</ion-title>
|
||||
<ion-buttons slot="end" class="ion-padding-end">
|
||||
<ion-button (click)="dismiss()" class="enter-click"
|
||||
>Byeeeeeee!</ion-button
|
||||
>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
@@ -0,0 +1,6 @@
|
||||
.canvas-center {
|
||||
padding-top: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
260
frontend/projects/ui/src/app/modals/snake/snake.page.ts
Normal file
260
frontend/projects/ui/src/app/modals/snake/snake.page.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
import { Component, HostListener } from '@angular/core'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { pauseFor } from '@start9labs/shared'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
|
||||
@Component({
|
||||
selector: 'snake',
|
||||
templateUrl: './snake.page.html',
|
||||
styleUrls: ['./snake.page.scss'],
|
||||
})
|
||||
export class SnakePage {
|
||||
speed = 40
|
||||
width = 40
|
||||
height = 26
|
||||
grid
|
||||
|
||||
startingLength = 4
|
||||
|
||||
score = 0
|
||||
highScore = 0
|
||||
|
||||
xDown: number
|
||||
yDown: number
|
||||
canvas: HTMLCanvasElement
|
||||
image: HTMLImageElement
|
||||
context
|
||||
|
||||
snake
|
||||
bitcoin
|
||||
|
||||
moveQueue: String[] = []
|
||||
|
||||
constructor(
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly patch: PatchDbService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.patch.data.ui.gaming?.snake?.['high-score']) {
|
||||
this.highScore = this.patch.data.ui.gaming?.snake?.['high-score']
|
||||
}
|
||||
}
|
||||
|
||||
async dismiss() {
|
||||
return this.modalCtrl.dismiss({ highScore: this.highScore })
|
||||
}
|
||||
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
keyEvent(e: KeyboardEvent) {
|
||||
this.moveQueue.push(e.key)
|
||||
}
|
||||
|
||||
@HostListener('touchstart', ['$event'])
|
||||
touchStart(e: TouchEvent) {
|
||||
this.handleTouchStart(e)
|
||||
}
|
||||
|
||||
@HostListener('touchmove', ['$event'])
|
||||
touchMove(e: TouchEvent) {
|
||||
this.handleTouchMove(e)
|
||||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
sizeChange(event) {
|
||||
this.init()
|
||||
}
|
||||
|
||||
ionViewDidEnter() {
|
||||
this.init()
|
||||
|
||||
this.image = new Image()
|
||||
this.image.onload = () => {
|
||||
requestAnimationFrame(async () => await this.loop())
|
||||
}
|
||||
this.image.src = '../../../../../../assets/img/icons/bitcoin.svg'
|
||||
}
|
||||
|
||||
init() {
|
||||
this.canvas = document.getElementById('game') as HTMLCanvasElement
|
||||
this.canvas.style.border = '1px solid #e0e0e0'
|
||||
this.context = this.canvas.getContext('2d')
|
||||
const container = document.getElementsByClassName('canvas-center')[0]
|
||||
this.grid = Math.floor(container.clientWidth / this.width)
|
||||
this.snake = {
|
||||
x: this.grid * (Math.floor(this.width / 2) - this.startingLength),
|
||||
y: this.grid * Math.floor(this.height / 2),
|
||||
// snake velocity. moves one grid length every frame in either the x or y direction
|
||||
dx: this.grid,
|
||||
dy: 0,
|
||||
// keep track of all grids the snake body occupies
|
||||
cells: [],
|
||||
// length of the snake. grows when eating an bitcoin
|
||||
maxCells: this.startingLength,
|
||||
}
|
||||
this.bitcoin = {
|
||||
x: this.getRandomInt(0, this.width) * this.grid,
|
||||
y: this.getRandomInt(0, this.height) * this.grid,
|
||||
}
|
||||
|
||||
this.canvas.width = this.grid * this.width
|
||||
this.canvas.height = this.grid * this.height
|
||||
this.context.imageSmoothingEnabled = false
|
||||
}
|
||||
|
||||
getTouches(evt: TouchEvent) {
|
||||
return evt.touches
|
||||
}
|
||||
|
||||
handleTouchStart(evt) {
|
||||
const firstTouch = this.getTouches(evt)[0]
|
||||
this.xDown = firstTouch.clientX
|
||||
this.yDown = firstTouch.clientY
|
||||
}
|
||||
|
||||
handleTouchMove(evt) {
|
||||
if (!this.xDown || !this.yDown) {
|
||||
return
|
||||
}
|
||||
|
||||
var xUp = evt.touches[0].clientX
|
||||
var yUp = evt.touches[0].clientY
|
||||
|
||||
var xDiff = this.xDown - xUp
|
||||
var yDiff = this.yDown - yUp
|
||||
|
||||
if (Math.abs(xDiff) > Math.abs(yDiff)) {
|
||||
/*most significant*/
|
||||
if (xDiff > 0) {
|
||||
this.moveQueue.push('ArrowLeft')
|
||||
} else {
|
||||
this.moveQueue.push('ArrowRight')
|
||||
}
|
||||
} else {
|
||||
if (yDiff > 0) {
|
||||
this.moveQueue.push('ArrowUp')
|
||||
} else {
|
||||
this.moveQueue.push('ArrowDown')
|
||||
}
|
||||
}
|
||||
/* reset values */
|
||||
this.xDown = null
|
||||
this.yDown = null
|
||||
}
|
||||
|
||||
// game loop
|
||||
async loop() {
|
||||
await pauseFor(this.speed)
|
||||
|
||||
requestAnimationFrame(async () => await this.loop())
|
||||
|
||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||
|
||||
// move snake by it's velocity
|
||||
this.snake.x += this.snake.dx
|
||||
this.snake.y += this.snake.dy
|
||||
|
||||
if (this.moveQueue.length) {
|
||||
const move = this.moveQueue.shift()
|
||||
// left arrow key
|
||||
if (move === 'ArrowLeft' && this.snake.dx === 0) {
|
||||
this.snake.dx = -this.grid
|
||||
this.snake.dy = 0
|
||||
}
|
||||
// up arrow key
|
||||
else if (move === 'ArrowUp' && this.snake.dy === 0) {
|
||||
this.snake.dy = -this.grid
|
||||
this.snake.dx = 0
|
||||
}
|
||||
// right arrow key
|
||||
else if (move === 'ArrowRight' && this.snake.dx === 0) {
|
||||
this.snake.dx = this.grid
|
||||
this.snake.dy = 0
|
||||
}
|
||||
// down arrow key
|
||||
else if (move === 'ArrowDown' && this.snake.dy === 0) {
|
||||
this.snake.dy = this.grid
|
||||
this.snake.dx = 0
|
||||
}
|
||||
}
|
||||
|
||||
// edge death
|
||||
if (
|
||||
this.snake.x < 0 ||
|
||||
this.snake.y < 0 ||
|
||||
this.snake.x >= this.canvas.width ||
|
||||
this.snake.y >= this.canvas.height
|
||||
) {
|
||||
this.death()
|
||||
}
|
||||
|
||||
// keep track of where snake has been. front of the array is always the head
|
||||
this.snake.cells.unshift({ x: this.snake.x, y: this.snake.y })
|
||||
|
||||
// remove cells as we move away from them
|
||||
if (this.snake.cells.length > this.snake.maxCells) {
|
||||
this.snake.cells.pop()
|
||||
}
|
||||
|
||||
// draw bitcoin
|
||||
this.context.fillStyle = '#ff4961'
|
||||
this.context.drawImage(
|
||||
this.image,
|
||||
this.bitcoin.x - 1,
|
||||
this.bitcoin.y - 1,
|
||||
this.grid + 2,
|
||||
this.grid + 2,
|
||||
)
|
||||
|
||||
// draw snake one cell at a time
|
||||
this.context.fillStyle = '#2fdf75'
|
||||
|
||||
const firstCell = this.snake.cells[0]
|
||||
|
||||
for (let index = 0; index < this.snake.cells.length; index++) {
|
||||
const cell = this.snake.cells[index]
|
||||
|
||||
// drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
|
||||
this.context.fillRect(cell.x, cell.y, this.grid - 1, this.grid - 1)
|
||||
|
||||
// snake ate bitcoin
|
||||
if (cell.x === this.bitcoin.x && cell.y === this.bitcoin.y) {
|
||||
this.score++
|
||||
if (this.score > this.highScore) this.highScore = this.score
|
||||
this.snake.maxCells++
|
||||
|
||||
this.bitcoin.x = this.getRandomInt(0, this.width) * this.grid
|
||||
this.bitcoin.y = this.getRandomInt(0, this.height) * this.grid
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
// check collision with all cells after this one (modified bubble sort)
|
||||
// snake occupies same space as a body part. reset game
|
||||
if (
|
||||
firstCell.x === this.snake.cells[index].x &&
|
||||
firstCell.y === this.snake.cells[index].y
|
||||
) {
|
||||
this.death()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
death() {
|
||||
this.snake.x =
|
||||
this.grid * (Math.floor(this.width / 2) - this.startingLength)
|
||||
this.snake.y = this.grid * Math.floor(this.height / 2)
|
||||
this.snake.cells = []
|
||||
this.snake.maxCells = this.startingLength
|
||||
this.snake.dx = this.grid
|
||||
this.snake.dy = 0
|
||||
|
||||
this.bitcoin.x = this.getRandomInt(0, 25) * this.grid
|
||||
this.bitcoin.y = this.getRandomInt(0, 25) * this.grid
|
||||
this.score = 0
|
||||
}
|
||||
|
||||
getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<ion-icon slot="start" name="add" size="large" color="dark"></ion-icon>
|
||||
<ion-label>
|
||||
<ion-text color="dark">
|
||||
<b>Add alternative marketplace</b>
|
||||
<b>Add alt marketplace</b>
|
||||
</ion-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
@@ -291,7 +291,7 @@ function getMarketplaceValueSpec(): ValueSpecObject {
|
||||
url: {
|
||||
type: 'string',
|
||||
name: 'URL',
|
||||
description: 'The fully-qualified URL of the alternative marketplace.',
|
||||
description: 'The fully-qualified URL of the alt marketplace.',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ServerShowPage } from './server-show.page'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { TextSpinnerComponentModule } from '@start9labs/shared'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { SnakePageModule } from 'src/app/modals/snake/snake.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -22,6 +23,7 @@ const routes: Routes = [
|
||||
RouterModule.forChild(routes),
|
||||
TextSpinnerComponentModule,
|
||||
BadgeMenuComponentModule,
|
||||
SnakePageModule,
|
||||
],
|
||||
declarations: [ServerShowPage],
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ import { wizardModal } from 'src/app/components/install-wizard/install-wizard.co
|
||||
import { exists, isEmptyObject } from '@start9labs/shared'
|
||||
import { EOSService } from 'src/app/services/eos.service'
|
||||
import { ServerStatus } from 'src/app/services/patch-db/data-model'
|
||||
import { SnakePage } from 'src/app/modals/snake/snake.page'
|
||||
|
||||
@Component({
|
||||
selector: 'server-show',
|
||||
|
||||
@@ -16,6 +16,7 @@ export const mockPatchData: DataModel = {
|
||||
'ack-welcome': '1.0.0',
|
||||
marketplace: undefined,
|
||||
dev: undefined,
|
||||
gaming: undefined,
|
||||
},
|
||||
'server-info': {
|
||||
id: 'embassy-abcdefgh',
|
||||
|
||||
@@ -16,6 +16,13 @@ export interface UIData {
|
||||
'ack-welcome': string // EOS version
|
||||
marketplace: UIMarketplaceData
|
||||
dev: DevData
|
||||
gaming:
|
||||
| {
|
||||
snake: {
|
||||
'high-score': number
|
||||
}
|
||||
}
|
||||
| undefined
|
||||
}
|
||||
|
||||
export interface UIMarketplaceData {
|
||||
|
||||
Reference in New Issue
Block a user