spoint 0.1.83 → 0.1.84
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/maps/aim_kosova_ak47.glb +0 -0
- package/apps/maps/aim_kosova_battle.glb +0 -0
- package/apps/maps/aim_kosova_famas.glb +0 -0
- package/apps/maps/aim_sillos.glb +0 -0
- package/apps/maps/awp_india_ks.glb +0 -0
- package/apps/maps/awp_kosova.glb +0 -0
- package/apps/maps/awp_kosova_battle.glb +0 -0
- package/apps/maps/awp_kosovo_trainstation.glb +0 -0
- package/apps/maps/de_dolc.glb +0 -0
- package/apps/maps/de_dust2_kosovo.glb +0 -0
- package/apps/maps/de_gash.glb +0 -0
- package/apps/maps/de_kosovo.glb +0 -0
- package/apps/maps/de_kps.glb +0 -0
- package/apps/maps/de_pub2_r3.glb +0 -0
- package/apps/maps/deathrun_kosova.glb +0 -0
- package/apps/maps/fy_osama_house.glb +0 -0
- package/apps/prop-dynamic/index.js +13 -0
- package/apps/props/car1.glb +0 -0
- package/apps/props/car2.glb +0 -0
- package/apps/props/dynamic/3dPrinter1.glb +0 -0
- package/apps/props/dynamic/3dPrinter2.glb +0 -0
- package/apps/props/dynamic/AirConditioner1.glb +0 -0
- package/apps/props/dynamic/AirConditioner2.glb +0 -0
- package/apps/props/dynamic/AirConditioner3.glb +0 -0
- package/apps/props/dynamic/AirConditioner4.glb +0 -0
- package/apps/props/dynamic/ArmourToolBox1.glb +0 -0
- package/apps/props/dynamic/ArmourToolBox2.glb +0 -0
- package/apps/props/dynamic/ArmourToolBox3.glb +0 -0
- package/apps/props/dynamic/ArmourToolMan.glb +0 -0
- package/apps/props/dynamic/Atm1.glb +0 -0
- package/apps/props/dynamic/Atm2.glb +0 -0
- package/apps/props/dynamic/Atm3.glb +0 -0
- package/apps/props/dynamic/Atm4.glb +0 -0
- package/apps/props/dynamic/Ball1.glb +0 -0
- package/apps/props/dynamic/BeerBottle1.glb +0 -0
- package/apps/props/dynamic/BeerBottle2.glb +0 -0
- package/apps/props/dynamic/BeerBottle3.glb +0 -0
- package/apps/props/dynamic/BeerBottle4.glb +0 -0
- package/apps/props/dynamic/BreakRoomChair1.glb +0 -0
- package/apps/props/dynamic/BreakRoomChair2.glb +0 -0
- package/apps/props/dynamic/BreakRoomChair3.glb +0 -0
- package/apps/props/dynamic/BreakRoomChair4.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch1.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch2.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch3.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch4.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch5.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch6.glb +0 -0
- package/apps/props/dynamic/BreakRoomCouch7.glb +0 -0
- package/apps/props/dynamic/BreakRoomTable1.glb +0 -0
- package/apps/props/dynamic/BreakRoomTable2.glb +0 -0
- package/apps/props/dynamic/BrokenBeerBottles1.glb +0 -0
- package/apps/props/dynamic/BrokenBeerBottles2.glb +0 -0
- package/apps/props/dynamic/BrokenOfficeChair1.glb +0 -0
- package/apps/props/dynamic/BrokenOfficeChair2.glb +0 -0
- package/apps/props/dynamic/BrokenWaterCooler1.glb +0 -0
- package/apps/props/dynamic/BrokenWaterCooler2.glb +0 -0
- package/apps/props/dynamic/CanMan1.glb +0 -0
- package/apps/props/dynamic/CanMan2.glb +0 -0
- package/apps/props/dynamic/CanMan3.glb +0 -0
- package/apps/props/dynamic/CashRegister1.glb +0 -0
- package/apps/props/dynamic/CashRegister2.glb +0 -0
- package/apps/props/dynamic/CashRegister3.glb +0 -0
- package/apps/props/dynamic/ComfyChairs1.glb +0 -0
- package/apps/props/dynamic/CrushedGarbageCan1.glb +0 -0
- package/apps/props/dynamic/CrushedGarbageCan2.glb +0 -0
- package/apps/props/dynamic/CrushedGarbageCan3.glb +0 -0
- package/apps/props/dynamic/CrushedGarbageCan4.glb +0 -0
- package/apps/props/dynamic/DinnerTable1.glb +0 -0
- package/apps/props/dynamic/DinnerTable2.glb +0 -0
- package/apps/props/dynamic/DinnerTable3.glb +0 -0
- package/apps/props/dynamic/dj_mixer_baeeec4e_v1.glb +0 -0
- package/apps/props/dynamic/dj_mixer_baeeec4e_v2.glb +0 -0
- package/apps/props/dynamic/dj_mixer_baeeec4e_v3.glb +0 -0
- package/apps/props/dynamic/dj_mixer_baeeec4e_v4.glb +0 -0
- package/apps/props/dynamic/fancy_reception_desk_58fde71d_v1.glb +0 -0
- package/apps/props/dynamic/fancy_reception_desk_58fde71d_v2.glb +0 -0
- package/apps/props/dynamic/fancy_reception_desk_58fde71d_v3.glb +0 -0
- package/apps/props/dynamic/fancy_reception_desk_58fde71d_v4.glb +0 -0
- package/apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v1.glb +0 -0
- package/apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v2.glb +0 -0
- package/apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v3.glb +0 -0
- package/apps/props/dynamic/hi-fi_sound_system_2a2cc620_v1.glb +0 -0
- package/apps/props/dynamic/hi-fi_sound_system_2a2cc620_v2.glb +0 -0
- package/apps/props/dynamic/hi-fi_sound_system_2a2cc620_v3.glb +0 -0
- package/apps/props/dynamic/hi-fi_sound_system_2a2cc620_v4.glb +0 -0
- package/apps/props/dynamic/index.js +21 -0
- package/apps/props/dynamic/industrial_pipe_cb740c0c_v1.glb +0 -0
- package/apps/props/dynamic/industrial_pipe_cb740c0c_v2.glb +0 -0
- package/apps/props/dynamic/industrial_pipe_cb740c0c_v3.glb +0 -0
- package/apps/props/dynamic/industrial_pipe_cb740c0c_v4.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v1.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v2.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v3.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v4.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v1.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v2.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v3.glb +0 -0
- package/apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v4.glb +0 -0
- package/apps/props/dynamic/night_club_speakers_9155e359_v1.glb +0 -0
- package/apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v1.glb +0 -0
- package/apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v2.glb +0 -0
- package/apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v3.glb +0 -0
- package/apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v4.glb +0 -0
- package/apps/props/dynamic/server_rack_03b09d1f_v1.glb +0 -0
- package/apps/props/dynamic/server_rack_03b09d1f_v2.glb +0 -0
- package/apps/props/dynamic/server_rack_03b09d1f_v3.glb +0 -0
- package/apps/props/dynamic/server_rack_03b09d1f_v4.glb +0 -0
- package/apps/props/dynamic/server_rack_c2999a18_v1.glb +0 -0
- package/apps/props/dynamic/server_rack_c2999a18_v2.glb +0 -0
- package/apps/props/dynamic/server_rack_c2999a18_v3.glb +0 -0
- package/apps/props/dynamic/server_rack_c2999a18_v4.glb +0 -0
- package/apps/props/dynamic/shop_counter_f668a712_v1.glb +0 -0
- package/apps/props/dynamic/warehouse_crate_6e8a0927_v1.glb +0 -0
- package/apps/props/dynamic/warehouse_crate_6e8a0927_v2.glb +0 -0
- package/apps/props/dynamic/warehouse_crate_6e8a0927_v4.glb +0 -0
- package/apps/props/dynamic/water_tank_c27c18f7_v1.glb +0 -0
- package/apps/props/dynamic/water_tank_c27c18f7_v2.glb +0 -0
- package/apps/props/dynamic/water_tank_c27c18f7_v3.glb +0 -0
- package/apps/props/dynamic/water_tank_c27c18f7_v4.glb +0 -0
- package/apps/props/fountain.glb +0 -0
- package/apps/props/index.js +24 -0
- package/apps/props/rifle.glb +0 -0
- package/apps/props/rock1.glb +0 -0
- package/apps/props/rock2.glb +0 -0
- package/apps/world/index.js +130 -7
- package/client/app.js +72 -5
- package/package.json +1 -1
- package/src/apps/AppRuntime.js +31 -3
- package/src/netcode/SnapshotEncoder.js +6 -2
- package/src/physics/GLBLoader.js +6 -0
- package/src/physics/World.js +4 -0
- package/src/sdk/ServerHandlers.js +5 -2
- package/src/sdk/TickHandler.js +3 -2
- package/src/stage/Stage.js +1 -4
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
server: {
|
|
3
|
+
async setup(ctx) {
|
|
4
|
+
ctx.physics.setDynamic(true)
|
|
5
|
+
ctx.physics.addBoxCollider(0.5, 0.5, 0.5)
|
|
6
|
+
}
|
|
7
|
+
},
|
|
8
|
+
client: {
|
|
9
|
+
render(ctx) {
|
|
10
|
+
return { position: ctx.entity.position, rotation: ctx.entity.rotation, scale: ctx.entity.scale, model: ctx.entity.model }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
server: {
|
|
3
|
+
async setup(ctx) {
|
|
4
|
+
ctx.physics.setDynamic(true)
|
|
5
|
+
if (ctx.entity.model) {
|
|
6
|
+
try {
|
|
7
|
+
await ctx.physics.addConvexFromModel(0)
|
|
8
|
+
} catch (e) {
|
|
9
|
+
ctx.physics.addBoxCollider(0.5, 0.5, 0.5)
|
|
10
|
+
}
|
|
11
|
+
} else {
|
|
12
|
+
ctx.physics.addBoxCollider(0.5, 0.5, 0.5)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
client: {
|
|
17
|
+
render(ctx) {
|
|
18
|
+
return { position: ctx.entity.position, rotation: ctx.entity.rotation, scale: ctx.entity.scale, model: ctx.entity.model }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
server: {
|
|
3
|
+
async setup(ctx) {
|
|
4
|
+
ctx.physics.setStatic(true)
|
|
5
|
+
if (ctx.entity.model) {
|
|
6
|
+
try {
|
|
7
|
+
await ctx.physics.addConvexFromModel(0)
|
|
8
|
+
} catch (e) {
|
|
9
|
+
ctx.physics.addBoxCollider(1, 1, 1)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
client: {
|
|
15
|
+
render(ctx) {
|
|
16
|
+
return {
|
|
17
|
+
position: ctx.entity.position,
|
|
18
|
+
rotation: ctx.entity.rotation,
|
|
19
|
+
scale: ctx.entity.scale,
|
|
20
|
+
model: ctx.entity.model
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/apps/world/index.js
CHANGED
|
@@ -63,15 +63,138 @@ export default {
|
|
|
63
63
|
{ id: 'env-kosova', model: './apps/maps/aim_kosova_ak47.glb', position: [200, 0, 0], app: 'environment' },
|
|
64
64
|
{ id: 'env-sillos', model: './apps/maps/aim_sillos.glb', position: [400, 0, 0], app: 'environment' },
|
|
65
65
|
{ id: 'env-dust2', model: './apps/maps/de_dust2_kosovo.glb', position: [600, 0, 0], app: 'environment' },
|
|
66
|
-
{ id: 'env-gash', model: './apps/maps/de_gash.glb', position: [800, 0, 0], app: 'environment' }
|
|
66
|
+
{ id: 'env-gash', model: './apps/maps/de_gash.glb', position: [800, 0, 0], app: 'environment' },
|
|
67
|
+
|
|
68
|
+
{ id: 'prop-rock1-a', model: './apps/props/rock1.glb', position: [-10, 5, -10], app: 'props' },
|
|
69
|
+
{ id: 'prop-rock1-b', model: './apps/props/rock1.glb', position: [10, 5, 10], app: 'props' },
|
|
70
|
+
{ id: 'prop-rock2-a', model: './apps/props/rock2.glb', position: [-15, 5, 5], app: 'props' },
|
|
71
|
+
{ id: 'prop-car1-a', model: './apps/props/car1.glb', position: [-5, 5, -20], app: 'props' },
|
|
72
|
+
{ id: 'prop-car2-a', model: './apps/props/car2.glb', position: [15, 5, -15], app: 'props' },
|
|
73
|
+
{ id: 'prop-fountain', model: './apps/props/fountain.glb',position: [0, 5, 15], app: 'props' },
|
|
74
|
+
|
|
75
|
+
{ id: 'prop-rock1-c', model: './apps/props/rock1.glb', position: [190, 5, -10], app: 'props' },
|
|
76
|
+
{ id: 'prop-rock2-b', model: './apps/props/rock2.glb', position: [210, 5, 10], app: 'props' },
|
|
77
|
+
{ id: 'prop-car1-b', model: './apps/props/car1.glb', position: [205, 5, -15], app: 'props' },
|
|
78
|
+
|
|
79
|
+
{ id: 'prop-rock1-d', model: './apps/props/rock1.glb', position: [390, 5, -10], app: 'props' },
|
|
80
|
+
{ id: 'prop-car2-b', model: './apps/props/car2.glb', position: [415, 5, 10], app: 'props' },
|
|
81
|
+
|
|
82
|
+
{ id: 'prop-rock2-c', model: './apps/props/rock2.glb', position: [590, 5, -10], app: 'props' },
|
|
83
|
+
{ id: 'prop-car1-c', model: './apps/props/car1.glb', position: [610, 5, 5], app: 'props' },
|
|
84
|
+
|
|
85
|
+
{ id: 'prop-rock1-e', model: './apps/props/rock1.glb', position: [790, 5, -10], app: 'props' },
|
|
86
|
+
{ id: 'prop-car2-c', model: './apps/props/car2.glb', position: [810, 5, 5], app: 'props' },
|
|
87
|
+
|
|
88
|
+
{ id: 'dyn-ground', app: 'box-static', position: [66, -1, 236], config: { hx: 80, hy: 1, hz: 80, color: 0x888888 } },
|
|
89
|
+
{ id: 'dyn-0', model: './apps/props/dynamic/3dPrinter1.glb', position: [30, 30, 200], app: 'prop-dynamic' },
|
|
90
|
+
{ id: 'dyn-1', model: './apps/props/dynamic/3dPrinter2.glb', position: [38, 30, 200], app: 'prop-dynamic' },
|
|
91
|
+
{ id: 'dyn-2', model: './apps/props/dynamic/AirConditioner1.glb', position: [46, 30, 200], app: 'prop-dynamic' },
|
|
92
|
+
{ id: 'dyn-3', model: './apps/props/dynamic/AirConditioner2.glb', position: [54, 30, 200], app: 'prop-dynamic' },
|
|
93
|
+
{ id: 'dyn-4', model: './apps/props/dynamic/AirConditioner3.glb', position: [62, 30, 200], app: 'prop-dynamic' },
|
|
94
|
+
{ id: 'dyn-5', model: './apps/props/dynamic/AirConditioner4.glb', position: [70, 30, 200], app: 'prop-dynamic' },
|
|
95
|
+
{ id: 'dyn-6', model: './apps/props/dynamic/ArmourToolBox1.glb', position: [78, 30, 200], app: 'prop-dynamic' },
|
|
96
|
+
{ id: 'dyn-7', model: './apps/props/dynamic/ArmourToolBox2.glb', position: [86, 30, 200], app: 'prop-dynamic' },
|
|
97
|
+
{ id: 'dyn-8', model: './apps/props/dynamic/ArmourToolBox3.glb', position: [94, 30, 200], app: 'prop-dynamic' },
|
|
98
|
+
{ id: 'dyn-9', model: './apps/props/dynamic/ArmourToolMan.glb', position: [102, 30, 200], app: 'prop-dynamic' },
|
|
99
|
+
{ id: 'dyn-10', model: './apps/props/dynamic/Atm1.glb', position: [30, 33, 208], app: 'prop-dynamic' },
|
|
100
|
+
{ id: 'dyn-11', model: './apps/props/dynamic/Atm2.glb', position: [38, 33, 208], app: 'prop-dynamic' },
|
|
101
|
+
{ id: 'dyn-12', model: './apps/props/dynamic/Atm3.glb', position: [46, 33, 208], app: 'prop-dynamic' },
|
|
102
|
+
{ id: 'dyn-13', model: './apps/props/dynamic/Atm4.glb', position: [54, 33, 208], app: 'prop-dynamic' },
|
|
103
|
+
{ id: 'dyn-14', model: './apps/props/dynamic/Ball1.glb', position: [62, 33, 208], app: 'prop-dynamic' },
|
|
104
|
+
{ id: 'dyn-15', model: './apps/props/dynamic/BeerBottle1.glb', position: [70, 33, 208], app: 'prop-dynamic' },
|
|
105
|
+
{ id: 'dyn-16', model: './apps/props/dynamic/BeerBottle2.glb', position: [78, 33, 208], app: 'prop-dynamic' },
|
|
106
|
+
{ id: 'dyn-17', model: './apps/props/dynamic/BeerBottle3.glb', position: [86, 33, 208], app: 'prop-dynamic' },
|
|
107
|
+
{ id: 'dyn-18', model: './apps/props/dynamic/BeerBottle4.glb', position: [94, 33, 208], app: 'prop-dynamic' },
|
|
108
|
+
{ id: 'dyn-19', model: './apps/props/dynamic/BreakRoomChair1.glb', position: [102, 33, 208], app: 'prop-dynamic' },
|
|
109
|
+
{ id: 'dyn-20', model: './apps/props/dynamic/BreakRoomChair2.glb', position: [30, 36, 216], app: 'prop-dynamic' },
|
|
110
|
+
{ id: 'dyn-21', model: './apps/props/dynamic/BreakRoomChair3.glb', position: [38, 36, 216], app: 'prop-dynamic' },
|
|
111
|
+
{ id: 'dyn-22', model: './apps/props/dynamic/BreakRoomChair4.glb', position: [46, 36, 216], app: 'prop-dynamic' },
|
|
112
|
+
{ id: 'dyn-23', model: './apps/props/dynamic/BreakRoomCouch1.glb', position: [54, 36, 216], app: 'prop-dynamic' },
|
|
113
|
+
{ id: 'dyn-24', model: './apps/props/dynamic/BreakRoomCouch2.glb', position: [62, 36, 216], app: 'prop-dynamic' },
|
|
114
|
+
{ id: 'dyn-25', model: './apps/props/dynamic/BreakRoomCouch3.glb', position: [70, 36, 216], app: 'prop-dynamic' },
|
|
115
|
+
{ id: 'dyn-26', model: './apps/props/dynamic/BreakRoomCouch4.glb', position: [78, 36, 216], app: 'prop-dynamic' },
|
|
116
|
+
{ id: 'dyn-27', model: './apps/props/dynamic/BreakRoomCouch5.glb', position: [86, 36, 216], app: 'prop-dynamic' },
|
|
117
|
+
{ id: 'dyn-28', model: './apps/props/dynamic/BreakRoomCouch6.glb', position: [94, 36, 216], app: 'prop-dynamic' },
|
|
118
|
+
{ id: 'dyn-29', model: './apps/props/dynamic/BreakRoomCouch7.glb', position: [102, 36, 216], app: 'prop-dynamic' },
|
|
119
|
+
{ id: 'dyn-30', model: './apps/props/dynamic/BreakRoomTable1.glb', position: [30, 39, 224], app: 'prop-dynamic' },
|
|
120
|
+
{ id: 'dyn-31', model: './apps/props/dynamic/BreakRoomTable2.glb', position: [38, 39, 224], app: 'prop-dynamic' },
|
|
121
|
+
{ id: 'dyn-32', model: './apps/props/dynamic/BrokenBeerBottles1.glb', position: [46, 39, 224], app: 'prop-dynamic' },
|
|
122
|
+
{ id: 'dyn-33', model: './apps/props/dynamic/BrokenBeerBottles2.glb', position: [54, 39, 224], app: 'prop-dynamic' },
|
|
123
|
+
{ id: 'dyn-34', model: './apps/props/dynamic/BrokenOfficeChair1.glb', position: [62, 39, 224], app: 'prop-dynamic' },
|
|
124
|
+
{ id: 'dyn-35', model: './apps/props/dynamic/BrokenOfficeChair2.glb', position: [70, 39, 224], app: 'prop-dynamic' },
|
|
125
|
+
{ id: 'dyn-36', model: './apps/props/dynamic/BrokenWaterCooler1.glb', position: [78, 39, 224], app: 'prop-dynamic' },
|
|
126
|
+
{ id: 'dyn-37', model: './apps/props/dynamic/BrokenWaterCooler2.glb', position: [86, 39, 224], app: 'prop-dynamic' },
|
|
127
|
+
{ id: 'dyn-38', model: './apps/props/dynamic/CanMan1.glb', position: [94, 39, 224], app: 'prop-dynamic' },
|
|
128
|
+
{ id: 'dyn-39', model: './apps/props/dynamic/CanMan2.glb', position: [102, 39, 224], app: 'prop-dynamic' },
|
|
129
|
+
{ id: 'dyn-40', model: './apps/props/dynamic/CanMan3.glb', position: [30, 42, 232], app: 'prop-dynamic' },
|
|
130
|
+
{ id: 'dyn-41', model: './apps/props/dynamic/CashRegister1.glb', position: [38, 42, 232], app: 'prop-dynamic' },
|
|
131
|
+
{ id: 'dyn-42', model: './apps/props/dynamic/CashRegister2.glb', position: [46, 42, 232], app: 'prop-dynamic' },
|
|
132
|
+
{ id: 'dyn-43', model: './apps/props/dynamic/CashRegister3.glb', position: [54, 42, 232], app: 'prop-dynamic' },
|
|
133
|
+
{ id: 'dyn-44', model: './apps/props/dynamic/ComfyChairs1.glb', position: [62, 42, 232], app: 'prop-dynamic' },
|
|
134
|
+
{ id: 'dyn-45', model: './apps/props/dynamic/CrushedGarbageCan1.glb', position: [70, 42, 232], app: 'prop-dynamic' },
|
|
135
|
+
{ id: 'dyn-46', model: './apps/props/dynamic/CrushedGarbageCan2.glb', position: [78, 42, 232], app: 'prop-dynamic' },
|
|
136
|
+
{ id: 'dyn-47', model: './apps/props/dynamic/CrushedGarbageCan3.glb', position: [86, 42, 232], app: 'prop-dynamic' },
|
|
137
|
+
{ id: 'dyn-48', model: './apps/props/dynamic/CrushedGarbageCan4.glb', position: [94, 42, 232], app: 'prop-dynamic' },
|
|
138
|
+
{ id: 'dyn-49', model: './apps/props/dynamic/DinnerTable1.glb', position: [102, 42, 232], app: 'prop-dynamic' },
|
|
139
|
+
{ id: 'dyn-50', model: './apps/props/dynamic/DinnerTable2.glb', position: [30, 45, 240], app: 'prop-dynamic' },
|
|
140
|
+
{ id: 'dyn-51', model: './apps/props/dynamic/DinnerTable3.glb', position: [38, 45, 240], app: 'prop-dynamic' },
|
|
141
|
+
{ id: 'dyn-52', model: './apps/props/dynamic/dj_mixer_baeeec4e_v1.glb', position: [46, 45, 240], app: 'prop-dynamic' },
|
|
142
|
+
{ id: 'dyn-53', model: './apps/props/dynamic/dj_mixer_baeeec4e_v2.glb', position: [54, 45, 240], app: 'prop-dynamic' },
|
|
143
|
+
{ id: 'dyn-54', model: './apps/props/dynamic/dj_mixer_baeeec4e_v3.glb', position: [62, 45, 240], app: 'prop-dynamic' },
|
|
144
|
+
{ id: 'dyn-55', model: './apps/props/dynamic/dj_mixer_baeeec4e_v4.glb', position: [70, 45, 240], app: 'prop-dynamic' },
|
|
145
|
+
{ id: 'dyn-56', model: './apps/props/dynamic/fancy_reception_desk_58fde71d_v1.glb', position: [78, 45, 240], app: 'prop-dynamic' },
|
|
146
|
+
{ id: 'dyn-57', model: './apps/props/dynamic/fancy_reception_desk_58fde71d_v2.glb', position: [86, 45, 240], app: 'prop-dynamic' },
|
|
147
|
+
{ id: 'dyn-58', model: './apps/props/dynamic/fancy_reception_desk_58fde71d_v3.glb', position: [94, 45, 240], app: 'prop-dynamic' },
|
|
148
|
+
{ id: 'dyn-59', model: './apps/props/dynamic/fancy_reception_desk_58fde71d_v4.glb', position: [102, 45, 240], app: 'prop-dynamic' },
|
|
149
|
+
{ id: 'dyn-60', model: './apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v1.glb', position: [30, 48, 248], app: 'prop-dynamic' },
|
|
150
|
+
{ id: 'dyn-61', model: './apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v2.glb', position: [38, 48, 248], app: 'prop-dynamic' },
|
|
151
|
+
{ id: 'dyn-62', model: './apps/props/dynamic/heavy_machinery__crane_from_junk_yard_with_magnet_for_lifting_cars_db884752_v3.glb', position: [46, 48, 248], app: 'prop-dynamic' },
|
|
152
|
+
{ id: 'dyn-63', model: './apps/props/dynamic/hi-fi_sound_system_2a2cc620_v1.glb', position: [54, 48, 248], app: 'prop-dynamic' },
|
|
153
|
+
{ id: 'dyn-64', model: './apps/props/dynamic/hi-fi_sound_system_2a2cc620_v2.glb', position: [62, 48, 248], app: 'prop-dynamic' },
|
|
154
|
+
{ id: 'dyn-65', model: './apps/props/dynamic/hi-fi_sound_system_2a2cc620_v3.glb', position: [70, 48, 248], app: 'prop-dynamic' },
|
|
155
|
+
{ id: 'dyn-66', model: './apps/props/dynamic/hi-fi_sound_system_2a2cc620_v4.glb', position: [78, 48, 248], app: 'prop-dynamic' },
|
|
156
|
+
{ id: 'dyn-67', model: './apps/props/dynamic/industrial_pipe_cb740c0c_v1.glb', position: [86, 48, 248], app: 'prop-dynamic' },
|
|
157
|
+
{ id: 'dyn-68', model: './apps/props/dynamic/industrial_pipe_cb740c0c_v2.glb', position: [94, 48, 248], app: 'prop-dynamic' },
|
|
158
|
+
{ id: 'dyn-69', model: './apps/props/dynamic/industrial_pipe_cb740c0c_v3.glb', position: [102, 48, 248], app: 'prop-dynamic' },
|
|
159
|
+
{ id: 'dyn-70', model: './apps/props/dynamic/industrial_pipe_cb740c0c_v4.glb', position: [30, 51, 256], app: 'prop-dynamic' },
|
|
160
|
+
{ id: 'dyn-71', model: './apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v1.glb', position: [38, 51, 256], app: 'prop-dynamic' },
|
|
161
|
+
{ id: 'dyn-72', model: './apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v2.glb', position: [46, 51, 256], app: 'prop-dynamic' },
|
|
162
|
+
{ id: 'dyn-73', model: './apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v3.glb', position: [54, 51, 256], app: 'prop-dynamic' },
|
|
163
|
+
{ id: 'dyn-74', model: './apps/props/dynamic/l-shaped_industrial_pipe_3b570c7e_v4.glb', position: [62, 51, 256], app: 'prop-dynamic' },
|
|
164
|
+
{ id: 'dyn-75', model: './apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v1.glb', position: [70, 51, 256], app: 'prop-dynamic' },
|
|
165
|
+
{ id: 'dyn-76', model: './apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v2.glb', position: [78, 51, 256], app: 'prop-dynamic' },
|
|
166
|
+
{ id: 'dyn-77', model: './apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v3.glb', position: [86, 51, 256], app: 'prop-dynamic' },
|
|
167
|
+
{ id: 'dyn-78', model: './apps/props/dynamic/l-shaped_industrial_pipe_f7fd8524_v4.glb', position: [94, 51, 256], app: 'prop-dynamic' },
|
|
168
|
+
{ id: 'dyn-79', model: './apps/props/dynamic/night_club_speakers_9155e359_v1.glb', position: [102, 51, 256], app: 'prop-dynamic' },
|
|
169
|
+
{ id: 'dyn-80', model: './apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v1.glb', position: [30, 54, 264], app: 'prop-dynamic' },
|
|
170
|
+
{ id: 'dyn-81', model: './apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v2.glb', position: [38, 54, 264], app: 'prop-dynamic' },
|
|
171
|
+
{ id: 'dyn-82', model: './apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v3.glb', position: [46, 54, 264], app: 'prop-dynamic' },
|
|
172
|
+
{ id: 'dyn-83', model: './apps/props/dynamic/old_cheap_couch_with_a_bad_floral_pattern_53278f1b_v4.glb', position: [54, 54, 264], app: 'prop-dynamic' },
|
|
173
|
+
{ id: 'dyn-84', model: './apps/props/dynamic/server_rack_03b09d1f_v1.glb', position: [62, 54, 264], app: 'prop-dynamic' },
|
|
174
|
+
{ id: 'dyn-85', model: './apps/props/dynamic/server_rack_03b09d1f_v2.glb', position: [70, 54, 264], app: 'prop-dynamic' },
|
|
175
|
+
{ id: 'dyn-86', model: './apps/props/dynamic/server_rack_03b09d1f_v3.glb', position: [78, 54, 264], app: 'prop-dynamic' },
|
|
176
|
+
{ id: 'dyn-87', model: './apps/props/dynamic/server_rack_03b09d1f_v4.glb', position: [86, 54, 264], app: 'prop-dynamic' },
|
|
177
|
+
{ id: 'dyn-88', model: './apps/props/dynamic/server_rack_c2999a18_v1.glb', position: [94, 54, 264], app: 'prop-dynamic' },
|
|
178
|
+
{ id: 'dyn-89', model: './apps/props/dynamic/server_rack_c2999a18_v2.glb', position: [102, 54, 264], app: 'prop-dynamic' },
|
|
179
|
+
{ id: 'dyn-90', model: './apps/props/dynamic/server_rack_c2999a18_v3.glb', position: [30, 57, 272], app: 'prop-dynamic' },
|
|
180
|
+
{ id: 'dyn-91', model: './apps/props/dynamic/server_rack_c2999a18_v4.glb', position: [38, 57, 272], app: 'prop-dynamic' },
|
|
181
|
+
{ id: 'dyn-92', model: './apps/props/dynamic/shop_counter_f668a712_v1.glb', position: [46, 57, 272], app: 'prop-dynamic' },
|
|
182
|
+
{ id: 'dyn-93', model: './apps/props/dynamic/warehouse_crate_6e8a0927_v1.glb', position: [54, 57, 272], app: 'prop-dynamic' },
|
|
183
|
+
{ id: 'dyn-94', model: './apps/props/dynamic/warehouse_crate_6e8a0927_v2.glb', position: [62, 57, 272], app: 'prop-dynamic' },
|
|
184
|
+
{ id: 'dyn-95', model: './apps/props/dynamic/warehouse_crate_6e8a0927_v4.glb', position: [70, 57, 272], app: 'prop-dynamic' },
|
|
185
|
+
{ id: 'dyn-96', model: './apps/props/dynamic/water_tank_c27c18f7_v1.glb', position: [78, 57, 272], app: 'prop-dynamic' },
|
|
186
|
+
{ id: 'dyn-97', model: './apps/props/dynamic/water_tank_c27c18f7_v2.glb', position: [86, 57, 272], app: 'prop-dynamic' },
|
|
187
|
+
{ id: 'dyn-98', model: './apps/props/dynamic/water_tank_c27c18f7_v3.glb', position: [94, 57, 272], app: 'prop-dynamic' },
|
|
188
|
+
{ id: 'dyn-99', model: './apps/props/dynamic/water_tank_c27c18f7_v4.glb', position: [102, 57, 272], app: 'prop-dynamic' }
|
|
67
189
|
],
|
|
68
190
|
spawnPoints: [
|
|
69
|
-
[
|
|
70
|
-
[
|
|
71
|
-
[
|
|
72
|
-
[
|
|
73
|
-
[
|
|
191
|
+
[10, 5, 10],
|
|
192
|
+
[200, 5, -10],
|
|
193
|
+
[400, 5, -10],
|
|
194
|
+
[610, 5, 5],
|
|
195
|
+
[800, 5, -10]
|
|
74
196
|
],
|
|
75
|
-
spawnPoint: [
|
|
197
|
+
spawnPoint: [10, 5, 10],
|
|
76
198
|
playerModel: './apps/tps-game/cleetus.vrm'
|
|
77
199
|
}
|
|
200
|
+
|
package/client/app.js
CHANGED
|
@@ -21,6 +21,37 @@ import { createLoadingScreen } from './createLoadingScreen.js'
|
|
|
21
21
|
import { MobileControls, detectDevice } from './MobileControls.js'
|
|
22
22
|
import { XRControls, createXRButton } from './XRControls.js'
|
|
23
23
|
|
|
24
|
+
function patchGLB(arrayBuffer) {
|
|
25
|
+
try {
|
|
26
|
+
const v = new DataView(arrayBuffer)
|
|
27
|
+
if (v.getUint32(0, true) !== 0x46546C67) return arrayBuffer
|
|
28
|
+
const jsonLen = v.getUint32(12, true)
|
|
29
|
+
const jsonBytes = new Uint8Array(arrayBuffer, 20, jsonLen)
|
|
30
|
+
const json = JSON.parse(new TextDecoder().decode(jsonBytes))
|
|
31
|
+
if (!json.textures) return arrayBuffer
|
|
32
|
+
json.textures = json.textures.map(t => {
|
|
33
|
+
if (t.source === undefined && (!t.extensions || !Object.keys(t.extensions).some(k => t.extensions[k]?.source !== undefined))) {
|
|
34
|
+
return { ...t, source: 0 }
|
|
35
|
+
}
|
|
36
|
+
return t
|
|
37
|
+
})
|
|
38
|
+
const patched = new TextEncoder().encode(JSON.stringify(json))
|
|
39
|
+
const pad = (4 - (patched.length % 4)) % 4
|
|
40
|
+
const out = new ArrayBuffer(12 + 8 + patched.length + pad + (arrayBuffer.byteLength - 20 - jsonLen))
|
|
41
|
+
const ov = new DataView(out)
|
|
42
|
+
const ou = new Uint8Array(out)
|
|
43
|
+
ov.setUint32(0, 0x46546C67, true)
|
|
44
|
+
ov.setUint32(4, v.getUint32(4, true), true)
|
|
45
|
+
ov.setUint32(8, out.byteLength, true)
|
|
46
|
+
ov.setUint32(12, patched.length + pad, true)
|
|
47
|
+
ov.setUint32(16, 0x4E4F534A, true)
|
|
48
|
+
ou.set(patched, 20)
|
|
49
|
+
for (let i = 0; i < pad; i++) ou[20 + patched.length + i] = 0x20
|
|
50
|
+
ou.set(new Uint8Array(arrayBuffer, 20 + jsonLen), 20 + patched.length + pad)
|
|
51
|
+
return out
|
|
52
|
+
} catch (_) { return arrayBuffer }
|
|
53
|
+
}
|
|
54
|
+
|
|
24
55
|
const loadingMgr = new LoadingManager()
|
|
25
56
|
const loadingScreen = createLoadingScreen(loadingMgr)
|
|
26
57
|
loadingMgr.setStage('CONNECTING')
|
|
@@ -705,6 +736,21 @@ let vrmBuffer = null
|
|
|
705
736
|
let animAssets = null
|
|
706
737
|
let assetsReady = null
|
|
707
738
|
let assetsLoaded = false
|
|
739
|
+
const MAX_VRM_CONCURRENT = 6
|
|
740
|
+
let _vrmActive = 0
|
|
741
|
+
const _vrmQueue = []
|
|
742
|
+
function _vrmSlot() {
|
|
743
|
+
if (_vrmActive >= MAX_VRM_CONCURRENT || _vrmQueue.length === 0) return
|
|
744
|
+
_vrmActive++
|
|
745
|
+
const resolve = _vrmQueue.shift()
|
|
746
|
+
resolve()
|
|
747
|
+
}
|
|
748
|
+
function acquireVrmSlot() {
|
|
749
|
+
return new Promise(r => { _vrmQueue.push(r); _vrmSlot() })
|
|
750
|
+
}
|
|
751
|
+
function releaseVrmSlot() {
|
|
752
|
+
_vrmActive--; _vrmSlot()
|
|
753
|
+
}
|
|
708
754
|
|
|
709
755
|
function detectVrmVersion(buffer) {
|
|
710
756
|
try {
|
|
@@ -739,6 +785,8 @@ async function createPlayerVRM(id) {
|
|
|
739
785
|
playerMeshes.set(id, group)
|
|
740
786
|
if (assetsReady) await assetsReady
|
|
741
787
|
if (!vrmBuffer) return group
|
|
788
|
+
await acquireVrmSlot()
|
|
789
|
+
if (!playerMeshes.has(id)) { releaseVrmSlot(); return group }
|
|
742
790
|
try {
|
|
743
791
|
const gltf = await gltfLoader.parseAsync(vrmBuffer.buffer.slice(0), '')
|
|
744
792
|
const vrm = gltf.userData.vrm
|
|
@@ -786,7 +834,7 @@ async function createPlayerVRM(id) {
|
|
|
786
834
|
console.log('[shader] vrm warmup compile done (fallback)')
|
|
787
835
|
})
|
|
788
836
|
}
|
|
789
|
-
} catch (e) { console.error('[vrm]', id, e.message) }
|
|
837
|
+
} catch (e) { console.error('[vrm]', id, e.message) } finally { releaseVrmSlot() }
|
|
790
838
|
return group
|
|
791
839
|
}
|
|
792
840
|
|
|
@@ -979,8 +1027,11 @@ function loadEntityModel(entityId, entityState) {
|
|
|
979
1027
|
const mp = entityState.position; model.position.set(mp[0], mp[1], mp[2])
|
|
980
1028
|
const mr = entityState.rotation; if (mr) model.quaternion.set(mr[0], mr[1], mr[2], mr[3])
|
|
981
1029
|
const colliders = []
|
|
1030
|
+
const SKIP_MATS = new Set(['aaatrigger', '{invisible', 'playerclip', 'clip', 'nodraw', 'trigger', 'sky', 'toolsclip', 'toolsplayerclip', 'toolsnodraw', 'toolsskybox', 'toolstrigger'])
|
|
982
1031
|
model.traverse(c => {
|
|
983
1032
|
if (c.isMesh) {
|
|
1033
|
+
const matName = (c.material?.name || '').toLowerCase()
|
|
1034
|
+
if (SKIP_MATS.has(matName) || SKIP_MATS.has(c.material?.name)) { c.visible = false; return }
|
|
984
1035
|
c.castShadow = true
|
|
985
1036
|
c.receiveShadow = true
|
|
986
1037
|
if (!c.isSkinnedMesh) { c.matrixAutoUpdate = false; c.geometry.computeBoundsTree(); colliders.push(c) }
|
|
@@ -1000,7 +1051,7 @@ function loadEntityModel(entityId, entityState) {
|
|
|
1000
1051
|
}
|
|
1001
1052
|
const onGltfErr = (err) => { console.error('[gltf]', url, err); pendingLoads.delete(entityId); if (firstSnapshotEntityPending.has(entityId)) { firstSnapshotEntityPending.delete(entityId); if (firstSnapshotEntityPending.size === 0) checkAllLoaded() } }
|
|
1002
1053
|
fetchCached(url).then(buf => {
|
|
1003
|
-
gltfLoader.parse(buf.buffer.slice(0), '', onGltfLoad, onGltfErr)
|
|
1054
|
+
gltfLoader.parse(patchGLB(buf.buffer.slice(0)), '', onGltfLoad, onGltfErr)
|
|
1004
1055
|
}).catch(onGltfErr)
|
|
1005
1056
|
}
|
|
1006
1057
|
|
|
@@ -1047,8 +1098,24 @@ const client = new PhysicsNetworkClient({
|
|
|
1047
1098
|
predictionEnabled: true,
|
|
1048
1099
|
smoothInterpolation: true,
|
|
1049
1100
|
onStateUpdate: (state) => {
|
|
1050
|
-
|
|
1051
|
-
|
|
1101
|
+
const myPos = state.players.find(p => p.id === client.playerId)?.position
|
|
1102
|
+
const sorted = myPos ? [...state.players].sort((a, b) => {
|
|
1103
|
+
if (a.id === client.playerId) return -1
|
|
1104
|
+
if (b.id === client.playerId) return 1
|
|
1105
|
+
const da = (a.position[0]-myPos[0])**2+(a.position[1]-myPos[1])**2+(a.position[2]-myPos[2])**2
|
|
1106
|
+
const db = (b.position[0]-myPos[0])**2+(b.position[1]-myPos[1])**2+(b.position[2]-myPos[2])**2
|
|
1107
|
+
return da - db
|
|
1108
|
+
}) : state.players
|
|
1109
|
+
const MAX_VISIBLE_PLAYERS = 32
|
|
1110
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
1111
|
+
const p = sorted[i]
|
|
1112
|
+
if (!playerMeshes.has(p.id)) {
|
|
1113
|
+
if (i < MAX_VISIBLE_PLAYERS) createPlayerVRM(p.id)
|
|
1114
|
+
else { const g = new THREE.Group(); scene.add(g); playerMeshes.set(p.id, g) }
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
for (const [id] of playerMeshes) {
|
|
1118
|
+
if (!state.players.find(p => p.id === id)) removePlayerMesh(id)
|
|
1052
1119
|
}
|
|
1053
1120
|
for (const e of state.entities) {
|
|
1054
1121
|
const mesh = entityMeshes.get(e.id)
|
|
@@ -1079,7 +1146,7 @@ const client = new PhysicsNetworkClient({
|
|
|
1079
1146
|
worldConfig = wd
|
|
1080
1147
|
if (wd.playerModel) initAssets(wd.playerModel.startsWith('./') ? '/' + wd.playerModel.slice(2) : wd.playerModel)
|
|
1081
1148
|
else { assetsReady = Promise.resolve(); assetsLoaded = true; checkAllLoaded() }
|
|
1082
|
-
if (wd.entities) for (const e of wd.entities) { if (e.app) entityAppMap.set(e.id, e.app)
|
|
1149
|
+
if (wd.entities) for (const e of wd.entities) { if (e.app) entityAppMap.set(e.id, e.app) }
|
|
1083
1150
|
if (wd.scene) applySceneConfig(wd.scene)
|
|
1084
1151
|
if (wd.camera) cam.applyConfig(wd.camera)
|
|
1085
1152
|
if (wd.input) {
|
package/package.json
CHANGED
package/src/apps/AppRuntime.js
CHANGED
|
@@ -126,7 +126,21 @@ export class AppRuntime {
|
|
|
126
126
|
const ctx = this.contexts.get(entityId); if (!ctx) continue
|
|
127
127
|
this._safeCall(appDef.server || appDef, 'update', [ctx, dt], `update(${entityId})`)
|
|
128
128
|
}
|
|
129
|
-
this._tickTimers(dt); this._spatialSync(); this._tickCollisions(); this._tickInteractables()
|
|
129
|
+
this._tickTimers(dt); this._syncDynamicBodies(); this._spatialSync(); this._tickCollisions(); this._tickInteractables()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
_syncDynamicBodies() {
|
|
133
|
+
if (!this._physics) return
|
|
134
|
+
for (const e of this.entities.values()) {
|
|
135
|
+
if (e.bodyType !== 'dynamic' || e._physicsBodyId === undefined) continue
|
|
136
|
+
const active = this._physics.isBodyActive(e._physicsBodyId)
|
|
137
|
+
if (!active && e._dynSleeping) continue
|
|
138
|
+
e._dynSleeping = !active
|
|
139
|
+
const p = this._physics.getBodyPosition(e._physicsBodyId)
|
|
140
|
+
const r = this._physics.getBodyRotation(e._physicsBodyId)
|
|
141
|
+
e.position[0] = p[0]; e.position[1] = p[1]; e.position[2] = p[2]
|
|
142
|
+
e.rotation[0] = r[0]; e.rotation[1] = r[1]; e.rotation[2] = r[2]; e.rotation[3] = r[3]
|
|
143
|
+
}
|
|
130
144
|
}
|
|
131
145
|
|
|
132
146
|
_encodeEntity(id, e) {
|
|
@@ -143,7 +157,9 @@ export class AppRuntime {
|
|
|
143
157
|
getSnapshotForPlayer(playerPosition, radius) {
|
|
144
158
|
const relevant = new Set(this.relevantEntities(playerPosition, radius))
|
|
145
159
|
const entities = []
|
|
146
|
-
for (const [id, e] of this.entities) {
|
|
160
|
+
for (const [id, e] of this.entities) {
|
|
161
|
+
if (relevant.has(id) || e._appName === 'environment') entities.push(this._encodeEntity(id, e))
|
|
162
|
+
}
|
|
147
163
|
return { tick: this.currentTick, timestamp: Date.now(), entities }
|
|
148
164
|
}
|
|
149
165
|
|
|
@@ -207,7 +223,19 @@ export class AppRuntime {
|
|
|
207
223
|
}
|
|
208
224
|
}
|
|
209
225
|
|
|
210
|
-
_colR(c) {
|
|
226
|
+
_colR(c) {
|
|
227
|
+
if (!c) return 0
|
|
228
|
+
if (c.type === 'sphere') return c.radius || 1
|
|
229
|
+
if (c.type === 'capsule') return Math.max(c.radius || 0.5, (c.height || 1) / 2)
|
|
230
|
+
if (c.type === 'box') {
|
|
231
|
+
const s = c.size; const h = c.halfExtents
|
|
232
|
+
if (Array.isArray(s)) return Math.max(...s)
|
|
233
|
+
if (typeof s === 'number') return s
|
|
234
|
+
if (Array.isArray(h)) return Math.max(...h)
|
|
235
|
+
return 1
|
|
236
|
+
}
|
|
237
|
+
return 1
|
|
238
|
+
}
|
|
211
239
|
setPlayerManager(pm) { this._playerManager = pm }
|
|
212
240
|
setStageLoader(sl) { this._stageLoader = sl }
|
|
213
241
|
getPlayers() { return this._playerManager ? this._playerManager.getConnectedPlayers() : [] }
|
|
@@ -29,8 +29,12 @@ function encodeEntity(e) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export class SnapshotEncoder {
|
|
32
|
-
static
|
|
33
|
-
|
|
32
|
+
static encodePlayers(players) {
|
|
33
|
+
return (players || []).map(encodePlayer)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static encodeDelta(snapshot, prevEntityMap, preEncodedPlayers) {
|
|
37
|
+
const players = preEncodedPlayers || (snapshot.players || []).map(encodePlayer)
|
|
34
38
|
const currentIds = new Set()
|
|
35
39
|
const entities = []
|
|
36
40
|
const nextMap = new Map()
|
package/src/physics/GLBLoader.js
CHANGED
|
@@ -389,6 +389,9 @@ export async function extractAllMeshesFromGLBAsync(filepath) {
|
|
|
389
389
|
|
|
390
390
|
// Build a node->transform map for node hierarchy
|
|
391
391
|
const nodeTransforms = buildNodeTransforms(json)
|
|
392
|
+
const materials = json.materials || []
|
|
393
|
+
// Source Engine / CS:GO invisible/trigger materials — exclude from physics
|
|
394
|
+
const SKIP_MATS = new Set(['aaatrigger', '{invisible', 'playerclip', 'clip', 'nodraw', 'trigger', 'sky', 'toolsclip', 'toolsplayerclip', 'toolsnodraw', 'toolsskybox', 'toolstrigger'])
|
|
392
395
|
|
|
393
396
|
for (let meshIdx = 0; meshIdx < (json.meshes || []).length; meshIdx++) {
|
|
394
397
|
const mesh = json.meshes[meshIdx]
|
|
@@ -398,6 +401,9 @@ export async function extractAllMeshesFromGLBAsync(filepath) {
|
|
|
398
401
|
|
|
399
402
|
for (let primIdx = 0; primIdx < mesh.primitives.length; primIdx++) {
|
|
400
403
|
const prim = mesh.primitives[primIdx]
|
|
404
|
+
// Skip invisible/trigger materials that should not have physics collision
|
|
405
|
+
const matName = prim.material !== undefined ? (materials[prim.material]?.name || '') : ''
|
|
406
|
+
if (SKIP_MATS.has(matName)) continue
|
|
401
407
|
let result
|
|
402
408
|
try {
|
|
403
409
|
if (prim.extensions?.KHR_draco_mesh_compression) {
|
package/src/physics/World.js
CHANGED
|
@@ -267,6 +267,10 @@ export class PhysicsWorld {
|
|
|
267
267
|
this.Jolt.destroy(v)
|
|
268
268
|
return r
|
|
269
269
|
}
|
|
270
|
+
isBodyActive(bodyId) {
|
|
271
|
+
const b = this._getBody(bodyId); if (!b) return false
|
|
272
|
+
const id = b.GetID(); const r = this.bodyInterface.IsActive(id); this.Jolt.destroy(id); return r
|
|
273
|
+
}
|
|
270
274
|
setBodyPosition(bodyId, position) {
|
|
271
275
|
const b = this._getBody(bodyId); if (!b) return
|
|
272
276
|
const p = this._tmpRVec3 || new this.Jolt.RVec3(0, 0, 0); p.Set(position[0], position[1], position[2])
|
|
@@ -24,8 +24,11 @@ export function createConnectionHandlers(ctx) {
|
|
|
24
24
|
for (const [appName, code] of Object.entries(clientModules)) {
|
|
25
25
|
connections.send(playerId, MSG.APP_MODULE, { app: appName, code })
|
|
26
26
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
27
|
+
const relevanceRadius = ctx.currentWorldDef?.relevanceRadius || 0
|
|
28
|
+
const snapEntities = relevanceRadius > 0 ? appRuntime.getSnapshotForPlayer(sp, relevanceRadius) : appRuntime.getSnapshot()
|
|
29
|
+
const playerSnap = networkState.getSnapshot()
|
|
30
|
+
const combined = { tick: playerSnap.tick, timestamp: playerSnap.timestamp, players: playerSnap.players, entities: snapEntities.entities }
|
|
31
|
+
connections.send(playerId, MSG.SNAPSHOT, { seq: ++ctx.snapshotSeq, ...SnapshotEncoder.encode(combined) })
|
|
29
32
|
for (const [entityId] of appRuntime.apps) appRuntime.fireMessage(entityId, { type: 'player_join', playerId })
|
|
30
33
|
emitter.emit('playerJoin', { id: playerId })
|
|
31
34
|
}
|
package/src/sdk/TickHandler.js
CHANGED
|
@@ -126,12 +126,13 @@ export function createTickHandler(deps) {
|
|
|
126
126
|
? stageLoader.getActiveStage().spatial.relevanceRadius
|
|
127
127
|
: (getRelevanceRadius ? getRelevanceRadius() : 0)
|
|
128
128
|
if (relevanceRadius > 0) {
|
|
129
|
+
const preEncodedPlayers = SnapshotEncoder.encodePlayers(playerSnap.players)
|
|
129
130
|
for (const player of players) {
|
|
130
131
|
if (!isKeyframe && player.id % snapGroups !== curGroup) continue
|
|
131
132
|
const entitySnap = appRuntime.getSnapshotForPlayer(player.state.position, relevanceRadius)
|
|
132
|
-
const combined = { tick: playerSnap.tick, timestamp: playerSnap.timestamp,
|
|
133
|
+
const combined = { tick: playerSnap.tick, timestamp: playerSnap.timestamp, entities: entitySnap.entities }
|
|
133
134
|
const prevMap = (isKeyframe || !playerEntityMaps.has(player.id)) ? new Map() : playerEntityMaps.get(player.id)
|
|
134
|
-
const { encoded, entityMap } = SnapshotEncoder.encodeDelta(combined, prevMap)
|
|
135
|
+
const { encoded, entityMap } = SnapshotEncoder.encodeDelta(combined, prevMap, preEncodedPlayers)
|
|
135
136
|
playerEntityMaps.set(player.id, entityMap)
|
|
136
137
|
connections.send(player.id, MSG.SNAPSHOT, { seq: snapshotSeq, ...encoded })
|
|
137
138
|
}
|
package/src/stage/Stage.js
CHANGED
|
@@ -46,10 +46,7 @@ export class Stage {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
getRelevantEntities(position, radius) {
|
|
49
|
-
|
|
50
|
-
const set = new Set(nearby)
|
|
51
|
-
for (const sid of this._staticIds) set.add(sid)
|
|
52
|
-
return Array.from(set)
|
|
49
|
+
return this.spatial.nearby(position, radius || this.spatial.relevanceRadius)
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
getStaticIds() {
|