spoint 0.1.0 → 0.1.11
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/README.md +134 -209
- package/SKILL.md +95 -0
- package/apps/environment/index.js +200 -1
- package/apps/environment/models/decorative/.gitkeep +0 -0
- package/apps/environment/models/hazards/.gitkeep +0 -0
- package/apps/environment/models/interactive/.gitkeep +0 -0
- package/apps/environment/models/structures/.gitkeep +0 -0
- package/apps/environment/smartObjects.js +114 -0
- package/apps/interactable/index.js +155 -0
- package/apps/physics-crate/index.js +15 -9
- package/apps/power-crate/index.js +18 -12
- package/apps/tps-game/$GDUPI.vrm +0 -0
- package/apps/tps-game/Cleetus.vrm +0 -0
- package/apps/tps-game/index.js +185 -27
- package/apps/world/index.js +68 -22
- package/bin/create-app.js +337 -0
- package/client/ARControls.js +301 -0
- package/client/LoadingManager.js +117 -0
- package/client/MobileControls.js +1122 -0
- package/client/anim-lib.glb +0 -0
- package/client/animation.js +306 -0
- package/client/app.js +1341 -65
- package/client/camera.js +191 -33
- package/client/createLoadingScreen.js +69 -0
- package/client/editor/bridge.js +113 -0
- package/client/editor/css/main.css +794 -0
- package/client/editor/images/rotate.svg +4 -0
- package/client/editor/images/scale.svg +4 -0
- package/client/editor/images/translate.svg +4 -0
- package/client/editor/index.html +103 -0
- package/client/editor/js/Command.js +41 -0
- package/client/editor/js/Config.js +81 -0
- package/client/editor/js/Editor.js +785 -0
- package/client/editor/js/EditorControls.js +438 -0
- package/client/editor/js/History.js +321 -0
- package/client/editor/js/Loader.js +987 -0
- package/client/editor/js/LoaderUtils.js +90 -0
- package/client/editor/js/Menubar.Add.js +510 -0
- package/client/editor/js/Menubar.Edit.js +145 -0
- package/client/editor/js/Menubar.File.js +466 -0
- package/client/editor/js/Menubar.Help.js +73 -0
- package/client/editor/js/Menubar.Status.js +51 -0
- package/client/editor/js/Menubar.View.js +183 -0
- package/client/editor/js/Menubar.js +27 -0
- package/client/editor/js/Player.js +53 -0
- package/client/editor/js/Resizer.js +58 -0
- package/client/editor/js/Script.js +503 -0
- package/client/editor/js/Selector.js +102 -0
- package/client/editor/js/Sidebar.Geometry.BoxGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.BufferGeometry.js +115 -0
- package/client/editor/js/Sidebar.Geometry.CapsuleGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.CircleGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.CylinderGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.DodecahedronGeometry.js +73 -0
- package/client/editor/js/Sidebar.Geometry.ExtrudeGeometry.js +196 -0
- package/client/editor/js/Sidebar.Geometry.IcosahedronGeometry.js +73 -0
- package/client/editor/js/Sidebar.Geometry.LatheGeometry.js +98 -0
- package/client/editor/js/Sidebar.Geometry.Modifiers.js +73 -0
- package/client/editor/js/Sidebar.Geometry.OctahedronGeometry.js +74 -0
- package/client/editor/js/Sidebar.Geometry.PlaneGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.RingGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.ShapeGeometry.js +76 -0
- package/client/editor/js/Sidebar.Geometry.SphereGeometry.js +133 -0
- package/client/editor/js/Sidebar.Geometry.TetrahedronGeometry.js +74 -0
- package/client/editor/js/Sidebar.Geometry.TorusGeometry.js +109 -0
- package/client/editor/js/Sidebar.Geometry.TorusKnotGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.TubeGeometry.js +135 -0
- package/client/editor/js/Sidebar.Geometry.js +332 -0
- package/client/editor/js/Sidebar.Material.BooleanProperty.js +60 -0
- package/client/editor/js/Sidebar.Material.ColorProperty.js +87 -0
- package/client/editor/js/Sidebar.Material.ConstantProperty.js +62 -0
- package/client/editor/js/Sidebar.Material.MapProperty.js +249 -0
- package/client/editor/js/Sidebar.Material.NumberProperty.js +60 -0
- package/client/editor/js/Sidebar.Material.Program.js +73 -0
- package/client/editor/js/Sidebar.Material.RangeValueProperty.js +63 -0
- package/client/editor/js/Sidebar.Material.js +751 -0
- package/client/editor/js/Sidebar.Object.Animation.js +102 -0
- package/client/editor/js/Sidebar.Object.js +898 -0
- package/client/editor/js/Sidebar.Project.App.js +165 -0
- package/client/editor/js/Sidebar.Project.Image.js +225 -0
- package/client/editor/js/Sidebar.Project.Materials.js +82 -0
- package/client/editor/js/Sidebar.Project.Renderer.js +144 -0
- package/client/editor/js/Sidebar.Project.Video.js +242 -0
- package/client/editor/js/Sidebar.Project.js +31 -0
- package/client/editor/js/Sidebar.Properties.js +73 -0
- package/client/editor/js/Sidebar.Scene.js +585 -0
- package/client/editor/js/Sidebar.Script.js +129 -0
- package/client/editor/js/Sidebar.Settings.History.js +146 -0
- package/client/editor/js/Sidebar.Settings.Shortcuts.js +175 -0
- package/client/editor/js/Sidebar.Settings.js +60 -0
- package/client/editor/js/Sidebar.js +41 -0
- package/client/editor/js/Storage.js +98 -0
- package/client/editor/js/Strings.js +2028 -0
- package/client/editor/js/Toolbar.js +84 -0
- package/client/editor/js/Viewport.Controls.js +92 -0
- package/client/editor/js/Viewport.Info.js +136 -0
- package/client/editor/js/Viewport.Pathtracer.js +91 -0
- package/client/editor/js/Viewport.ViewHelper.js +39 -0
- package/client/editor/js/Viewport.XR.js +222 -0
- package/client/editor/js/Viewport.js +900 -0
- package/client/editor/js/commands/AddObjectCommand.js +68 -0
- package/client/editor/js/commands/AddScriptCommand.js +75 -0
- package/client/editor/js/commands/Commands.js +23 -0
- package/client/editor/js/commands/MoveObjectCommand.js +111 -0
- package/client/editor/js/commands/MultiCmdsCommand.js +85 -0
- package/client/editor/js/commands/RemoveObjectCommand.js +88 -0
- package/client/editor/js/commands/RemoveScriptCommand.js +81 -0
- package/client/editor/js/commands/SetColorCommand.js +73 -0
- package/client/editor/js/commands/SetGeometryCommand.js +87 -0
- package/client/editor/js/commands/SetGeometryValueCommand.js +70 -0
- package/client/editor/js/commands/SetMaterialColorCommand.js +86 -0
- package/client/editor/js/commands/SetMaterialCommand.js +79 -0
- package/client/editor/js/commands/SetMaterialMapCommand.js +143 -0
- package/client/editor/js/commands/SetMaterialRangeCommand.js +91 -0
- package/client/editor/js/commands/SetMaterialValueCommand.js +90 -0
- package/client/editor/js/commands/SetMaterialVectorCommand.js +79 -0
- package/client/editor/js/commands/SetPositionCommand.js +84 -0
- package/client/editor/js/commands/SetRotationCommand.js +84 -0
- package/client/editor/js/commands/SetScaleCommand.js +84 -0
- package/client/editor/js/commands/SetSceneCommand.js +103 -0
- package/client/editor/js/commands/SetScriptValueCommand.js +80 -0
- package/client/editor/js/commands/SetShadowValueCommand.js +73 -0
- package/client/editor/js/commands/SetUuidCommand.js +70 -0
- package/client/editor/js/commands/SetValueCommand.js +75 -0
- package/client/editor/js/libs/acorn/acorn.js +3236 -0
- package/client/editor/js/libs/acorn/acorn_loose.js +1299 -0
- package/client/editor/js/libs/acorn/walk.js +344 -0
- package/client/editor/js/libs/app/index.html +57 -0
- package/client/editor/js/libs/app.js +251 -0
- package/client/editor/js/libs/codemirror/addon/dialog.css +32 -0
- package/client/editor/js/libs/codemirror/addon/dialog.js +163 -0
- package/client/editor/js/libs/codemirror/addon/show-hint.css +36 -0
- package/client/editor/js/libs/codemirror/addon/show-hint.js +529 -0
- package/client/editor/js/libs/codemirror/addon/tern.css +87 -0
- package/client/editor/js/libs/codemirror/addon/tern.js +750 -0
- package/client/editor/js/libs/codemirror/codemirror.css +344 -0
- package/client/editor/js/libs/codemirror/codemirror.js +9849 -0
- package/client/editor/js/libs/codemirror/mode/glsl.js +233 -0
- package/client/editor/js/libs/codemirror/mode/javascript.js +959 -0
- package/client/editor/js/libs/codemirror/theme/monokai.css +41 -0
- package/client/editor/js/libs/esprima.js +6401 -0
- package/client/editor/js/libs/jsonlint.js +453 -0
- package/client/editor/js/libs/signals.min.js +14 -0
- package/client/editor/js/libs/tern-threejs/threejs.js +5031 -0
- package/client/editor/js/libs/ternjs/comment.js +87 -0
- package/client/editor/js/libs/ternjs/def.js +588 -0
- package/client/editor/js/libs/ternjs/doc_comment.js +401 -0
- package/client/editor/js/libs/ternjs/infer.js +1635 -0
- package/client/editor/js/libs/ternjs/polyfill.js +80 -0
- package/client/editor/js/libs/ternjs/signal.js +26 -0
- package/client/editor/js/libs/ternjs/tern.js +993 -0
- package/client/editor/js/libs/ui.js +1346 -0
- package/client/editor/js/libs/ui.three.js +855 -0
- package/client/facial-animation.js +455 -0
- package/client/index.html +7 -4
- package/client/loading.css +147 -0
- package/client/loading.html +25 -0
- package/client/style.css +251 -0
- package/package.json +7 -3
- package/server.js +9 -1
- package/src/apps/AppContext.js +1 -1
- package/src/apps/AppLoader.js +50 -37
- package/src/apps/AppRuntime.js +32 -8
- package/src/client/InputHandler.js +233 -0
- package/src/client/JitterBuffer.js +207 -0
- package/src/client/KalmanFilter.js +125 -0
- package/src/client/MessageHandler.js +101 -0
- package/src/client/PhysicsNetworkClient.js +141 -68
- package/src/client/ReconnectManager.js +62 -0
- package/src/client/SmoothInterpolation.js +127 -0
- package/src/client/SnapshotProcessor.js +144 -0
- package/src/connection/ConnectionManager.js +21 -3
- package/src/connection/SessionStore.js +13 -3
- package/src/index.client.js +4 -6
- package/src/netcode/EventLog.js +29 -15
- package/src/netcode/LagCompensator.js +25 -26
- package/src/netcode/NetworkState.js +4 -1
- package/src/netcode/PhysicsIntegration.js +20 -6
- package/src/netcode/PlayerManager.js +10 -2
- package/src/netcode/SnapshotEncoder.js +66 -19
- package/src/netcode/TickSystem.js +13 -4
- package/src/physics/World.js +66 -13
- package/src/protocol/msgpack.js +90 -63
- package/src/sdk/ReloadHandlers.js +12 -2
- package/src/sdk/ReloadManager.js +5 -0
- package/src/sdk/ServerHandlers.js +50 -11
- package/src/sdk/StaticHandler.js +22 -6
- package/src/sdk/TickHandler.js +101 -34
- package/src/sdk/scaffold.js +31 -0
- package/src/sdk/server.js +59 -33
- package/src/shared/movement.js +2 -1
- package/src/spatial/Octree.js +5 -0
- package/apps/interactive-door/index.js +0 -33
- package/apps/patrol-npc/index.js +0 -37
- package/src/connection/QualityMonitor.js +0 -46
- package/src/debug/StateInspector.js +0 -42
- package/src/index.js +0 -1
- package/src/index.server.js +0 -27
- package/src/protocol/Codec.js +0 -60
- package/src/protocol/SequenceTracker.js +0 -71
- package/src/sdk/ClientMessageHandler.js +0 -80
- package/src/sdk/client.js +0 -122
- package/world/kaira.glb +0 -0
- package/world/schwust.glb +0 -0
package/client/camera.js
CHANGED
|
@@ -7,14 +7,61 @@ const camDesired = new THREE.Vector3()
|
|
|
7
7
|
const camLookTarget = new THREE.Vector3()
|
|
8
8
|
const aimRaycaster = new THREE.Raycaster()
|
|
9
9
|
const aimDir = new THREE.Vector3()
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
let shoulderOffset = 0.35
|
|
11
|
+
let headHeight = 0.4
|
|
12
|
+
let camFollowSpeed = 12.0
|
|
13
|
+
let camSnapSpeed = 30.0
|
|
14
|
+
let zoomStages = [0, 1.5, 3, 5, 8]
|
|
15
|
+
let mouseSensitivity = 0.002
|
|
16
|
+
let pitchMin = -1.4, pitchMax = 1.4
|
|
17
|
+
|
|
18
|
+
function isDescendant(obj, ancestor) {
|
|
19
|
+
let cur = obj
|
|
20
|
+
while (cur) {
|
|
21
|
+
if (cur === ancestor) return true
|
|
22
|
+
cur = cur.parent
|
|
23
|
+
}
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const _boneWorldPos = new THREE.Vector3()
|
|
28
|
+
const _boneForward = new THREE.Vector3()
|
|
15
29
|
|
|
16
30
|
export function createCameraController(camera, scene) {
|
|
17
31
|
let yaw = 0, pitch = 0, zoomIndex = 2, camInitialized = false
|
|
32
|
+
let mode = 'tps'
|
|
33
|
+
let editMode = false
|
|
34
|
+
let editCamPos = new THREE.Vector3(0, 5, 10)
|
|
35
|
+
let editCamSpeed = 8
|
|
36
|
+
const envMeshes = []
|
|
37
|
+
let rayTimer = 0, cachedClipDist = 10, cachedAimPoint = null
|
|
38
|
+
let cameraBone = null
|
|
39
|
+
let headBone = null
|
|
40
|
+
let fpsForwardOffset = 0.7
|
|
41
|
+
let fpsHeadDownOffset = 0.2
|
|
42
|
+
camRaycaster.firstHitOnly = true
|
|
43
|
+
aimRaycaster.firstHitOnly = true
|
|
44
|
+
|
|
45
|
+
function setEnvironment(meshes) { envMeshes.length = 0; envMeshes.push(...meshes) }
|
|
46
|
+
function setCameraBone(bone) { cameraBone = bone }
|
|
47
|
+
function setHeadBone(bone) { headBone = bone }
|
|
48
|
+
|
|
49
|
+
function setMode(m) {
|
|
50
|
+
const prev = mode
|
|
51
|
+
mode = m
|
|
52
|
+
if (m === 'fps' && headBone) {
|
|
53
|
+
headBone.scale.set(0, 0, 0)
|
|
54
|
+
headBone.position.y -= fpsHeadDownOffset
|
|
55
|
+
}
|
|
56
|
+
if (prev === 'fps' && m !== 'fps' && headBone) {
|
|
57
|
+
headBone.scale.set(1, 1, 1)
|
|
58
|
+
headBone.position.y += fpsHeadDownOffset
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function getMode() { return mode }
|
|
62
|
+
|
|
63
|
+
function setPosition(x, y, z) { camera.position.set(x, y, z) }
|
|
64
|
+
function setTarget(x, y, z) { camera.lookAt(x, y, z) }
|
|
18
65
|
|
|
19
66
|
function restore(saved) {
|
|
20
67
|
if (saved) { yaw = saved.yaw || 0; pitch = saved.pitch || 0; zoomIndex = saved.zoomIndex ?? 2 }
|
|
@@ -23,9 +70,9 @@ export function createCameraController(camera, scene) {
|
|
|
23
70
|
function save() { return { yaw, pitch, zoomIndex } }
|
|
24
71
|
|
|
25
72
|
function onMouseMove(e) {
|
|
26
|
-
yaw -= e.movementX *
|
|
27
|
-
pitch -= e.movementY *
|
|
28
|
-
pitch = Math.max(
|
|
73
|
+
yaw -= e.movementX * mouseSensitivity
|
|
74
|
+
pitch -= e.movementY * mouseSensitivity
|
|
75
|
+
pitch = Math.max(pitchMin, Math.min(pitchMax, pitch))
|
|
29
76
|
}
|
|
30
77
|
|
|
31
78
|
function onWheel(e) {
|
|
@@ -51,19 +98,85 @@ export function createCameraController(camera, scene) {
|
|
|
51
98
|
return len > 0.001 ? [dx / len, dy / len, dz / len] : [fwdX, fwdY, fwdZ]
|
|
52
99
|
}
|
|
53
100
|
|
|
54
|
-
function update(localPlayer, localMesh, frameDt) {
|
|
55
|
-
if (
|
|
56
|
-
|
|
101
|
+
function update(localPlayer, localMesh, frameDt, inputState) {
|
|
102
|
+
if (mode === 'custom' || mode === 'fixed') return
|
|
103
|
+
if (!localPlayer && !editMode) return
|
|
104
|
+
|
|
105
|
+
if (editMode && inputState) {
|
|
106
|
+
const sy = Math.sin(yaw), cy = Math.cos(yaw)
|
|
107
|
+
const fwdX = sy, fwdZ = cy
|
|
108
|
+
const rightX = -cy, rightZ = sy
|
|
109
|
+
const moveForward = (inputState.forward ? 1 : 0) - (inputState.backward ? 1 : 0)
|
|
110
|
+
const moveRight = (inputState.right ? 1 : 0) - (inputState.left ? 1 : 0)
|
|
111
|
+
const moveUp = (inputState.jump ? 1 : 0) - (inputState.crouch ? 1 : 0)
|
|
112
|
+
const speed = editCamSpeed * frameDt
|
|
113
|
+
editCamPos.x += (moveForward * fwdX + moveRight * rightX) * speed
|
|
114
|
+
editCamPos.y += moveUp * speed
|
|
115
|
+
editCamPos.z += (moveForward * fwdZ + moveRight * rightZ) * speed
|
|
116
|
+
camera.position.copy(editCamPos)
|
|
117
|
+
const sp = Math.sin(pitch), cp = Math.cos(pitch)
|
|
118
|
+
camera.lookAt(
|
|
119
|
+
camera.position.x + fwdX * 100,
|
|
120
|
+
camera.position.y + sp * 100,
|
|
121
|
+
camera.position.z + fwdZ * 100
|
|
122
|
+
)
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const dist = mode === 'fps' ? 0 : zoomStages[zoomIndex]
|
|
57
127
|
camTarget.set(localPlayer.position[0], localPlayer.position[1] + headHeight, localPlayer.position[2])
|
|
58
|
-
|
|
128
|
+
const punchLerp = 1 - Math.exp(-972 * frameDt)
|
|
129
|
+
punchYaw += (punchYawTarget - punchYaw) * punchLerp
|
|
130
|
+
punchPitch += (punchPitchTarget - punchPitch) * punchLerp
|
|
131
|
+
punchYawTarget *= 1 - Math.min(1, 18 * frameDt)
|
|
132
|
+
punchPitchTarget *= 1 - Math.min(1, 18 * frameDt)
|
|
133
|
+
yaw += punchYaw * frameDt
|
|
134
|
+
pitch = Math.max(pitchMin, Math.min(pitchMax, pitch + punchPitch * frameDt))
|
|
59
135
|
const sy = Math.sin(yaw), cy = Math.cos(yaw)
|
|
60
136
|
const sp = Math.sin(pitch), cp = Math.cos(pitch)
|
|
61
137
|
const fwdX = sy * cp, fwdY = sp, fwdZ = cy * cp
|
|
62
138
|
const rightX = -cy, rightZ = sy
|
|
63
139
|
if (dist < 0.01) {
|
|
64
|
-
|
|
65
|
-
|
|
140
|
+
if (cameraBone && localMesh) {
|
|
141
|
+
localMesh.updateMatrixWorld(true)
|
|
142
|
+
cameraBone.getWorldPosition(_boneWorldPos)
|
|
143
|
+
_boneForward.set(fwdX, 0, fwdZ).normalize()
|
|
144
|
+
camera.position.copy(_boneWorldPos).addScaledVector(_boneForward, fpsForwardOffset)
|
|
145
|
+
camera.position.y += 0.35
|
|
146
|
+
} else {
|
|
147
|
+
camera.position.copy(camTarget)
|
|
148
|
+
}
|
|
149
|
+
if (headBone) headBone.scale.set(0, 0, 0)
|
|
150
|
+
const rayTargets = envMeshes.length ? envMeshes : scene.children
|
|
151
|
+
const wallDist = 0.35
|
|
152
|
+
const fpsRayOrigin = new THREE.Vector3().copy(camera.position)
|
|
153
|
+
const rayDirs = [
|
|
154
|
+
[fwdX, fwdY, fwdZ],
|
|
155
|
+
[rightX, 0, rightZ],
|
|
156
|
+
[-rightX, 0, -rightZ],
|
|
157
|
+
[0, 1, 0],
|
|
158
|
+
[0, -1, 0]
|
|
159
|
+
]
|
|
160
|
+
for (const d of rayDirs) {
|
|
161
|
+
camDir.set(-d[0], -d[1], -d[2])
|
|
162
|
+
camRaycaster.set(fpsRayOrigin, camDir)
|
|
163
|
+
camRaycaster.far = wallDist
|
|
164
|
+
camRaycaster.near = 0
|
|
165
|
+
const hits = camRaycaster.intersectObjects(rayTargets, true)
|
|
166
|
+
for (const hit of hits) {
|
|
167
|
+
if (localMesh && isDescendant(hit.object, localMesh)) continue
|
|
168
|
+
const push = wallDist - hit.distance
|
|
169
|
+
if (push > 0) {
|
|
170
|
+
camera.position.x += d[0] * push
|
|
171
|
+
camera.position.y += d[1] * push
|
|
172
|
+
camera.position.z += d[2] * push
|
|
173
|
+
}
|
|
174
|
+
break
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
camera.lookAt(camera.position.x + fwdX, camera.position.y + fwdY, camera.position.z + fwdZ)
|
|
66
178
|
} else {
|
|
179
|
+
if (headBone) headBone.scale.set(1, 1, 1)
|
|
67
180
|
camDesired.set(
|
|
68
181
|
camTarget.x - fwdX * dist + rightX * shoulderOffset,
|
|
69
182
|
camTarget.y - fwdY * dist + 0.2,
|
|
@@ -71,16 +184,22 @@ export function createCameraController(camera, scene) {
|
|
|
71
184
|
)
|
|
72
185
|
camDir.subVectors(camDesired, camTarget).normalize()
|
|
73
186
|
const fullDist = camTarget.distanceTo(camDesired)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
187
|
+
rayTimer += frameDt
|
|
188
|
+
const doRaycast = rayTimer >= 0.05
|
|
189
|
+
if (doRaycast) {
|
|
190
|
+
rayTimer = 0
|
|
191
|
+
camRaycaster.set(camTarget, camDir)
|
|
192
|
+
camRaycaster.far = fullDist
|
|
193
|
+
camRaycaster.near = 0
|
|
194
|
+
const hits = camRaycaster.intersectObjects(envMeshes.length ? envMeshes : scene.children, true)
|
|
195
|
+
cachedClipDist = fullDist
|
|
196
|
+
for (const hit of hits) {
|
|
197
|
+
if (localMesh && isDescendant(hit.object, localMesh)) continue
|
|
198
|
+
if (hit.distance < cachedClipDist) cachedClipDist = hit.distance - 0.2
|
|
199
|
+
}
|
|
200
|
+
if (cachedClipDist < 0.3) cachedClipDist = 0.3
|
|
82
201
|
}
|
|
83
|
-
|
|
202
|
+
const clippedDist = Math.min(cachedClipDist, fullDist)
|
|
84
203
|
camDesired.set(
|
|
85
204
|
camTarget.x + camDir.x * clippedDist,
|
|
86
205
|
camTarget.y + camDir.y * clippedDist,
|
|
@@ -93,16 +212,19 @@ export function createCameraController(camera, scene) {
|
|
|
93
212
|
camera.position.lerp(camDesired, 1.0 - Math.exp(-speed * frameDt))
|
|
94
213
|
}
|
|
95
214
|
aimDir.set(fwdX, fwdY, fwdZ)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
215
|
+
if (doRaycast) {
|
|
216
|
+
aimRaycaster.set(camera.position, aimDir)
|
|
217
|
+
aimRaycaster.far = 500
|
|
218
|
+
aimRaycaster.near = 0.5
|
|
219
|
+
const aimHits = aimRaycaster.intersectObjects(envMeshes.length ? envMeshes : scene.children, true)
|
|
220
|
+
cachedAimPoint = null
|
|
221
|
+
for (const ah of aimHits) {
|
|
222
|
+
if (localMesh && isDescendant(ah.object, localMesh)) continue
|
|
223
|
+
cachedAimPoint = ah.point; break
|
|
224
|
+
}
|
|
104
225
|
}
|
|
105
|
-
if (
|
|
226
|
+
if (cachedAimPoint) {
|
|
227
|
+
const aimPoint = cachedAimPoint
|
|
106
228
|
if (!camLookTarget.lengthSq()) camLookTarget.copy(aimPoint)
|
|
107
229
|
camLookTarget.lerp(aimPoint, 1.0 - Math.exp(-camFollowSpeed * frameDt))
|
|
108
230
|
} else {
|
|
@@ -112,5 +234,41 @@ export function createCameraController(camera, scene) {
|
|
|
112
234
|
}
|
|
113
235
|
}
|
|
114
236
|
|
|
115
|
-
|
|
237
|
+
function applyConfig(cfg) {
|
|
238
|
+
if (cfg.mode != null) mode = cfg.mode
|
|
239
|
+
if (cfg.shoulderOffset != null) shoulderOffset = cfg.shoulderOffset
|
|
240
|
+
if (cfg.headHeight != null) headHeight = cfg.headHeight
|
|
241
|
+
if (cfg.zoomStages) zoomStages = cfg.zoomStages
|
|
242
|
+
if (cfg.defaultZoomIndex != null) zoomIndex = cfg.defaultZoomIndex
|
|
243
|
+
if (cfg.followSpeed != null) camFollowSpeed = cfg.followSpeed
|
|
244
|
+
if (cfg.snapSpeed != null) camSnapSpeed = cfg.snapSpeed
|
|
245
|
+
if (cfg.mouseSensitivity != null) mouseSensitivity = cfg.mouseSensitivity
|
|
246
|
+
if (cfg.pitchRange) { pitchMin = cfg.pitchRange[0]; pitchMax = cfg.pitchRange[1] }
|
|
247
|
+
if (cfg.fov) { camera.fov = cfg.fov; camera.updateProjectionMatrix() }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let punchYawTarget = 0, punchPitchTarget = 0, punchYaw = 0, punchPitch = 0
|
|
251
|
+
function punch(intensity) {
|
|
252
|
+
punchYawTarget += (Math.random() - 0.5) * intensity * 0.9
|
|
253
|
+
punchPitchTarget += (Math.random() - 0.3) * intensity * 0.9
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function setVRYaw(vrYaw) { yaw = vrYaw }
|
|
257
|
+
function getVRYaw() { return yaw }
|
|
258
|
+
function setVRPitch(vrPitch) { pitch = vrPitch }
|
|
259
|
+
function getVRPitch() { return pitch }
|
|
260
|
+
function adjustVRPitch(delta) {
|
|
261
|
+
pitch = Math.max(pitchMin, Math.min(pitchMax, pitch + delta))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function setEditMode(enabled) {
|
|
265
|
+
if (enabled && !editMode) {
|
|
266
|
+
editCamPos.copy(camera.position)
|
|
267
|
+
}
|
|
268
|
+
editMode = enabled
|
|
269
|
+
}
|
|
270
|
+
function getEditMode() { return editMode }
|
|
271
|
+
function getEditCameraPosition() { return editCamPos }
|
|
272
|
+
|
|
273
|
+
return { restore, save, onMouseMove, onWheel, getAimDirection, update, setEnvironment, setCameraBone, setHeadBone, applyConfig, setMode, getMode, setPosition, setTarget, punch, setVRYaw, getVRYaw, setVRPitch, getVRPitch, adjustVRPitch, setEditMode, getEditMode, getEditCameraPosition, get yaw() { return yaw }, get pitch() { return pitch }, get mode() { return mode } }
|
|
116
274
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export function createLoadingScreen(loadingManager) {
|
|
2
|
+
const overlay = document.createElement('div')
|
|
3
|
+
overlay.id = 'loading-overlay'
|
|
4
|
+
overlay.className = 'loading-overlay'
|
|
5
|
+
overlay.innerHTML = `
|
|
6
|
+
<div class="loading-container">
|
|
7
|
+
<div class="loading-header">
|
|
8
|
+
<h1>Spawnpoint</h1>
|
|
9
|
+
<p class="loading-stage-text">Connecting...</p>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="loading-progress-wrapper">
|
|
12
|
+
<div class="loading-progress-bar">
|
|
13
|
+
<div class="loading-progress-fill"></div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="loading-percent">0%</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="loading-details">
|
|
18
|
+
<span class="loading-current">0</span> / <span class="loading-total">0</span> bytes
|
|
19
|
+
</div>
|
|
20
|
+
<div class="loading-spinner">
|
|
21
|
+
<div class="spinner-dot"></div>
|
|
22
|
+
<div class="spinner-dot"></div>
|
|
23
|
+
<div class="spinner-dot"></div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
`
|
|
27
|
+
document.body.insertBefore(overlay, document.body.firstChild)
|
|
28
|
+
|
|
29
|
+
const progressFill = overlay.querySelector('.loading-progress-fill')
|
|
30
|
+
const percentText = overlay.querySelector('.loading-percent')
|
|
31
|
+
const stageText = overlay.querySelector('.loading-stage-text')
|
|
32
|
+
const currentBytes = overlay.querySelector('.loading-current')
|
|
33
|
+
const totalBytes = overlay.querySelector('.loading-total')
|
|
34
|
+
|
|
35
|
+
const updateUI = (detail) => {
|
|
36
|
+
const percent = detail.percent || 0
|
|
37
|
+
progressFill.style.width = percent + '%'
|
|
38
|
+
percentText.textContent = Math.round(percent) + '%'
|
|
39
|
+
stageText.textContent = detail.label || ''
|
|
40
|
+
|
|
41
|
+
if (detail.current !== undefined && detail.total !== undefined) {
|
|
42
|
+
currentBytes.textContent = formatBytes(detail.current)
|
|
43
|
+
totalBytes.textContent = formatBytes(detail.total)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const formatBytes = (bytes) => {
|
|
48
|
+
if (bytes === 0) return '0'
|
|
49
|
+
const k = 1024
|
|
50
|
+
const sizes = ['B', 'KB', 'MB']
|
|
51
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
52
|
+
return Math.round((bytes / Math.pow(k, i)) * 10) / 10 + sizes[i]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
loadingManager.addEventListener('progress', (e) => updateUI(e.detail))
|
|
56
|
+
loadingManager.addEventListener('stagechange', (e) => updateUI(e.detail))
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
element: overlay,
|
|
60
|
+
hide: async () => {
|
|
61
|
+
overlay.classList.add('fade-out')
|
|
62
|
+
await new Promise(resolve => setTimeout(resolve, 500))
|
|
63
|
+
overlay.remove()
|
|
64
|
+
},
|
|
65
|
+
dispose: () => {
|
|
66
|
+
overlay.remove()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { PhysicsNetworkClient } from '/src/index.client.js'
|
|
2
|
+
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
|
|
3
|
+
|
|
4
|
+
export function connectEditorToGame(editor, THREE) {
|
|
5
|
+
const gltfLoader = new GLTFLoader()
|
|
6
|
+
const playerMeshes = new Map()
|
|
7
|
+
const entityMeshes = new Map()
|
|
8
|
+
|
|
9
|
+
const liveGroup = new THREE.Group()
|
|
10
|
+
liveGroup.name = 'Game Scene (Live)'
|
|
11
|
+
editor.addObject(liveGroup)
|
|
12
|
+
|
|
13
|
+
const playersGroup = new THREE.Group()
|
|
14
|
+
playersGroup.name = 'Players'
|
|
15
|
+
liveGroup.add(playersGroup)
|
|
16
|
+
|
|
17
|
+
const entitiesGroup = new THREE.Group()
|
|
18
|
+
entitiesGroup.name = 'Entities'
|
|
19
|
+
liveGroup.add(entitiesGroup)
|
|
20
|
+
|
|
21
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
22
|
+
|
|
23
|
+
const client = new PhysicsNetworkClient({
|
|
24
|
+
url: `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${location.host}/ws`,
|
|
25
|
+
predictionEnabled: false,
|
|
26
|
+
onStateUpdate(state) {
|
|
27
|
+
for (const p of state.players) {
|
|
28
|
+
let mesh = playerMeshes.get(p.id)
|
|
29
|
+
if (!mesh) {
|
|
30
|
+
mesh = new THREE.Group()
|
|
31
|
+
mesh.name = `Player_${p.id}`
|
|
32
|
+
const capsule = new THREE.Mesh(
|
|
33
|
+
new THREE.CapsuleGeometry(0.3, 1.0, 8, 16),
|
|
34
|
+
new THREE.MeshStandardMaterial({ color: 0x4488ff })
|
|
35
|
+
)
|
|
36
|
+
capsule.name = 'Capsule'
|
|
37
|
+
capsule.position.y = 0.8
|
|
38
|
+
mesh.add(capsule)
|
|
39
|
+
playersGroup.add(mesh)
|
|
40
|
+
playerMeshes.set(p.id, mesh)
|
|
41
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
42
|
+
}
|
|
43
|
+
mesh.position.set(p.position[0], p.position[1] - 1.3, p.position[2])
|
|
44
|
+
if (p.rotation) mesh.quaternion.set(p.rotation[0], p.rotation[1], p.rotation[2], p.rotation[3])
|
|
45
|
+
}
|
|
46
|
+
const activeIds = new Set(state.players.map(p => p.id))
|
|
47
|
+
for (const [id, mesh] of playerMeshes) {
|
|
48
|
+
if (!activeIds.has(id)) {
|
|
49
|
+
playersGroup.remove(mesh)
|
|
50
|
+
playerMeshes.delete(id)
|
|
51
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
editor.signals.objectChanged.dispatch(liveGroup)
|
|
55
|
+
},
|
|
56
|
+
onEntityAdded(id, entityState) {
|
|
57
|
+
if (entityState.model) {
|
|
58
|
+
const url = entityState.model.startsWith('./') ? '/' + entityState.model.slice(2) : entityState.model
|
|
59
|
+
gltfLoader.load(url, (gltf) => {
|
|
60
|
+
const model = gltf.scene
|
|
61
|
+
model.name = `Entity_${id}`
|
|
62
|
+
model.position.set(...entityState.position)
|
|
63
|
+
if (entityState.rotation) model.quaternion.set(...entityState.rotation)
|
|
64
|
+
entitiesGroup.add(model)
|
|
65
|
+
entityMeshes.set(id, model)
|
|
66
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
67
|
+
})
|
|
68
|
+
} else {
|
|
69
|
+
const c = entityState.custom || {}
|
|
70
|
+
const geo = c.mesh === 'sphere' ? new THREE.SphereGeometry(c.r || 0.5) :
|
|
71
|
+
c.mesh === 'cylinder' ? new THREE.CylinderGeometry(c.r || 0.4, c.r || 0.4, c.h || 0.1) :
|
|
72
|
+
new THREE.BoxGeometry(c.sx || 1, c.sy || 1, c.sz || 1)
|
|
73
|
+
const mat = new THREE.MeshStandardMaterial({ color: c.color ?? 0xff8800 })
|
|
74
|
+
const mesh = new THREE.Mesh(geo, mat)
|
|
75
|
+
mesh.name = `Entity_${id}`
|
|
76
|
+
mesh.position.set(...entityState.position)
|
|
77
|
+
if (entityState.rotation) mesh.quaternion.set(...entityState.rotation)
|
|
78
|
+
entitiesGroup.add(mesh)
|
|
79
|
+
entityMeshes.set(id, mesh)
|
|
80
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
onEntityRemoved(id) {
|
|
84
|
+
const mesh = entityMeshes.get(id)
|
|
85
|
+
if (mesh) {
|
|
86
|
+
entitiesGroup.remove(mesh)
|
|
87
|
+
entityMeshes.delete(id)
|
|
88
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
onWorldDef(wd) {
|
|
92
|
+
if (wd.scene) {
|
|
93
|
+
if (wd.scene.skyColor != null) editor.scene.background = new THREE.Color(wd.scene.skyColor)
|
|
94
|
+
if (wd.scene.fogColor != null) editor.scene.fog = new THREE.Fog(wd.scene.fogColor, wd.scene.fogNear ?? 80, wd.scene.fogFar ?? 200)
|
|
95
|
+
editor.signals.sceneBackgroundChanged.dispatch()
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
onPlayerLeft(id) {
|
|
99
|
+
const mesh = playerMeshes.get(id)
|
|
100
|
+
if (mesh) {
|
|
101
|
+
playersGroup.remove(mesh)
|
|
102
|
+
playerMeshes.delete(id)
|
|
103
|
+
editor.signals.sceneGraphChanged.dispatch()
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onHotReload() {}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
client.connect().then(() => console.log('[editor-bridge] Connected to game server'))
|
|
110
|
+
|
|
111
|
+
window.gameClient = client
|
|
112
|
+
window.liveGroup = liveGroup
|
|
113
|
+
}
|