Skip to content

Commit

Permalink
initial implementation that should work already!
Browse files Browse the repository at this point in the history
  • Loading branch information
zardoy committed Jun 27, 2024
1 parent b9f3e67 commit e9aa0e9
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 52 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Vercel Deploy Preview
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
issue_comment:
types: [created]
push:
branches:
- perf-test
jobs:
deploy:
runs-on: ubuntu-latest
# todo skip already created deploys on that commit
if: >-
github.event.issue.pull_request != '' &&
(
contains(github.event.comment.body, '/benchmark')
)
permissions:
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.issue.number }}/head
- run: npm i -g pnpm@9.0.4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
- run: pnpm install
- run: pnpm build
- run: pnpm test:benchmark
# read benchmark results from stdout
- run: echo "BENCHMARK_RESULT=$(cat benchmark.txt)" >> $GITHUB_ENV
- uses: mshick/add-pr-comment@v2
with:
allow-repeats: true
message: |
Benchmark result: ${{ env.BENCHMARK_RESULT }}
4 changes: 3 additions & 1 deletion cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { defineConfig } from 'cypress'

const isPerformanceTest = process.env.PERFORMANCE_TEST === 'true'

export default defineConfig({
video: false,
chromeWebSecurity: false,
Expand Down Expand Up @@ -31,7 +33,7 @@ export default defineConfig({
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:8080',
specPattern: 'cypress/e2e/**/*.spec.ts',
specPattern: !isPerformanceTest ? 'cypress/e2e/**/*.spec.ts' : 'cypress/e2e/rendering_performance.spec.ts',
excludeSpecPattern: ['**/__snapshots__/*', '**/__image_snapshots__/*'],
},
})
37 changes: 37 additions & 0 deletions cypress/e2e/rendering_performance.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
import { BenchmarkAdapter } from '../../src/benchmarkAdapter'
import { setOptions, cleanVisit, visit } from './shared'

it('Benchmark rendering performance', () => {
cleanVisit('/?openBenchmark=true&renderDistance=5')
// wait for render end event
return cy.document().then({ timeout: 120_000 }, doc => {
return new Cypress.Promise(resolve => {
cy.log('Waiting for world to load')
doc.addEventListener('cypress-world-ready', resolve)
}).then(() => {
cy.log('World loaded')
})
}).then(() => {
cy.window().then(win => {
const adapter = win.benchmarkAdapter as BenchmarkAdapter
const renderTimeWorst = adapter.worstRenderTime
const renderTimeAvg = adapter.averageRenderTime
const fpsWorst = 1000 / renderTimeWorst
const fpsAvg = 1000 / renderTimeAvg
const totalTime = adapter.worldLoadTime

const messages = [
`Worst FPS: ${fpsWorst.toFixed(2)}`,
`Average FPS: ${fpsAvg.toFixed(2)}`,
`Total time: ${totalTime.toFixed(2)}s`,
`Memory usage average: ${adapter.memoryUsageAverage.toFixed(2)}MB`,
`Memory usage worst: ${adapter.memoryUsageWorst.toFixed(2)}MB`,
]
for (const message of messages) {
cy.log(message)
}
cy.writeFile('benchmark.txt', messages.join('\n'))
})
})
})
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build": "node scripts/build.js copyFiles && node scripts/prepareData.mjs -f && node esbuild.mjs --minify --prod",
"check-build": "tsc && pnpm build",
"test:cypress": "cypress run",
"test:benchmark": "PERFORMANCE_TEST=true cypress run",
"test-unit": "vitest",
"test:e2e": "start-test http-get://localhost:8080 test:cypress",
"prod-start": "node server.js",
Expand Down Expand Up @@ -63,7 +64,7 @@
"esbuild-plugin-polyfill-node": "^0.3.0",
"express": "^4.18.2",
"filesize": "^10.0.12",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.29",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.32",
"fs-extra": "^11.1.1",
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
"iconify-icon": "^1.0.8",
Expand Down
33 changes: 26 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions prismarine-viewer/viewer/lib/viewerWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ export class ViewerWrapper {
windowFocused = true
trackWindowFocus () {
window.addEventListener('focus', () => {
console.log('window focused')
this.windowFocused = true
})
window.addEventListener('blur', () => {
console.log('window blurred')
this.windowFocused = false
})
}
Expand Down
20 changes: 6 additions & 14 deletions prismarine-viewer/viewer/lib/worldrendererThree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export class WorldRendererThree extends WorldRendererCommon {
signsCache = new Map<string, any>()
starField: StarField
cameraSectionPos: Vec3 = new Vec3(0, 0, 0)
worstRenderTime = 0
avgRenderTime = 0

get tilesRendered () {
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0)
Expand Down Expand Up @@ -72,20 +74,6 @@ export class WorldRendererThree extends WorldRendererCommon {
const chunkCoords = data.key.split(',')
if (!this.loadedChunks[chunkCoords[0] + ',' + chunkCoords[2]] || !data.geometry.positions.length || !this.active) return

// if (!this.initialChunksLoad && this.enableChunksLoadDelay) {
// const newPromise = new Promise(resolve => {
// if (this.droppedFpsPercentage > 0.5) {
// setTimeout(resolve, 1000 / 50 * this.droppedFpsPercentage)
// } else {
// setTimeout(resolve)
// }
// })
// this.promisesQueue.push(newPromise)
// for (const promise of this.promisesQueue) {
// await promise
// }
// }

const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3))
geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3))
Expand Down Expand Up @@ -163,7 +151,11 @@ export class WorldRendererThree extends WorldRendererCommon {
render () {
tweenJs.update()
const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera
const start = performance.now()
this.renderer.render(this.scene, cam)
const totalTime = performance.now() - start
this.avgRenderTime = this.avgRenderTime * 0.9 + totalTime * 0.1 // exponential moving average
this.worstRenderTime = Math.max(this.worstRenderTime, totalTime)
}

renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) {
Expand Down
73 changes: 73 additions & 0 deletions src/benchmark.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Vec3 } from 'vec3'
import { downloadAndOpenFileFromUrl } from './downloadAndOpenFile'
import { activeModalStack, miscUiState } from './globalState'
import { options } from './optionsStorage'
import { BenchmarkAdapter } from './benchmarkAdapter'

const testWorldFixtureUrl = 'https://bucket.mcraft.fun/Future CITY 4.4-slim.zip'
const testWorldFixtureSpawn = [-133, 87, 309] as const

export const openBenchmark = async (renderDistance = 8) => {
let memoryUsageAverage = 0
let memoryUsageSamples = 0
let memoryUsageWorst = 0
setInterval(() => {
const memoryUsage = (window.performance as any)?.memory?.usedJSHeapSize
if (memoryUsage) {
memoryUsageAverage = (memoryUsageAverage * memoryUsageSamples + memoryUsage) / (memoryUsageSamples + 1)
memoryUsageSamples++
if (memoryUsage > memoryUsageWorst) {
memoryUsageWorst = memoryUsage
}
}
}, 200)

const benchmarkAdapter: BenchmarkAdapter = {
get worldLoadTime () {
return window.worldLoadTime
},
get averageRenderTime () {
return window.viewer.world.avgRenderTime
},
get worstRenderTime () {
return window.viewer.world.worstRenderTime
},
get memoryUsageAverage () {
return memoryUsageAverage
},
get memoryUsageWorst () {
return memoryUsageWorst
}
}
window.benchmarkAdapter = benchmarkAdapter

options.renderDistance = renderDistance
void downloadAndOpenFileFromUrl(testWorldFixtureUrl, undefined, {
connectEvents: {
serverCreated () {
if (testWorldFixtureSpawn) {
localServer!.spawnPoint = new Vec3(...testWorldFixtureSpawn)
localServer!.on('newPlayer', (player) => {
player.on('dataLoaded', () => {
player.position = new Vec3(...testWorldFixtureSpawn)
})
})
}
},
}
})
}

export const registerOpenBenchmarkListener = () => {
const params = new URLSearchParams(window.location.search)
if (params.get('openBenchmark')) {
void openBenchmark(params.has('renderDistance') ? +params.get('renderDistance')! : undefined)
}

window.addEventListener('keydown', (e) => {
if (e.code === 'KeyB' && e.shiftKey && !miscUiState.gameLoaded && activeModalStack.length === 0) {
e.preventDefault()
void openBenchmark()
}
})
}
7 changes: 7 additions & 0 deletions src/benchmarkAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface BenchmarkAdapter {
worldLoadTime: number
averageRenderTime: number
worstRenderTime: number
memoryUsageAverage: number
memoryUsageWorst: number
}
5 changes: 3 additions & 2 deletions src/browserfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { fsState, loadSave } from './loadSave'
import { installTexturePack, installTexturePackFromHandle, updateTexturePackInstalledState } from './texturePack'
import { miscUiState } from './globalState'
import { setLoadingScreenStatus } from './utils'
import { ConnectOptions } from './connect'
const { GoogleDriveFileSystem } = require('google-drive-browserfs/src/backends/GoogleDrive') // disable type checking

browserfs.install(window)
Expand Down Expand Up @@ -434,7 +435,7 @@ export const copyFilesAsync = async (pathSrc: string, pathDest: string, fileCopi
}

// todo rename method
const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name']) => {
const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name'], connectOptions?: Partial<ConnectOptions>) => {
await new Promise<void>(async resolve => {
browserfs.configure({
// todo
Expand Down Expand Up @@ -478,7 +479,7 @@ const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name'])
}

if (availableWorlds.length === 1) {
await loadSave(`/world/${availableWorlds[0]}`)
await loadSave(`/world/${availableWorlds[0]}`, connectOptions)
return
}

Expand Down
29 changes: 19 additions & 10 deletions src/connect.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
export type ConnectOptions = {
server?: string;
singleplayer?: any;
username: string;
password?: any;
proxy?: any;
botVersion?: any;
serverOverrides?;
serverOverridesFlat?;
peerId?: string;
ignoreQs?: boolean;
server?: string
singleplayer?: any
username: string
password?: any
proxy?: any
botVersion?: any
serverOverrides?
serverOverridesFlat?
peerId?: string
ignoreQs?: boolean
onSuccessfulPlay?: () => void
autoLoginPassword?: string
serverIndex?: string

connectEvents?: {
serverCreated?: () => void
// connect: () => void;
// disconnect: () => void;
// error: (err: any) => void;
// ready: () => void;
// end: () => void;
}
}
Loading

0 comments on commit e9aa0e9

Please # to comment.