spoint 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/interactable/index.js +26 -108
- package/client/app.js +8 -6
- package/client/draco/draco_decoder.js +34 -0
- package/client/draco/draco_decoder.wasm +0 -0
- package/client/draco/draco_wasm_wrapper.js +117 -0
- package/package.json +1 -1
- package/src/apps/AppContext.js +1 -0
- package/src/apps/AppRuntime.js +23 -2
- package/src/client/InputHandler.js +6 -4
- package/src/client/MessageHandler.js +1 -1
- package/apps/tps-game/$GDUPI.vrm +0 -0
- package/apps/tps-game/Cleetus.vrm +0 -0
|
@@ -2,57 +2,25 @@ export default {
|
|
|
2
2
|
server: {
|
|
3
3
|
setup(ctx) {
|
|
4
4
|
ctx.entity.custom = { mesh: 'box', color: 0x00ff88, sx: 1.5, sy: 0.5, sz: 1.5, label: 'INTERACT' }
|
|
5
|
-
ctx.state.interactionRadius = 3.5
|
|
6
|
-
ctx.state.interactionCooldown = new Map()
|
|
7
5
|
ctx.state.interactionCount = 0
|
|
8
6
|
|
|
9
7
|
ctx.physics.setStatic(true)
|
|
10
8
|
ctx.physics.addBoxCollider([0.75, 0.25, 0.75])
|
|
11
|
-
|
|
12
|
-
ctx.time.every(0.1, () => {
|
|
13
|
-
const nearby = ctx.players.getNearest(ctx.entity.position, ctx.state.interactionRadius)
|
|
14
|
-
if (!nearby) return
|
|
15
|
-
|
|
16
|
-
const now = Date.now()
|
|
17
|
-
const playerId = nearby.id
|
|
18
|
-
const lastInteract = ctx.state.interactionCooldown.get(playerId) || 0
|
|
19
|
-
|
|
20
|
-
if (nearby.state?.interact && now - lastInteract > 500) {
|
|
21
|
-
ctx.state.interactionCooldown.set(playerId, now)
|
|
22
|
-
ctx.state.interactionCount++
|
|
23
|
-
|
|
24
|
-
const messages = [
|
|
25
|
-
'Hello there!',
|
|
26
|
-
'You found the interact button!',
|
|
27
|
-
'Nice to meet you!',
|
|
28
|
-
'This button works!',
|
|
29
|
-
`Interacted ${ctx.state.interactionCount} times total`
|
|
30
|
-
]
|
|
31
|
-
const msg = messages[ctx.state.interactionCount % messages.length]
|
|
32
|
-
|
|
33
|
-
ctx.players.send(playerId, {
|
|
34
|
-
type: 'interact_response',
|
|
35
|
-
message: msg,
|
|
36
|
-
count: ctx.state.interactionCount
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
ctx.network.broadcast({
|
|
40
|
-
type: 'interact_effect',
|
|
41
|
-
position: ctx.entity.position,
|
|
42
|
-
playerId: playerId
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
})
|
|
9
|
+
ctx.physics.setInteractable(3.5)
|
|
46
10
|
},
|
|
47
11
|
|
|
48
|
-
|
|
49
|
-
ctx.state.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
12
|
+
onInteract(ctx, player) {
|
|
13
|
+
ctx.state.interactionCount++
|
|
14
|
+
const messages = [
|
|
15
|
+
'Hello there!',
|
|
16
|
+
'You found the interact button!',
|
|
17
|
+
'Nice to meet you!',
|
|
18
|
+
'This button works!',
|
|
19
|
+
`Interacted ${ctx.state.interactionCount} times total`
|
|
20
|
+
]
|
|
21
|
+
const msg = messages[ctx.state.interactionCount % messages.length]
|
|
22
|
+
ctx.players.send(player.id, { type: 'interact_response', message: msg, count: ctx.state.interactionCount })
|
|
23
|
+
ctx.network.broadcast({ type: 'interact_effect', position: ctx.entity.position, playerId: player.id })
|
|
56
24
|
}
|
|
57
25
|
},
|
|
58
26
|
|
|
@@ -60,8 +28,7 @@ export default {
|
|
|
60
28
|
setup(engine) {
|
|
61
29
|
this._lastMessage = null
|
|
62
30
|
this._messageExpire = 0
|
|
63
|
-
this.
|
|
64
|
-
this._isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
|
31
|
+
this._canInteract = false
|
|
65
32
|
this._wasRegistered = false
|
|
66
33
|
},
|
|
67
34
|
|
|
@@ -70,86 +37,37 @@ export default {
|
|
|
70
37
|
const pos = ent?.position
|
|
71
38
|
const local = engine.client?.state?.players?.find(p => p.id === engine.playerId)
|
|
72
39
|
if (!pos || !local?.position) {
|
|
73
|
-
if (this._wasRegistered) {
|
|
74
|
-
engine.mobileControls?.unregisterInteractable(ent?.id || 'interactable')
|
|
75
|
-
this._wasRegistered = false
|
|
76
|
-
}
|
|
40
|
+
if (this._wasRegistered) { engine.mobileControls?.unregisterInteractable(this._wasRegistered); this._wasRegistered = false }
|
|
77
41
|
return
|
|
78
42
|
}
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz)
|
|
84
|
-
const canInteract = dist < 3.5
|
|
85
|
-
|
|
86
|
-
if (canInteract && !this._wasRegistered) {
|
|
87
|
-
engine.mobileControls?.registerInteractable(ent.id, 'INTERACT')
|
|
88
|
-
this._wasRegistered = ent.id
|
|
89
|
-
} else if (!canInteract && this._wasRegistered) {
|
|
90
|
-
engine.mobileControls?.unregisterInteractable(this._wasRegistered)
|
|
91
|
-
this._wasRegistered = false
|
|
92
|
-
}
|
|
93
|
-
|
|
43
|
+
const dx = pos[0]-local.position[0], dy = pos[1]-local.position[1], dz = pos[2]-local.position[2]
|
|
44
|
+
const canInteract = dx*dx+dy*dy+dz*dz < 3.5*3.5
|
|
45
|
+
if (canInteract && !this._wasRegistered) { engine.mobileControls?.registerInteractable(ent.id, 'INTERACT'); this._wasRegistered = ent.id }
|
|
46
|
+
else if (!canInteract && this._wasRegistered) { engine.mobileControls?.unregisterInteractable(this._wasRegistered); this._wasRegistered = false }
|
|
94
47
|
this._canInteract = canInteract
|
|
95
48
|
},
|
|
96
49
|
|
|
97
50
|
teardown(engine) {
|
|
98
|
-
if (this._wasRegistered) {
|
|
99
|
-
engine.mobileControls?.unregisterInteractable('interactable')
|
|
100
|
-
this._wasRegistered = false
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
onInput(input, engine) {
|
|
105
|
-
if (input.interact && !this._wasInteracting) {
|
|
106
|
-
this._showingInteract = true
|
|
107
|
-
this._messageExpire = Date.now() + 2000
|
|
108
|
-
}
|
|
109
|
-
this._wasInteracting = input.interact
|
|
51
|
+
if (this._wasRegistered) { engine.mobileControls?.unregisterInteractable(this._wasRegistered); this._wasRegistered = false }
|
|
110
52
|
},
|
|
111
53
|
|
|
112
54
|
onEvent(payload, engine) {
|
|
113
|
-
if (payload.type === 'interact_response') {
|
|
114
|
-
|
|
115
|
-
this._messageExpire = Date.now() + 3000
|
|
116
|
-
}
|
|
117
|
-
if (payload.type === 'interact_effect') {
|
|
118
|
-
this._lastMessage = 'Someone interacted!'
|
|
119
|
-
this._messageExpire = Date.now() + 1500
|
|
120
|
-
}
|
|
55
|
+
if (payload.type === 'interact_response') { this._lastMessage = payload.message; this._messageExpire = Date.now() + 3000 }
|
|
56
|
+
if (payload.type === 'interact_effect') { this._lastMessage = 'Someone interacted!'; this._messageExpire = Date.now() + 1500 }
|
|
121
57
|
},
|
|
122
58
|
|
|
123
59
|
render(ctx) {
|
|
124
60
|
const h = ctx.h
|
|
125
61
|
const pos = ctx.entity.position
|
|
126
62
|
if (!h || !pos) return { position: pos }
|
|
127
|
-
|
|
128
63
|
const ui = []
|
|
129
|
-
|
|
130
64
|
if (this._lastMessage && Date.now() < this._messageExpire) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
ui.push(
|
|
134
|
-
h('div', {
|
|
135
|
-
style: `position:fixed;top:30%;left:50%;transform:translate(-50%,-50%);padding:16px 32px;background:rgba(0,0,0,0.8);border-radius:12px;color:#0f0;font-weight:bold;font-size:20px;text-align:center;border:2px solid #0f0;opacity:${opacity}`
|
|
136
|
-
}, this._lastMessage)
|
|
137
|
-
)
|
|
65
|
+
const opacity = Math.min(1, ((this._messageExpire - Date.now()) / 3000) * 2)
|
|
66
|
+
ui.push(h('div', { style: `position:fixed;top:30%;left:50%;transform:translate(-50%,-50%);padding:16px 32px;background:rgba(0,0,0,0.8);border-radius:12px;color:#0f0;font-weight:bold;font-size:20px;text-align:center;border:2px solid #0f0;opacity:${opacity}` }, this._lastMessage))
|
|
138
67
|
}
|
|
139
|
-
|
|
140
68
|
const custom = { ...ctx.entity.custom }
|
|
141
|
-
if (this._canInteract) {
|
|
142
|
-
|
|
143
|
-
custom.glowColor = 0x00ff88
|
|
144
|
-
custom.glowIntensity = 0.5
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
position: pos,
|
|
149
|
-
rotation: ctx.entity.rotation,
|
|
150
|
-
custom,
|
|
151
|
-
ui: ui.length > 0 ? h('div', null, ...ui) : null
|
|
152
|
-
}
|
|
69
|
+
if (this._canInteract) { custom.glow = true; custom.glowColor = 0x00ff88; custom.glowIntensity = 0.5 }
|
|
70
|
+
return { position: pos, rotation: ctx.entity.rotation, custom, ui: ui.length > 0 ? h('div', null, ...ui) : null }
|
|
153
71
|
}
|
|
154
72
|
}
|
|
155
73
|
}
|
package/client/app.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three'
|
|
2
2
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
|
|
3
|
+
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
|
|
3
4
|
import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm'
|
|
4
5
|
import { PhysicsNetworkClient, InputHandler, MSG } from '/src/index.client.js'
|
|
5
6
|
import { createElement, applyDiff } from 'webjsx'
|
|
@@ -657,6 +658,9 @@ ground.receiveShadow = true
|
|
|
657
658
|
scene.add(ground)
|
|
658
659
|
|
|
659
660
|
const gltfLoader = new GLTFLoader()
|
|
661
|
+
const dracoLoader = new DRACOLoader()
|
|
662
|
+
dracoLoader.setDecoderPath('/draco/')
|
|
663
|
+
gltfLoader.setDRACOLoader(dracoLoader)
|
|
660
664
|
gltfLoader.register((parser) => new VRMLoaderPlugin(parser))
|
|
661
665
|
const playerMeshes = new Map()
|
|
662
666
|
const playerAnimators = new Map()
|
|
@@ -1154,12 +1158,10 @@ function startInputLoop() {
|
|
|
1154
1158
|
const input = inputHandler.getInput()
|
|
1155
1159
|
latestInput = input
|
|
1156
1160
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
cam.setEditMode(false)
|
|
1162
|
-
console.log('[EditMode] Disabled')
|
|
1161
|
+
const wantsEdit = !!input.editToggle
|
|
1162
|
+
if (wantsEdit !== cam.getEditMode()) {
|
|
1163
|
+
cam.setEditMode(wantsEdit)
|
|
1164
|
+
console.log('[EditMode]', wantsEdit ? 'Enabled' : 'Disabled')
|
|
1163
1165
|
}
|
|
1164
1166
|
|
|
1165
1167
|
if (input.yaw !== undefined) {
|