pages235/src/globalState.ts
Vitaly 65af9a73c2
feat: rework hand! enable by default, fix bow anim (#261)
* refactor swing animation to controller

* idle animator!!!!

* implelment state switch transition

* a huge fix for UI server edit!

* adjust ui scaling so main menu elements clip less

* view bobbing, new config name, ws:

* EXTREMELY important fixes to entities rendering

* a lot of fixes, add dns resolve fallback

* improve f3 E, fix modal not found edge case

* set correctly target for old browsers, should fix ios 14 crash

* unecessary big refactor, to fix ts err

* fix isWysiwyg check

* fix entities rendering count
2025-02-15 05:14:36 +03:00

169 lines
4.7 KiB
TypeScript

//@ts-check
import { proxy, ref, subscribe } from 'valtio'
import type { WorldWarp } from 'flying-squid/dist/lib/modules/warps'
import type { OptionsGroupType } from './optionsGuiScheme'
import { appQueryParams } from './appParams'
// todo: refactor structure with support of hideNext=false
const notHideableModalsWithoutForce = new Set(['app-status'])
if (appQueryParams.lockConnect) {
notHideableModalsWithoutForce.add('editServer')
}
type Modal = ({ elem?: HTMLElement & Record<string, any> } & { reactType: string })
type ContextMenuItem = { callback; label }
export const activeModalStack: Modal[] = proxy([])
export const insertActiveModalStack = (name: string, newModalStack = activeModalStacks[name]) => {
hideModal(undefined, undefined, { restorePrevious: false, force: true })
activeModalStack.splice(0, activeModalStack.length, ...newModalStack)
const last = activeModalStack.at(-1)
if (last) showModalInner(last)
}
export const activeModalStacks: Record<string, Modal[]> = {}
window.activeModalStack = activeModalStack
/**
* @returns true if operation was successful
*/
const showModalInner = (modal: Modal) => {
const cancel = modal.elem?.show?.()
return true
}
export const showModal = (elem: /* (HTMLElement & Record<string, any>) | */{ reactType: string }) => {
const resolved = elem
const curModal = activeModalStack.at(-1)
if (/* elem === curModal?.elem || */(elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return
activeModalStack.push(resolved)
}
/**
*
* @returns true if previous modal was restored
*/
export const hideModal = (modal = activeModalStack.at(-1), data: any = undefined, options: { force?: boolean; restorePrevious?: boolean } = {}) => {
const { force = false, restorePrevious = true } = options
if (!modal) return
let cancel = notHideableModalsWithoutForce.has(modal.reactType) ? !force : undefined
if (force) {
cancel = undefined
}
if (!cancel) {
const lastModal = activeModalStack.at(-1)
for (let i = activeModalStack.length - 1; i >= 0; i--) {
if (activeModalStack[i].reactType === modal.reactType) {
activeModalStack.splice(i, 1)
break
}
}
const newModal = activeModalStack.at(-1)
if (newModal && lastModal !== newModal && restorePrevious) {
// would be great to ignore cancel I guess?
showModalInner(newModal)
}
return true
}
}
export const hideCurrentModal = (_data?, onHide?: () => void) => {
if (hideModal(undefined, undefined)) {
onHide?.()
}
}
export const hideAllModals = () => {
while (activeModalStack.length > 0) {
if (!hideModal()) break
}
return activeModalStack.length === 0
}
export const openOptionsMenu = (group: OptionsGroupType) => {
showModal({ reactType: `options-${group}` })
}
subscribe(activeModalStack, () => {
document.body.style.setProperty('--has-modals-z', activeModalStack.length ? '-1' : null)
})
// ---
export const currentContextMenu = proxy({ items: [] as ContextMenuItem[] | null, x: 0, y: 0 })
export const showContextmenu = (items: ContextMenuItem[], { clientX, clientY }) => {
Object.assign(currentContextMenu, {
items,
x: clientX,
y: clientY,
})
}
// ---
export type AppConfig = {
// defaultHost?: string
// defaultHostSave?: string
defaultProxy?: string
// defaultProxySave?: string
// defaultVersion?: string
peerJsServer?: string
peerJsServerFallback?: string
promoteServers?: Array<{ ip, description, version? }>
mapsProvider?: string
defaultSettings?: Record<string, any>
allowAutoConnect?: boolean
}
export const miscUiState = proxy({
currentDisplayQr: null as string | null,
currentTouch: null as boolean | null,
hasErrors: false,
singleplayer: false,
flyingSquid: false,
wanOpened: false,
wanOpening: false,
/** wether game hud is shown (in playing state) */
gameLoaded: false,
showUI: true,
loadedServerIndex: '',
/** currently trying to load or loaded mc version, after all data is loaded */
loadedDataVersion: null as string | null,
appLoaded: false,
usingGamepadInput: false,
appConfig: null as AppConfig | null,
displaySearchInput: false,
displayFullmap: false
})
export const isGameActive = (foregroundCheck: boolean) => {
if (foregroundCheck && activeModalStack.length) return false
return miscUiState.gameLoaded
}
window.miscUiState = miscUiState
// state that is not possible to get via bot and in-game specific
export const gameAdditionalState = proxy({
isFlying: false,
isSprinting: false,
isSneaking: false,
isZooming: false,
warps: [] as WorldWarp[],
noConnection: false,
poorConnection: false,
viewerConnection: false,
usingServerResourcePack: false,
})
window.gameAdditionalState = gameAdditionalState