Skip to content

Commit

Permalink
release now (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
zardoy authored Feb 19, 2024
2 parents 3ae7447 + dd1c335 commit 829d7e2
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 159 deletions.
68 changes: 35 additions & 33 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@
<script>
window.startLoad = Date.now()
</script>
<script async>
const loadingDiv = `
<div class="initial-loader" style="position: fixed;transition:opacity 0.2s;inset: 0;background:black;display: flex;justify-content: center;align-items: center;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', Arial, Helvetica, sans-serif;gap: 15px;" ontransitionend="this.remove()">
<div>
<img src="./loading-bg.jpg" alt="Prismarine Web Client" style="position:fixed;inset:0;width:100%;height:100%;z-index: -2;object-fit: cover;filter: blur(3px);">
<div style="position: fixed;inset: 0;z-index: -1;background-color: rgba(0, 0, 0, 0.8);"></div>
</div>
<div>
<div style="font-size: calc(var(--font-size) * 1.8);color: lightgray;" class="title">Loading...</div>
<div style="font-size: var(--font-size);color: rgb(176, 176, 176);" class="subtitle">A true Minecraft client in your browser!</div>
</div>
</div>
`
const loadingDivElem = document.createElement('div')
loadingDivElem.innerHTML = loadingDiv
if (!window.pageLoaded) {
document.documentElement.appendChild(loadingDivElem)
}
<!-- // #region initial loader -->
<script async>
const loadingDiv = `
<div class="initial-loader" style="position: fixed;transition:opacity 0.2s;inset: 0;background:black;display: flex;justify-content: center;align-items: center;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', Arial, Helvetica, sans-serif;gap: 15px;" ontransitionend="this.remove()">
<div>
<img src="./loading-bg.jpg" alt="Prismarine Web Client" style="position:fixed;inset:0;width:100%;height:100%;z-index: -2;object-fit: cover;filter: blur(3px);">
<div style="position: fixed;inset: 0;z-index: -1;background-color: rgba(0, 0, 0, 0.8);"></div>
</div>
<div>
<div style="font-size: calc(var(--font-size) * 1.8);color: lightgray;" class="title">Loading...</div>
<div style="font-size: var(--font-size);color: rgb(176, 176, 176);" class="subtitle">A true Minecraft client in your browser!</div>
</div>
</div>
`
const loadingDivElem = document.createElement('div')
loadingDivElem.innerHTML = loadingDiv
if (!window.pageLoaded) {
document.documentElement.appendChild(loadingDivElem)
}
// load error handling
const onError = (message) => {
console.log(message)
Expand All @@ -33,23 +34,23 @@
}
window.addEventListener('unhandledrejection', (e) => onError(e.reason))
window.addEventListener('error', (e) => onError(e.message))
</script>
<script type="module" async>
const checkLoadEruda = () => {
if (window.location.hash === '#dev') {
// todo precache (check offline)?
import('https://cdn.skypack.dev/eruda').then(({ default: eruda }) => {
eruda.init()
})
}
}
checkLoadEruda()
window.addEventListener('hashchange', (e) => {
setTimeout(() => {
checkLoadEruda()
</script>
<script type="module" async>
const checkLoadEruda = () => {
if (window.location.hash === '#dev') {
// todo precache (check offline)?
import('https://cdn.skypack.dev/eruda').then(({ default: eruda }) => {
eruda.init()
})
}
}
checkLoadEruda()
window.addEventListener('hashchange', (e) => {
setTimeout(() => {
checkLoadEruda()
})
</script>
})
</script>
<style>
html {
background: black;
Expand All @@ -68,6 +69,7 @@
}
}
</style>
<!-- // #endregion -->
<title>Prismarine Web Client</title>
<link rel="stylesheet" href="index.css">
<link rel="favicon" href="favicon.ico">
Expand Down
53 changes: 46 additions & 7 deletions prismarine-viewer/viewer/lib/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ export class Entities extends EventEmitter {
return playerObject
}

// fixme workaround
defaultSteveTexture

// true means use default skin url
updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) {
let playerObject = this.getPlayerObject(entityId)
Expand All @@ -146,15 +149,24 @@ export class Entities extends EventEmitter {
loadImage(skinUrl).then((image) => {
playerObject = this.getPlayerObject(entityId)
if (!playerObject) return
const skinCanvas = document.createElement('canvas')
loadSkinToCanvas(skinCanvas, image)
const skinTexture = new THREE.CanvasTexture(skinCanvas)
/** @type {THREE.CanvasTexture} */
let skinTexture
if (skinUrl === stevePng && this.defaultSteveTexture) {
skinTexture = this.defaultSteveTexture
} else {
const skinCanvas = document.createElement('canvas')
loadSkinToCanvas(skinCanvas, image)
skinTexture = new THREE.CanvasTexture(skinCanvas)
if (skinUrl === stevePng) {
this.defaultSteveTexture = skinTexture
}
}
skinTexture.magFilter = THREE.NearestFilter
skinTexture.minFilter = THREE.NearestFilter
skinTexture.needsUpdate = true
//@ts-ignore
playerObject.skin.map = skinTexture
playerObject.skin.modelType = inferModelType(skinCanvas)
playerObject.skin.modelType = inferModelType(skinTexture.image)

const earsCanvas = document.createElement('canvas')
loadEarsToCanvasFromSkin(earsCanvas, image)
Expand Down Expand Up @@ -193,9 +205,9 @@ export class Entities extends EventEmitter {
if (!playerObject.backEquipment) {
playerObject.backEquipment = 'cape'
}
})
}, () => {})
}
})
}, () => {})


playerObject.cape.visible = false
Expand Down Expand Up @@ -320,10 +332,37 @@ export class Entities extends EventEmitter {
}
// not player
const displayText = entity.metadata?.[3] && this.displaySimpleText(entity.metadata[2]);
if (entity.name !== 'player') {
if (entity.name !== 'player' && displayText) {
addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh'))
}

// todo handle map, map_chunks events
// if (entity.name === 'item_frame' || entity.name === 'glow_item_frame') {
// const example = {
// "present": true,
// "itemId": 847,
// "itemCount": 1,
// "nbtData": {
// "type": "compound",
// "name": "",
// "value": {
// "map": {
// "type": "int",
// "value": 2146483444
// },
// "interactiveboard": {
// "type": "byte",
// "value": 1
// }
// }
// }
// }
// const item = entity.metadata?.[8]
// if (item.nbtData) {
// const nbt = nbt.simplify(item.nbtData)
// }
// }

// this can be undefined in case where packet entity_destroy was sent twice (so it was already deleted)
const e = this.entities[entity.id]

Expand Down
68 changes: 51 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import { loadInMemorySave } from './react/SingleplayerProvider'
// side effects
import { downloadSoundsIfNeeded } from './soundSystem'
import { ua } from './react/utils'
import { handleMovementStickDelta, joystickPointer } from './react/TouchAreasControls'

window.debug = debug
window.THREE = THREE
Expand Down Expand Up @@ -350,12 +351,12 @@ async function connect (connectOptions: {
}
const handleError = (err) => {
errorAbortController.abort()
console.log('Encountered error!', err)
if (isCypress()) throw err
if (miscUiState.gameLoaded) return

setLoadingScreenStatus(`Error encountered. ${err}`, true)
onPossibleErrorDisconnect()
destroyAll()
if (isCypress()) throw err
}

const errorAbortController = new AbortController()
Expand Down Expand Up @@ -670,6 +671,7 @@ async function connect (connectOptions: {
let screenTouches = 0
let capturedPointer: { id; x; y; sourceX; sourceY; activateCameraMove; time } | undefined
registerListener(document, 'pointerdown', (e) => {
const usingJoystick = options.touchControlsType === 'joystick-buttons'
const clickedEl = e.composedPath()[0]
if (!isGameActive(true) || !miscUiState.currentTouch || clickedEl !== cameraControlEl || e.pointerId === undefined) {
return
Expand All @@ -679,6 +681,16 @@ async function connect (connectOptions: {
// todo needs fixing!
// window.dispatchEvent(new MouseEvent('mousedown', { button: 1 }))
}
if (usingJoystick) {
if (!joystickPointer.pointer && e.clientX < window.innerWidth / 2) {
joystickPointer.pointer = {
pointerId: e.pointerId,
x: e.clientX,
y: e.clientY
}
return
}
}
if (capturedPointer) {
return
}
Expand All @@ -692,19 +704,33 @@ async function connect (connectOptions: {
activateCameraMove: false,
time: Date.now()
}
virtualClickTimeout ??= setTimeout(() => {
virtualClickActive = true
document.dispatchEvent(new MouseEvent('mousedown', { button: 0 }))
}, touchStartBreakingBlockMs)
if (options.touchControlsType !== 'joystick-buttons') {
virtualClickTimeout ??= setTimeout(() => {
virtualClickActive = true
document.dispatchEvent(new MouseEvent('mousedown', { button: 0 }))
}, touchStartBreakingBlockMs)
}
})
registerListener(document, 'pointermove', (e) => {
if (e.pointerId === undefined || e.pointerId !== capturedPointer?.id) return
if (e.pointerId === undefined) return
const supportsPressure = (e as any).pressure !== undefined && (e as any).pressure !== 0 && (e as any).pressure !== 0.5 && (e as any).pressure !== 1 && (e.pointerType === 'touch' || e.pointerType === 'pen')
if (e.pointerId === joystickPointer.pointer?.pointerId) {
handleMovementStickDelta(e)
if (supportsPressure && (e as any).pressure > 0.5) {
bot.setControlState('sprint', true)
// todo
}
return
}
if (e.pointerId !== capturedPointer?.id) return
window.scrollTo(0, 0)
e.preventDefault()
e.stopPropagation()

const allowedJitter = 1.1
// todo support .pressure (3d touch)
if (supportsPressure) {
bot.setControlState('jump', (e as any).pressure > 0.5)
}
const xDiff = Math.abs(e.pageX - capturedPointer.sourceX) > allowedJitter
const yDiff = Math.abs(e.pageY - capturedPointer.sourceY) > allowedJitter
if (!capturedPointer.activateCameraMove && (xDiff || yDiff)) capturedPointer.activateCameraMove = true
Expand All @@ -717,18 +743,26 @@ async function connect (connectOptions: {
}, { passive: false })

const pointerUpHandler = (e: PointerEvent) => {
if (e.pointerId === undefined || e.pointerId !== capturedPointer?.id) return
if (e.pointerId === undefined) return
if (e.pointerId === joystickPointer.pointer?.pointerId) {
handleMovementStickDelta()
joystickPointer.pointer = null
return
}
if (e.pointerId !== capturedPointer?.id) return
clearTimeout(virtualClickTimeout)
virtualClickTimeout = undefined

if (virtualClickActive) {
// button 0 is left click
document.dispatchEvent(new MouseEvent('mouseup', { button: 0 }))
virtualClickActive = false
} else if (!capturedPointer.activateCameraMove && (Date.now() - capturedPointer.time < touchStartBreakingBlockMs)) {
document.dispatchEvent(new MouseEvent('mousedown', { button: 2 }))
worldInteractions.update()
document.dispatchEvent(new MouseEvent('mouseup', { button: 2 }))
if (options.touchControlsType !== 'joystick-buttons') {
if (virtualClickActive) {
// button 0 is left click
document.dispatchEvent(new MouseEvent('mouseup', { button: 0 }))
virtualClickActive = false
} else if (!capturedPointer.activateCameraMove && (Date.now() - capturedPointer.time < touchStartBreakingBlockMs)) {
document.dispatchEvent(new MouseEvent('mousedown', { button: 2 }))
worldInteractions.update()
document.dispatchEvent(new MouseEvent('mouseup', { button: 2 }))
}
}
capturedPointer = undefined
screenTouches--
Expand Down
28 changes: 22 additions & 6 deletions src/optionsGuiScheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ export const guiOptionsScheme: {
},
{
custom () {
return <>
<div></div>
<span style={{ fontSize: 9, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>Experimental</span>
<div></div>
</>
return <Category>Experimental</Category>
},
dayCycleAndLighting: {
text: 'Day Cycle',
Expand Down Expand Up @@ -139,6 +135,9 @@ export const guiOptionsScheme: {
unit: '',
delayApply: true,
},
custom () {
return <Category>Chat</Category>
},
chatWidth: {
max: 320,
unit: 'px',
Expand All @@ -151,6 +150,8 @@ export const guiOptionsScheme: {
},
chatOpacityOpened: {
},
chatSelect: {
},
}
],
controls: [
Expand Down Expand Up @@ -187,7 +188,16 @@ export const guiOptionsScheme: {
},
touchButtonsPosition: {
max: 80
}
},
touchControlsType: {
values: [['classic', 'Classic'], ['joystick-buttons', 'New']],
},
},
{
custom () {
const { touchControlsType } = useSnapshot(options)
return <Button label='Setup Touch Buttons' onClick={() => showModal({ reactType: 'touch-buttons-setup' })} inScreen disabled={touchControlsType !== 'joystick-buttons'} />
},
}
],
sound: [
Expand Down Expand Up @@ -220,3 +230,9 @@ export const guiOptionsScheme: {
],
}
export type OptionsGroupType = 'main' | 'render' | 'interface' | 'controls' | 'sound' | 'advanced' | 'VR'

const Category = ({ children }) => <div style={{
fontSize: 9,
textAlign: 'center',
gridColumn: 'span 2'
}}>{children}</div>
Loading

0 comments on commit 829d7e2

Please sign in to comment.