feat: add gamemode selector in create world screen. always use creative with ?singleplayer=1

This commit is contained in:
Vitaly Turovsky 2024-05-26 18:58:46 +03:00
commit 0d8beef65c
11 changed files with 56 additions and 50 deletions

View file

@ -1,15 +1,5 @@
/// <reference types="cypress" />
import type { AppOptions } from '../../src/optionsStorage'
const cleanVisit = (url?) => {
cy.clearLocalStorage()
visit(url)
}
const visit = (url = '/') => {
window.localStorage.cypress = 'true'
cy.visit(url)
}
import { setOptions, cleanVisit, visit } from './shared'
// todo use ssl
@ -31,14 +21,8 @@ const testWorldLoad = () => {
})
}
const setOptions = (options: Partial<AppOptions>) => {
cy.window().then(win => {
Object.assign(win['options'], options)
})
}
it('Loads & renders singleplayer', () => {
visit('/?singleplayer=1')
cleanVisit('/?singleplayer=1')
setOptions({
localServerOptions: {
generation: {
@ -69,10 +53,3 @@ it('Loads & renders zip world', () => {
cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true })
testWorldLoad()
})
it.skip('Performance test', () => {
// select that world
// from -2 85 24
// await bot.loadPlugin(pathfinder.pathfinder)
// bot.pathfinder.goto(new pathfinder.goals.GoalXZ(28, -28))
})

15
cypress/e2e/shared.ts Normal file
View file

@ -0,0 +1,15 @@
import { AppOptions } from '../../src/optionsStorage'
export const cleanVisit = (url?) => {
cy.clearLocalStorage()
visit(url)
}
export const visit = (url = '/') => {
window.localStorage.cypress = 'true'
cy.visit(url)
}
export const setOptions = (options: Partial<AppOptions>) => {
cy.window().then(win => {
Object.assign(win['options'], options)
})
}

View file

@ -19,9 +19,10 @@ const warnings = new Set<string>()
Promise.resolve().then(async () => {
generateItemsAtlases()
console.time('generateTextures')
for (const version of mcAssets.versions as typeof mcAssets['versions']) {
const versions = process.argv.includes('-l') ? [mcAssets.versions.at(-1)!] : mcAssets.versions
for (const version of versions as typeof mcAssets['versions']) {
// for debugging (e.g. when above is overridden)
if (!mcAssets.versions.includes(version)) {
if (!versions.includes(version)) {
throw new Error(`Version ${version} is not supported by minecraft-assets`)
}
if (versionToNumber(version) < versionToNumber('1.13')) {
@ -45,7 +46,7 @@ Promise.resolve().then(async () => {
fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true })
}
fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + mcAssets.versions.map(v => `"${v}"`).toString() + ']')
fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + versions.map(v => `"${v}"`).toString() + ']')
warnings.forEach(x => console.warn(x))
console.timeEnd('generateTextures')
})

View file

@ -40,7 +40,7 @@ export const startWatchingHmr = () => {
const mesherSharedPlugins = [
{
name: 'minecraft-data',
setup (build) {
setup(build) {
build.onLoad({
filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/,
}, async (args) => {
@ -59,7 +59,7 @@ const plugins = [
...mesherSharedPlugins,
{
name: 'strict-aliases',
setup (build) {
setup(build) {
build.onResolve({
filter: /^minecraft-protocol$/,
}, async ({ kind, resolveDir }) => {
@ -110,7 +110,7 @@ const plugins = [
},
{
name: 'data-assets',
setup (build) {
setup(build) {
build.onResolve({
filter: /.*/,
}, async ({ path, ...rest }) => {
@ -161,7 +161,7 @@ const plugins = [
},
{
name: 'prevent-incorrect-linking',
setup (build) {
setup(build) {
build.onResolve({
filter: /.+/,
}, async ({ resolveDir, path, importer, kind, pluginData }) => {
@ -184,7 +184,7 @@ const plugins = [
},
{
name: 'watch-notify',
setup (build) {
setup(build) {
let count = 0
let time
let prevHash
@ -234,7 +234,7 @@ const plugins = [
},
{
name: 'esbuild-readdir',
setup (build) {
setup(build) {
build.onResolve({
filter: /^esbuild-readdir:.+$/,
}, ({ resolveDir, path }) => {
@ -262,7 +262,7 @@ const plugins = [
},
{
name: 'esbuild-import-glob',
setup (build) {
setup(build) {
build.onResolve({
filter: /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/,
}, ({ resolveDir, path }) => {
@ -292,7 +292,7 @@ const plugins = [
},
{
name: 'fix-dynamic-require',
setup (build) {
setup(build) {
build.onResolve({
filter: /1\.14\/chunk/,
}, async ({ resolveDir, path }) => {
@ -321,7 +321,7 @@ const plugins = [
},
{
name: 'react-displayname',
setup (build) {
setup(build) {
build.onLoad({
filter: /.tsx$/,
}, async ({ path }) => {

View file

@ -6,10 +6,10 @@ const fns = {
async getAlias () {
const aliasesRaw = process.env.ALIASES
if (!aliasesRaw) throw new Error('No aliases found')
const aliases = aliasesRaw.split('\n').map((x) => x.split('='))
const aliases = aliasesRaw.split('\n').map((x) => x.trim().split('='))
const githubActionsPull = process.env.PULL_URL?.split('/').at(-1)
if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`)
const prNumber = githubActionsPull[1]
if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.PULL_URL}`)
const prNumber = githubActionsPull
const alias = aliases.find((x) => x[0] === prNumber)
if (alias) {
// set github output
@ -18,7 +18,7 @@ const fns = {
}
}
function setOutput(key, value) {
function setOutput (key, value) {
// Temporary hack until core actions library catches up with github new recommendations
const output = process.env['GITHUB_OUTPUT']
fs.appendFileSync(output, `${key}=${value}${os.EOL}`)

View file

@ -52,7 +52,9 @@ const defaultOptions = {
excludeCommunicationDebugEvents: [],
preventDevReloadWhilePlaying: false,
numWorkers: 4,
localServerOptions: {} as any,
localServerOptions: {
gameMode: 1
} as any,
preferLoadReadonly: false,
disableLoadPrompts: false,
guestUsername: 'guest',

View file

@ -8,17 +8,19 @@ import styles from './createWorld.module.css'
// const worldTypes = ['default', 'flat', 'largeBiomes', 'amplified', 'customized', 'buffet', 'debug_all_block_states']
const worldTypes = ['default', 'flat'/* , 'void' */]
const gameModes = ['survival', 'creative'/* , 'adventure', 'spectator' */]
export const creatingWorldState = proxy({
title: '',
type: worldTypes[0],
gameMode: gameModes[0],
version: ''
})
export default ({ cancelClick, createClick, customizeClick, versions, defaultVersion }) => {
const [quota, setQuota] = useState('')
const { title, type, version } = useSnapshot(creatingWorldState)
const { title, type, version, gameMode } = useSnapshot(creatingWorldState)
useEffect(() => {
creatingWorldState.version = defaultVersion
void navigator.storage?.estimate?.().then(({ quota, usage }) => {
@ -54,9 +56,15 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer
<Button onClick={() => {
const index = worldTypes.indexOf(type)
creatingWorldState.type = worldTypes[index === worldTypes.length - 1 ? 0 : index + 1]
}}>{type}</Button>
<Button onClick={() => customizeClick()} disabled>
}}>World Type: {type}</Button>
{/* <Button onClick={() => customizeClick()} disabled>
Customize
</Button> */}
<Button onClick={() => {
const index = gameModes.indexOf(gameMode)
creatingWorldState.gameMode = gameModes[index === gameModes.length - 1 ? 0 : index + 1]
}}>
Gamemode: {gameMode}
</Button>
</div>
<div className='muted' style={{ fontSize: 8 }}>Default and other world types are WIP</div>

View file

@ -3,8 +3,8 @@ import { hideCurrentModal, showModal } from '../globalState'
import defaultLocalServerOptions from '../defaultLocalServerOptions'
import { mkdirRecursive, uniqueFileNameFromWorldName } from '../browserfs'
import CreateWorld, { WorldCustomize, creatingWorldState } from './CreateWorld'
import { useIsModalActive } from './utilsApp'
import { getWorldsPath } from './SingleplayerProvider'
import { useIsModalActive } from './utilsApp'
export default () => {
const activeCreate = useIsModalActive('create-world')
@ -23,7 +23,7 @@ export default () => {
}}
createClick={async () => {
// create new world
const { title, type, version } = creatingWorldState
const { title, type, version, gameMode } = creatingWorldState
// todo display path in ui + disable if exist
const savePath = await uniqueFileNameFromWorldName(title, getWorldsPath())
await mkdirRecursive(savePath)
@ -51,7 +51,8 @@ export default () => {
levelName: title,
version,
generation,
'worldFolder': savePath
'worldFolder': savePath,
gameMode: gameMode === 'survival' ? 0 : 1,
},
}))
}}

View file

@ -12,7 +12,7 @@ export const itemBeingUsed = proxy({
export default () => {
const { name: usingItem, hand } = useSnapshot(itemBeingUsed)
const [displayIndicator, setDisplayIndicator] = useState(true)
const [displayIndicator, setDisplayIndicator] = useState(false)
const [indicatorProgress, setIndicatorProgress] = useState(0)
const [alternativeIndicator, setAlternativeIndicator] = useState(false)
const boxMaxTimeMs = 1000

2
src/workerWorkaround.ts Normal file
View file

@ -0,0 +1,2 @@
global = globalThis
globalThis.window = globalThis

View file

@ -15,7 +15,7 @@
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": false,
"skipLibCheck": true,
"experimentalDecorators": true,
"strictBindCallApply": true,
// this the only options that allows smooth transition from js to ts (by not dropping types from js files)
// however might need to consider includeing *only needed libraries* instead of using this
"maxNodeModuleJsDepth": 1,