@hytopia.com/examples 1.0.45 → 1.0.48

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.
Files changed (343) hide show
  1. package/big-world/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  2. package/big-world/assets/blocks/.atlas/atlas.json +3377 -0
  3. package/big-world/assets/blocks/.atlas/atlas.ktx2 +0 -0
  4. package/big-world/assets/blocks/.atlas/atlas.png +0 -0
  5. package/big-world/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  6. package/big-world/assets/models/players/.optimized/player/player.glb +0 -0
  7. package/big-world/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  8. package/big-world/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  9. package/big-world/assets/models/players/player.gltf +1 -0
  10. package/big-world/assets/skyboxes/partly-cloudy/+x.png +0 -0
  11. package/big-world/assets/skyboxes/partly-cloudy/+y.png +0 -0
  12. package/big-world/assets/skyboxes/partly-cloudy/+z.png +0 -0
  13. package/big-world/assets/skyboxes/partly-cloudy/-x.png +0 -0
  14. package/big-world/assets/skyboxes/partly-cloudy/-y.png +0 -0
  15. package/big-world/assets/skyboxes/partly-cloudy/-z.png +0 -0
  16. package/block-entity/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  17. package/block-entity/assets/blocks/.atlas/atlas.json +3377 -0
  18. package/block-entity/assets/blocks/.atlas/atlas.ktx2 +0 -0
  19. package/block-entity/assets/blocks/.atlas/atlas.png +0 -0
  20. package/block-entity/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  21. package/block-entity/assets/models/players/.optimized/player/player.glb +0 -0
  22. package/block-entity/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  23. package/block-entity/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  24. package/block-entity/assets/models/players/player.gltf +1 -0
  25. package/block-entity/assets/skyboxes/partly-cloudy/+x.png +0 -0
  26. package/block-entity/assets/skyboxes/partly-cloudy/+y.png +0 -0
  27. package/block-entity/assets/skyboxes/partly-cloudy/+z.png +0 -0
  28. package/block-entity/assets/skyboxes/partly-cloudy/-x.png +0 -0
  29. package/block-entity/assets/skyboxes/partly-cloudy/-y.png +0 -0
  30. package/block-entity/assets/skyboxes/partly-cloudy/-z.png +0 -0
  31. package/child-entity/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  32. package/child-entity/assets/blocks/.atlas/atlas.json +3377 -0
  33. package/child-entity/assets/blocks/.atlas/atlas.ktx2 +0 -0
  34. package/child-entity/assets/blocks/.atlas/atlas.png +0 -0
  35. package/child-entity/assets/models/items/.optimized/sword/sword-named-nodes.glb +0 -0
  36. package/child-entity/assets/models/items/.optimized/sword/sword.glb +0 -0
  37. package/child-entity/assets/models/items/.optimized/sword/sword.gltf.data.json +1 -0
  38. package/child-entity/assets/models/items/.optimized/sword/sword.gltf.md5 +1 -0
  39. package/child-entity/assets/models/items/sword.gltf +1 -0
  40. package/child-entity/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  41. package/child-entity/assets/models/players/.optimized/player/player.glb +0 -0
  42. package/child-entity/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  43. package/child-entity/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  44. package/child-entity/assets/models/players/player.gltf +1 -0
  45. package/child-entity/assets/skyboxes/partly-cloudy/+x.png +0 -0
  46. package/child-entity/assets/skyboxes/partly-cloudy/+y.png +0 -0
  47. package/child-entity/assets/skyboxes/partly-cloudy/+z.png +0 -0
  48. package/child-entity/assets/skyboxes/partly-cloudy/-x.png +0 -0
  49. package/child-entity/assets/skyboxes/partly-cloudy/-y.png +0 -0
  50. package/child-entity/assets/skyboxes/partly-cloudy/-z.png +0 -0
  51. package/child-entity/index.ts +4 -2
  52. package/custom-ui/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  53. package/custom-ui/assets/blocks/.atlas/atlas.json +3377 -0
  54. package/custom-ui/assets/blocks/.atlas/atlas.ktx2 +0 -0
  55. package/custom-ui/assets/blocks/.atlas/atlas.png +0 -0
  56. package/custom-ui/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  57. package/custom-ui/assets/models/players/.optimized/player/player.glb +0 -0
  58. package/custom-ui/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  59. package/custom-ui/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  60. package/custom-ui/assets/models/players/player.gltf +1 -0
  61. package/custom-ui/assets/skyboxes/partly-cloudy/+x.png +0 -0
  62. package/custom-ui/assets/skyboxes/partly-cloudy/+y.png +0 -0
  63. package/custom-ui/assets/skyboxes/partly-cloudy/+z.png +0 -0
  64. package/custom-ui/assets/skyboxes/partly-cloudy/-x.png +0 -0
  65. package/custom-ui/assets/skyboxes/partly-cloudy/-y.png +0 -0
  66. package/custom-ui/assets/skyboxes/partly-cloudy/-z.png +0 -0
  67. package/entity-animations/assets/blocks/.atlas/atlas.json +3377 -0
  68. package/entity-animations/assets/blocks/.atlas/atlas.ktx2 +0 -0
  69. package/entity-animations/assets/blocks/.atlas/atlas.png +0 -0
  70. package/entity-animations/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  71. package/entity-animations/assets/models/players/.optimized/player/player.glb +0 -0
  72. package/entity-animations/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  73. package/entity-animations/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  74. package/entity-animations/assets/models/players/player.gltf +1 -0
  75. package/entity-animations/assets/skyboxes/partly-cloudy/+x.png +0 -0
  76. package/entity-animations/assets/skyboxes/partly-cloudy/+y.png +0 -0
  77. package/entity-animations/assets/skyboxes/partly-cloudy/+z.png +0 -0
  78. package/entity-animations/assets/skyboxes/partly-cloudy/-x.png +0 -0
  79. package/entity-animations/assets/skyboxes/partly-cloudy/-y.png +0 -0
  80. package/entity-animations/assets/skyboxes/partly-cloudy/-z.png +0 -0
  81. package/entity-animations/index.ts +0 -1
  82. package/entity-controller/MyEntityController.ts +495 -148
  83. package/entity-controller/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  84. package/entity-controller/assets/blocks/.atlas/atlas.json +3377 -0
  85. package/entity-controller/assets/blocks/.atlas/atlas.ktx2 +0 -0
  86. package/entity-controller/assets/blocks/.atlas/atlas.png +0 -0
  87. package/entity-controller/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  88. package/entity-controller/assets/models/players/.optimized/player/player.glb +0 -0
  89. package/entity-controller/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  90. package/entity-controller/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  91. package/entity-controller/assets/models/players/player.gltf +1 -0
  92. package/entity-controller/assets/skyboxes/partly-cloudy/+x.png +0 -0
  93. package/entity-controller/assets/skyboxes/partly-cloudy/+y.png +0 -0
  94. package/entity-controller/assets/skyboxes/partly-cloudy/+z.png +0 -0
  95. package/entity-controller/assets/skyboxes/partly-cloudy/-x.png +0 -0
  96. package/entity-controller/assets/skyboxes/partly-cloudy/-y.png +0 -0
  97. package/entity-controller/assets/skyboxes/partly-cloudy/-z.png +0 -0
  98. package/entity-spawn/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  99. package/entity-spawn/assets/blocks/.atlas/atlas.json +3377 -0
  100. package/entity-spawn/assets/blocks/.atlas/atlas.ktx2 +0 -0
  101. package/entity-spawn/assets/blocks/.atlas/atlas.png +0 -0
  102. package/entity-spawn/assets/models/npcs/.optimized/spider/spider-named-nodes.glb +0 -0
  103. package/entity-spawn/assets/models/npcs/.optimized/spider/spider.glb +0 -0
  104. package/entity-spawn/assets/models/npcs/.optimized/spider/spider.gltf.data.json +1 -0
  105. package/entity-spawn/assets/models/npcs/.optimized/spider/spider.gltf.md5 +1 -0
  106. package/entity-spawn/assets/models/npcs/spider.gltf +1 -0
  107. package/entity-spawn/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  108. package/entity-spawn/assets/models/players/.optimized/player/player.glb +0 -0
  109. package/entity-spawn/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  110. package/entity-spawn/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  111. package/entity-spawn/assets/models/players/player.gltf +1 -0
  112. package/entity-spawn/assets/skyboxes/partly-cloudy/+x.png +0 -0
  113. package/entity-spawn/assets/skyboxes/partly-cloudy/+y.png +0 -0
  114. package/entity-spawn/assets/skyboxes/partly-cloudy/+z.png +0 -0
  115. package/entity-spawn/assets/skyboxes/partly-cloudy/-x.png +0 -0
  116. package/entity-spawn/assets/skyboxes/partly-cloudy/-y.png +0 -0
  117. package/entity-spawn/assets/skyboxes/partly-cloudy/-z.png +0 -0
  118. package/frontiers-rpg-game/assets/audio/music/cave-theme-looping.mp3 +0 -0
  119. package/frontiers-rpg-game/assets/audio/music/hytopia-main-theme.mp3 +0 -0
  120. package/frontiers-rpg-game/assets/audio/music/jungle-theme-looping.mp3 +0 -0
  121. package/frontiers-rpg-game/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  122. package/frontiers-rpg-game/assets/models/items/.optimized/snowball/snowball-named-nodes.glb +0 -0
  123. package/frontiers-rpg-game/assets/models/items/.optimized/snowball/snowball.glb +0 -0
  124. package/frontiers-rpg-game/assets/models/items/.optimized/snowball/snowball.gltf.data.json +1 -0
  125. package/frontiers-rpg-game/assets/models/items/.optimized/snowball/snowball.gltf.md5 +1 -0
  126. package/frontiers-rpg-game/assets/models/items/.optimized/sword-wooden/sword-wooden-named-nodes.glb +0 -0
  127. package/frontiers-rpg-game/assets/models/items/.optimized/sword-wooden/sword-wooden.glb +0 -0
  128. package/frontiers-rpg-game/assets/models/items/.optimized/sword-wooden/sword-wooden.gltf.data.json +1 -0
  129. package/frontiers-rpg-game/assets/models/items/.optimized/sword-wooden/sword-wooden.gltf.md5 +1 -0
  130. package/frontiers-rpg-game/assets/models/items/snowball.gltf +1 -0
  131. package/frontiers-rpg-game/assets/models/items/sword-wooden.gltf +1 -0
  132. package/frontiers-rpg-game/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  133. package/frontiers-rpg-game/assets/models/players/.optimized/player/player.glb +0 -0
  134. package/frontiers-rpg-game/assets/models/players/.optimized/player/player.gltf.data.json +1 -1
  135. package/frontiers-rpg-game/assets/models/players/.optimized/player/player.gltf.md5 +1 -1
  136. package/frontiers-rpg-game/assets/models/players/player.gltf +1 -1
  137. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/+x.png +0 -0
  138. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/+y.png +0 -0
  139. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/+z.png +0 -0
  140. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/-x.png +0 -0
  141. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/-y.png +0 -0
  142. package/frontiers-rpg-game/assets/skyboxes/partly-cloudy/-z.png +0 -0
  143. package/frontiers-rpg-game/dev/persistence/player-player-1.json +1 -1
  144. package/frontiers-rpg-game/dev/persistence/player-player-12.json +1 -0
  145. package/frontiers-rpg-game/dev/persistence/player-player-13.json +1 -0
  146. package/frontiers-rpg-game/dev/persistence/player-player-15.json +1 -0
  147. package/frontiers-rpg-game/dev/persistence/player-player-16.json +1 -0
  148. package/frontiers-rpg-game/dev/persistence/player-player-4.json +1 -0
  149. package/frontiers-rpg-game/dev/persistence/player-player-5.json +1 -0
  150. package/frontiers-rpg-game/dev/persistence/player-player-8.json +1 -0
  151. package/hole-in-wall-game/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  152. package/hole-in-wall-game/assets/blocks/.atlas/atlas.json +3377 -0
  153. package/hole-in-wall-game/assets/blocks/.atlas/atlas.ktx2 +0 -0
  154. package/hole-in-wall-game/assets/blocks/.atlas/atlas.png +0 -0
  155. package/hole-in-wall-game/assets/icons/jump.png +0 -0
  156. package/hole-in-wall-game/assets/models/npcs/.optimized/mindflayer/mindflayer-named-nodes.glb +0 -0
  157. package/hole-in-wall-game/assets/models/npcs/.optimized/mindflayer/mindflayer.glb +0 -0
  158. package/hole-in-wall-game/assets/models/npcs/.optimized/mindflayer/mindflayer.gltf.data.json +1 -0
  159. package/hole-in-wall-game/assets/models/npcs/.optimized/mindflayer/mindflayer.gltf.md5 +1 -0
  160. package/hole-in-wall-game/assets/models/npcs/mindflayer.gltf +1 -0
  161. package/hole-in-wall-game/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  162. package/hole-in-wall-game/assets/models/players/.optimized/player/player.glb +0 -0
  163. package/hole-in-wall-game/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  164. package/hole-in-wall-game/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  165. package/hole-in-wall-game/assets/models/players/player.gltf +1 -0
  166. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/+x.png +0 -0
  167. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/+y.png +0 -0
  168. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/+z.png +0 -0
  169. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/-x.png +0 -0
  170. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/-y.png +0 -0
  171. package/hole-in-wall-game/assets/skyboxes/partly-cloudy/-z.png +0 -0
  172. package/huntcraft/assets/blocks/.atlas/atlas.json +2155 -0
  173. package/huntcraft/assets/blocks/.atlas/atlas.ktx2 +0 -0
  174. package/huntcraft/assets/blocks/.atlas/atlas.png +0 -0
  175. package/hygrounds/assets/audio/sfx/dig/dig-stone.mp3 +0 -0
  176. package/hygrounds/assets/audio/sfx/player/player-swing-woosh.mp3 +0 -0
  177. package/hygrounds/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  178. package/hygrounds/assets/skyboxes/partly-cloudy/+x.png +0 -0
  179. package/hygrounds/assets/skyboxes/partly-cloudy/+y.png +0 -0
  180. package/hygrounds/assets/skyboxes/partly-cloudy/+z.png +0 -0
  181. package/hygrounds/assets/skyboxes/partly-cloudy/-x.png +0 -0
  182. package/hygrounds/assets/skyboxes/partly-cloudy/-y.png +0 -0
  183. package/hygrounds/assets/skyboxes/partly-cloudy/-z.png +0 -0
  184. package/lighting/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  185. package/lighting/assets/blocks/.atlas/atlas.json +3377 -0
  186. package/lighting/assets/blocks/.atlas/atlas.ktx2 +0 -0
  187. package/lighting/assets/blocks/.atlas/atlas.png +0 -0
  188. package/lighting/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  189. package/lighting/assets/models/players/.optimized/player/player.glb +0 -0
  190. package/lighting/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  191. package/lighting/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  192. package/lighting/assets/models/players/player.gltf +1 -0
  193. package/lighting/assets/skyboxes/partly-cloudy/+x.png +0 -0
  194. package/lighting/assets/skyboxes/partly-cloudy/+y.png +0 -0
  195. package/lighting/assets/skyboxes/partly-cloudy/+z.png +0 -0
  196. package/lighting/assets/skyboxes/partly-cloudy/-x.png +0 -0
  197. package/lighting/assets/skyboxes/partly-cloudy/-y.png +0 -0
  198. package/lighting/assets/skyboxes/partly-cloudy/-z.png +0 -0
  199. package/mobile-controls/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  200. package/mobile-controls/assets/blocks/.atlas/atlas.json +3377 -0
  201. package/mobile-controls/assets/blocks/.atlas/atlas.ktx2 +0 -0
  202. package/mobile-controls/assets/blocks/.atlas/atlas.png +0 -0
  203. package/mobile-controls/assets/icons/jump.png +0 -0
  204. package/mobile-controls/assets/icons/target.png +0 -0
  205. package/mobile-controls/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  206. package/mobile-controls/assets/models/players/.optimized/player/player.glb +0 -0
  207. package/mobile-controls/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  208. package/mobile-controls/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  209. package/mobile-controls/assets/models/players/player.gltf +1 -0
  210. package/mobile-controls/assets/skyboxes/partly-cloudy/+x.png +0 -0
  211. package/mobile-controls/assets/skyboxes/partly-cloudy/+y.png +0 -0
  212. package/mobile-controls/assets/skyboxes/partly-cloudy/+z.png +0 -0
  213. package/mobile-controls/assets/skyboxes/partly-cloudy/-x.png +0 -0
  214. package/mobile-controls/assets/skyboxes/partly-cloudy/-y.png +0 -0
  215. package/mobile-controls/assets/skyboxes/partly-cloudy/-z.png +0 -0
  216. package/package.json +1 -1
  217. package/particles/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  218. package/particles/assets/blocks/.atlas/atlas.json +3377 -0
  219. package/particles/assets/blocks/.atlas/atlas.ktx2 +0 -0
  220. package/particles/assets/blocks/.atlas/atlas.png +0 -0
  221. package/particles/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  222. package/particles/assets/models/players/.optimized/player/player.glb +0 -0
  223. package/particles/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  224. package/particles/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  225. package/particles/assets/models/players/player.gltf +1 -0
  226. package/particles/assets/skyboxes/partly-cloudy/+x.png +0 -0
  227. package/particles/assets/skyboxes/partly-cloudy/+y.png +0 -0
  228. package/particles/assets/skyboxes/partly-cloudy/+z.png +0 -0
  229. package/particles/assets/skyboxes/partly-cloudy/-x.png +0 -0
  230. package/particles/assets/skyboxes/partly-cloudy/-y.png +0 -0
  231. package/particles/assets/skyboxes/partly-cloudy/-z.png +0 -0
  232. package/pathfinding/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  233. package/pathfinding/assets/blocks/.atlas/atlas.json +3377 -0
  234. package/pathfinding/assets/blocks/.atlas/atlas.ktx2 +0 -0
  235. package/pathfinding/assets/blocks/.atlas/atlas.png +0 -0
  236. package/pathfinding/assets/models/items/.optimized/cookie/cookie-named-nodes.glb +0 -0
  237. package/pathfinding/assets/models/items/.optimized/cookie/cookie.glb +0 -0
  238. package/pathfinding/assets/models/items/.optimized/cookie/cookie.gltf.data.json +1 -0
  239. package/pathfinding/assets/models/items/.optimized/cookie/cookie.gltf.md5 +1 -0
  240. package/pathfinding/assets/models/items/cookie.gltf +1 -0
  241. package/pathfinding/assets/models/npcs/.optimized/zombie/zombie-named-nodes.glb +0 -0
  242. package/pathfinding/assets/models/npcs/.optimized/zombie/zombie.glb +0 -0
  243. package/pathfinding/assets/models/npcs/.optimized/zombie/zombie.gltf.data.json +1 -0
  244. package/pathfinding/assets/models/npcs/.optimized/zombie/zombie.gltf.md5 +1 -0
  245. package/pathfinding/assets/models/npcs/zombie.gltf +1 -0
  246. package/pathfinding/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  247. package/pathfinding/assets/models/players/.optimized/player/player.glb +0 -0
  248. package/pathfinding/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  249. package/pathfinding/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  250. package/pathfinding/assets/models/players/player.gltf +1 -0
  251. package/pathfinding/assets/skyboxes/partly-cloudy/+x.png +0 -0
  252. package/pathfinding/assets/skyboxes/partly-cloudy/+y.png +0 -0
  253. package/pathfinding/assets/skyboxes/partly-cloudy/+z.png +0 -0
  254. package/pathfinding/assets/skyboxes/partly-cloudy/-x.png +0 -0
  255. package/pathfinding/assets/skyboxes/partly-cloudy/-y.png +0 -0
  256. package/pathfinding/assets/skyboxes/partly-cloudy/-z.png +0 -0
  257. package/payload-game/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  258. package/payload-game/assets/blocks/.atlas/atlas.json +3377 -0
  259. package/payload-game/assets/blocks/.atlas/atlas.ktx2 +0 -0
  260. package/payload-game/assets/blocks/.atlas/atlas.png +0 -0
  261. package/payload-game/assets/models/npcs/.optimized/spider/spider-named-nodes.glb +0 -0
  262. package/payload-game/assets/models/npcs/.optimized/spider/spider.glb +0 -0
  263. package/payload-game/assets/models/npcs/.optimized/spider/spider.gltf.data.json +1 -0
  264. package/payload-game/assets/models/npcs/.optimized/spider/spider.gltf.md5 +1 -0
  265. package/payload-game/assets/models/npcs/spider.gltf +1 -0
  266. package/payload-game/assets/skyboxes/partly-cloudy/+x.png +0 -0
  267. package/payload-game/assets/skyboxes/partly-cloudy/+y.png +0 -0
  268. package/payload-game/assets/skyboxes/partly-cloudy/+z.png +0 -0
  269. package/payload-game/assets/skyboxes/partly-cloudy/-x.png +0 -0
  270. package/payload-game/assets/skyboxes/partly-cloudy/-y.png +0 -0
  271. package/payload-game/assets/skyboxes/partly-cloudy/-z.png +0 -0
  272. package/player-persistence/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  273. package/player-persistence/assets/blocks/.atlas/atlas.json +3377 -0
  274. package/player-persistence/assets/blocks/.atlas/atlas.ktx2 +0 -0
  275. package/player-persistence/assets/blocks/.atlas/atlas.png +0 -0
  276. package/player-persistence/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  277. package/player-persistence/assets/models/players/.optimized/player/player.glb +0 -0
  278. package/player-persistence/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  279. package/player-persistence/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  280. package/player-persistence/assets/models/players/player.gltf +1 -0
  281. package/player-persistence/assets/skyboxes/partly-cloudy/+x.png +0 -0
  282. package/player-persistence/assets/skyboxes/partly-cloudy/+y.png +0 -0
  283. package/player-persistence/assets/skyboxes/partly-cloudy/+z.png +0 -0
  284. package/player-persistence/assets/skyboxes/partly-cloudy/-x.png +0 -0
  285. package/player-persistence/assets/skyboxes/partly-cloudy/-y.png +0 -0
  286. package/player-persistence/assets/skyboxes/partly-cloudy/-z.png +0 -0
  287. package/scheduled-notifications/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  288. package/scheduled-notifications/assets/blocks/.atlas/atlas.json +3377 -0
  289. package/scheduled-notifications/assets/blocks/.atlas/atlas.ktx2 +0 -0
  290. package/scheduled-notifications/assets/blocks/.atlas/atlas.png +0 -0
  291. package/scheduled-notifications/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  292. package/scheduled-notifications/assets/models/players/.optimized/player/player.glb +0 -0
  293. package/scheduled-notifications/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  294. package/scheduled-notifications/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  295. package/scheduled-notifications/assets/models/players/player.gltf +1 -0
  296. package/scheduled-notifications/assets/skyboxes/partly-cloudy/+x.png +0 -0
  297. package/scheduled-notifications/assets/skyboxes/partly-cloudy/+y.png +0 -0
  298. package/scheduled-notifications/assets/skyboxes/partly-cloudy/+z.png +0 -0
  299. package/scheduled-notifications/assets/skyboxes/partly-cloudy/-x.png +0 -0
  300. package/scheduled-notifications/assets/skyboxes/partly-cloudy/-y.png +0 -0
  301. package/scheduled-notifications/assets/skyboxes/partly-cloudy/-z.png +0 -0
  302. package/wall-dodge-game/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  303. package/wall-dodge-game/assets/blocks/.atlas/atlas.json +3377 -0
  304. package/wall-dodge-game/assets/blocks/.atlas/atlas.ktx2 +0 -0
  305. package/wall-dodge-game/assets/blocks/.atlas/atlas.png +0 -0
  306. package/wall-dodge-game/assets/icons/jump.png +0 -0
  307. package/wall-dodge-game/assets/models/npcs/.optimized/mindflayer/mindflayer-named-nodes.glb +0 -0
  308. package/wall-dodge-game/assets/models/npcs/.optimized/mindflayer/mindflayer.glb +0 -0
  309. package/wall-dodge-game/assets/models/npcs/.optimized/mindflayer/mindflayer.gltf.data.json +1 -0
  310. package/wall-dodge-game/assets/models/npcs/.optimized/mindflayer/mindflayer.gltf.md5 +1 -0
  311. package/wall-dodge-game/assets/models/npcs/mindflayer.gltf +1 -0
  312. package/wall-dodge-game/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  313. package/wall-dodge-game/assets/models/players/.optimized/player/player.glb +0 -0
  314. package/wall-dodge-game/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  315. package/wall-dodge-game/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  316. package/wall-dodge-game/assets/models/players/player.gltf +1 -0
  317. package/wall-dodge-game/assets/skyboxes/partly-cloudy/+x.png +0 -0
  318. package/wall-dodge-game/assets/skyboxes/partly-cloudy/+y.png +0 -0
  319. package/wall-dodge-game/assets/skyboxes/partly-cloudy/+z.png +0 -0
  320. package/wall-dodge-game/assets/skyboxes/partly-cloudy/-x.png +0 -0
  321. package/wall-dodge-game/assets/skyboxes/partly-cloudy/-y.png +0 -0
  322. package/wall-dodge-game/assets/skyboxes/partly-cloudy/-z.png +0 -0
  323. package/world-switching/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
  324. package/world-switching/assets/blocks/.atlas/atlas.json +3377 -0
  325. package/world-switching/assets/blocks/.atlas/atlas.ktx2 +0 -0
  326. package/world-switching/assets/blocks/.atlas/atlas.png +0 -0
  327. package/world-switching/assets/models/players/.optimized/player/player-named-nodes.glb +0 -0
  328. package/world-switching/assets/models/players/.optimized/player/player.glb +0 -0
  329. package/world-switching/assets/models/players/.optimized/player/player.gltf.data.json +1 -0
  330. package/world-switching/assets/models/players/.optimized/player/player.gltf.md5 +1 -0
  331. package/world-switching/assets/models/players/player.gltf +1 -0
  332. package/world-switching/assets/models/projectiles/.optimized/energy-orb-projectile/energy-orb-projectile-named-nodes.glb +0 -0
  333. package/world-switching/assets/models/projectiles/.optimized/energy-orb-projectile/energy-orb-projectile.glb +0 -0
  334. package/world-switching/assets/models/projectiles/.optimized/energy-orb-projectile/energy-orb-projectile.gltf.data.json +1 -0
  335. package/world-switching/assets/models/projectiles/.optimized/energy-orb-projectile/energy-orb-projectile.gltf.md5 +1 -0
  336. package/world-switching/assets/models/projectiles/energy-orb-projectile.gltf +1 -0
  337. package/world-switching/assets/skyboxes/partly-cloudy/+x.png +0 -0
  338. package/world-switching/assets/skyboxes/partly-cloudy/+y.png +0 -0
  339. package/world-switching/assets/skyboxes/partly-cloudy/+z.png +0 -0
  340. package/world-switching/assets/skyboxes/partly-cloudy/-x.png +0 -0
  341. package/world-switching/assets/skyboxes/partly-cloudy/-y.png +0 -0
  342. package/world-switching/assets/skyboxes/partly-cloudy/-z.png +0 -0
  343. package/zombies-fps/assets/audio/sfx/step/stone/stone-step-04.mp3 +0 -0
@@ -5,6 +5,8 @@ import {
5
5
  CoefficientCombineRule,
6
6
  CollisionGroup,
7
7
  Entity,
8
+ EntityEvent,
9
+ ErrorHandler,
8
10
  PlayerEntity,
9
11
  BlockType,
10
12
  } from 'hytopia';
@@ -12,99 +14,305 @@ import {
12
14
  import type {
13
15
  PlayerInput,
14
16
  PlayerCameraOrientation,
17
+ Vector3Like,
15
18
  } from 'hytopia';
16
19
 
17
20
  /** Options for creating a MyEntityController instance. @public */
18
21
  export interface MyEntityControllerOptions {
19
- /** The upward velocity applied to the entity when it jumps. */
20
- jumpVelocity?: number;
21
-
22
- /** The normalized horizontal velocity applied to the entity when it runs. */
23
- runVelocity?: number;
22
+ /** Whether to apply directional rotations to the entity while moving, defaults to true. */
23
+ applyDirectionalMovementRotations?: boolean;
24
24
 
25
- /** The normalized horizontal velocity applied to the entity when it walks. */
26
- walkVelocity?: number;
25
+ /** Whether to automatically cancel left click input after first processed tick, defaults to true. */
26
+ autoCancelMouseLeftClick?: boolean;
27
27
 
28
28
  /** A function allowing custom logic to determine if the entity can jump. */
29
29
  canJump?: () => boolean;
30
30
 
31
+ /** A function allowing custom logic to determine if the entity can run. */
32
+ canRun?: () => boolean;
33
+
34
+ /** A function allowing custom logic to determine if the entity can swim. */
35
+ canSwim?: () => boolean;
36
+
31
37
  /** A function allowing custom logic to determine if the entity can walk. */
32
38
  canWalk?: () => boolean;
33
39
 
34
- /** A function allowing custom logic to determine if the entity can run. */
35
- canRun?: () => boolean;
36
- }
40
+ /** Whether to face forward when the entity stops moving. */
41
+ faceForwardOnStop?: boolean;
42
+
43
+ /** Overrides the animation(s) that will play when the entity is idle. */
44
+ idleLoopedAnimations?: string[];
45
+
46
+ /** Overrides the animation(s) that will play when the entity interacts (left click) */
47
+ interactOneshotAnimations?: string[];
48
+
49
+ /** Overrides the animation(s) that will play when the entity is jumping. */
50
+ jumpOneshotAnimations?: string[];
51
+
52
+ /** Overrides the animation(s) that will play when the entity lands with a high velocity. */
53
+ jumpLandHeavyOneshotAnimations?: string[];
54
+
55
+ /** Overrides the animation(s) that will play when the entity lands after jumping or being airborne. */
56
+ jumpLandLightOneshotAnimations?: string[];
37
57
 
38
- /**
39
- * A custom entity controller implementation.
40
- *
41
- * @remarks
42
- * This class extends {@link BaseEntityController}
43
- * and implements the default movement logic for a
44
- * entity.
45
- *
46
- * @public
47
- */
48
- export default class MyEntityController extends BaseEntityController {
49
58
  /** The upward velocity applied to the entity when it jumps. */
50
- public jumpVelocity: number = 10;
59
+ jumpVelocity?: number;
51
60
 
52
61
  /** The normalized horizontal velocity applied to the entity when it runs. */
53
- public runVelocity: number = 8;
62
+ runVelocity?: number;
63
+
64
+ /** Overrides the animation(s) that will play when the entity is running. */
65
+ runLoopedAnimations?: string[];
66
+
67
+ /** Whether the entity sticks to platforms, defaults to true. */
68
+ sticksToPlatforms?: boolean;
69
+
70
+ /** The normalized horizontal velocity applied to the entity when it swims fast (equivalent to running). */
71
+ swimFastVelocity?: number;
72
+
73
+ /** The gravity modifier applied to the entity when swimming. */
74
+ swimGravity?: number;
75
+
76
+ /** The maximum downward velocity that the entity can reach when affected by gravity while swimming. */
77
+ swimMaxGravityVelocity?: number;
78
+
79
+ /** The looped animation(s) that will play when the entity is swimming in any direction. */
80
+ swimLoopedAnimations?: string[];
81
+
82
+ /** The looped animation(s) that will play when the entity is not moving while swimming. */
83
+ swimIdleLoopedAnimations?: string[];
84
+
85
+ /** The normalized horizontal velocity applied to the entity when it swims slowly (equivalent to walking). */
86
+ swimSlowVelocity?: number;
87
+
88
+ /** The upward velocity applied to the entity when swimming. */
89
+ swimUpwardVelocity?: number;
90
+
91
+ /** Overrides the animation(s) that will play when the entity is walking. */
92
+ walkLoopedAnimations?: string[];
54
93
 
55
94
  /** The normalized horizontal velocity applied to the entity when it walks. */
56
- public walkVelocity: number = 4;
95
+ walkVelocity?: number;
96
+ }
97
+
98
+ export default class MyEntityController extends BaseEntityController {
99
+ // These constants are based on a model scale of 1, and will scale relative to the entity.modelScale
100
+ private static readonly BASE_ENTITY_HEIGHT = 1.5;
101
+ private static readonly GROUND_SENSOR_HEIGHT_SCALE = 0.125;
102
+ private static readonly GROUND_SENSOR_RADIUS_SCALE = 0.23;
103
+ private static readonly JUMP_LAND_HEAVY_VELOCITY_THRESHOLD = -12;
104
+ private static readonly WALL_COLLIDER_HEIGHT_SCALE = 0.33;
105
+ private static readonly WALL_COLLIDER_RADIUS_SCALE = 0.40;
106
+
107
+ // Movement rotation lookup (static to avoid per-tick allocation)
108
+ private static readonly MOVEMENT_ROTATIONS: Record<string, number> = {
109
+ 'wa': Math.PI / 4,
110
+ 'wd': -Math.PI / 4,
111
+ 'sa': Math.PI - Math.PI / 4,
112
+ 'sd': Math.PI + Math.PI / 4,
113
+ 's': Math.PI,
114
+ 'asd': Math.PI, // Special case for a+s+d without w
115
+ 'a': Math.PI / 2,
116
+ 'd': -Math.PI / 2,
117
+ };
118
+
119
+ // Physics constants
120
+ private static readonly EXTERNAL_IMPULSE_DECAY_RATE = 0.253;
121
+ private static readonly SWIM_UPWARD_COOLDOWN_MS = 600;
122
+ private static readonly SWIMMING_DRAG_FACTOR = 0.05;
123
+ private static readonly WATER_ENTRY_SINKING_FACTOR = 0.8;
124
+ private static readonly WATER_ENTRY_SINKING_MS = 250;
125
+
126
+ /** Whether to apply directional rotations to the entity while moving, defaults to true. */
127
+ public applyDirectionalMovementRotations: boolean = true;
128
+
129
+ /** Whether to automatically cancel left click input after first processed tick, defaults to true. */
130
+ public autoCancelMouseLeftClick: boolean = true;
57
131
 
58
132
  /**
59
- * A function allowing custom logic to determine if the entity can walk.
60
- * @param myEntityController - The entity controller instance.
61
- * @returns Whether the entity of the entity controller can walk.
133
+ * A function allowing custom logic to determine if the entity can jump.
134
+ * @param controller - The default player entity controller instance.
135
+ * @returns Whether the entity of the entity controller can jump.
62
136
  */
63
- public canWalk: (myEntityController: MyEntityController) => boolean = () => true;
137
+ public canJump: (controller: MyEntityController) => boolean = () => true;
64
138
 
65
139
  /**
66
140
  * A function allowing custom logic to determine if the entity can run.
67
- * @param myEntityController - The entity controller instance.
141
+ * @param controller - The default player entity controller instance.
68
142
  * @returns Whether the entity of the entity controller can run.
69
143
  */
70
- public canRun: (myEntityController: MyEntityController) => boolean = () => true;
144
+ public canRun: (controller: MyEntityController) => boolean = () => true;
71
145
 
72
146
  /**
73
- * A function allowing custom logic to determine if the entity can jump.
74
- * @param myEntityController - The entity controller instance.
75
- * @returns Whether the entity of the entity controller can jump.
147
+ * A function allowing custom logic to determine if the entity can swim.
148
+ * @param controller - The default player entity controller instance.
149
+ * @returns Whether the entity of the entity controller can swim.
150
+ */
151
+ public canSwim: (controller: MyEntityController) => boolean = () => true;
152
+
153
+ /**
154
+ * A function allowing custom logic to determine if the entity can walk.
155
+ * @param controller - The default player entity controller instance.
156
+ * @returns Whether the entity of the entity controller can walk.
76
157
  */
77
- public canJump: (myEntityController: MyEntityController) => boolean = () => true;
158
+ public canWalk: (controller: MyEntityController) => boolean = () => true;
159
+
160
+ /** Whether to face forward when the entity stops moving. */
161
+ public faceForwardOnStop: boolean = true;
162
+
163
+ /** The looped animation(s) that will play when the entity is idle. */
164
+ public idleLoopedAnimations: string[] = [ 'idle-upper', 'idle-lower' ];
165
+
166
+ /** The oneshot animation(s) that will play when the entity interacts (left click) */
167
+ public interactOneshotAnimations: string[] = [ 'simple-interact' ];
168
+
169
+ /** The oneshot animation(s) that will play when the entity lands with a high velocity. */
170
+ public jumpLandHeavyOneshotAnimations: string[] = [ 'jump-post-heavy' ];
171
+
172
+ /** The oneshot animation(s) that will play when the entity lands after jumping or being airborne. */
173
+ public jumpLandLightOneshotAnimations: string[] = [ 'jump-post-light' ];
174
+
175
+ /** The oneshot animation(s) that will play when the entity is jumping. */
176
+ public jumpOneshotAnimations: string[] = [ 'jump-loop' ];
177
+
178
+ /** The upward velocity applied to the entity when it jumps. */
179
+ public jumpVelocity: number = 10;
180
+
181
+ /** The looped animation(s) that will play when the entity is running. */
182
+ public runLoopedAnimations: string[] = [ 'run-upper', 'run-lower' ];
183
+
184
+ /** The normalized horizontal velocity applied to the entity when it runs. */
185
+ public runVelocity: number = 8;
186
+
187
+ /** Whether the entity sticks to platforms. */
188
+ public sticksToPlatforms: boolean = true;
189
+
190
+ /** The normalized horizontal velocity applied to the entity when it swims fast (equivalent to running). */
191
+ public swimFastVelocity: number = 5;
192
+
193
+ /** The gravity modifier applied to the entity when swimming. */
194
+ public swimGravity: number = 0;
195
+
196
+ /** The looped animation(s) that will play when the entity is not moving while swimming. */
197
+ public swimIdleLoopedAnimations: string[] = [ 'swim-idle' ];
198
+
199
+ /** The looped animation(s) that will play when the entity is swimming in any direction. */
200
+ public swimLoopedAnimations: string[] = [ 'swim-forward' ];
201
+
202
+ /** The maximum downward velocity that the entity can reach when affected by gravity while swimming. */
203
+ public swimMaxGravityVelocity: number = -1;
204
+
205
+ /** The normalized horizontal velocity applied to the entity when it swims slowly (equivalent to walking). */
206
+ public swimSlowVelocity: number = 3;
207
+
208
+ /** The upward velocity applied to the entity when swimming. */
209
+ public swimUpwardVelocity: number = 2;
210
+
211
+ /** The looped animation(s) that will play when the entity is walking. */
212
+ public walkLoopedAnimations: string[] = [ 'walk-upper', 'walk-lower' ];
213
+
214
+ /** The normalized horizontal velocity applied to the entity when it walks. */
215
+ public walkVelocity: number = 4;
78
216
 
79
217
  /** @internal */
80
- private _stepAudio: Audio | undefined;
218
+ private readonly _externalVelocity = { x: 0, y: 0, z: 0 };
219
+
220
+ /** @internal */
221
+ private _magnitudeYTracker: number = 0;
81
222
 
82
223
  /** @internal */
83
224
  private _groundContactCount: number = 0;
84
225
 
226
+ /** @internal */
227
+ private _internalApplyImpulse: (impulse: Vector3Like) => void = () => {};
228
+
229
+ /** @internal */
230
+ private _isActivelyMoving: boolean = false;
231
+
232
+ /** @internal */
233
+ private _isFullySubmerged: boolean = false;
234
+
235
+ /** @internal */
236
+ private _justSubmergedUntil: number = 0;
237
+
238
+ /** @internal */
239
+ private _liquidContactCount: number = 0;
240
+
85
241
  /** @internal */
86
242
  private _platform: Entity | undefined;
87
243
 
244
+ /** @internal - Reusable vector for impulse calculation to avoid per-tick allocation */
245
+ private readonly _reusableImpulse = { x: 0, y: 0, z: 0 };
246
+
247
+ /** @internal - Reusable vector for platform velocity fallback to avoid per-tick allocation */
248
+ private readonly _reusablePlatformVelocity = { x: 0, y: 0, z: 0 };
249
+
250
+ /** @internal - Reusable vector for target velocities to avoid per-tick allocation */
251
+ private readonly _reusableTargetVelocities = { x: 0, y: 0, z: 0 };
252
+
253
+ /** @internal - Reusable vector for velocity clamping to avoid per-tick allocation */
254
+ private readonly _reusableVelocityClamp = { x: 0, y: 0, z: 0 };
255
+
256
+ /** @internal */
257
+ private _stepAudio: Audio | undefined;
258
+
259
+ /** @internal */
260
+ private _swimUpwardCooldownAt: number = 0;
261
+
88
262
  /**
89
263
  * @param options - Options for the controller.
90
264
  */
91
265
  public constructor(options: MyEntityControllerOptions = {}) {
92
266
  super();
93
267
 
268
+ // Basic behavior options
269
+ this.applyDirectionalMovementRotations = options.applyDirectionalMovementRotations ?? this.applyDirectionalMovementRotations;
270
+ this.autoCancelMouseLeftClick = options.autoCancelMouseLeftClick ?? this.autoCancelMouseLeftClick;
271
+ this.faceForwardOnStop = options.faceForwardOnStop ?? this.faceForwardOnStop;
272
+ this.sticksToPlatforms = options.sticksToPlatforms ?? this.sticksToPlatforms;
273
+
274
+ // Capability functions
275
+ this.canJump = options.canJump ?? this.canJump;
276
+ this.canRun = options.canRun ?? this.canRun;
277
+ this.canSwim = options.canSwim ?? this.canSwim;
278
+ this.canWalk = options.canWalk ?? this.canWalk;
279
+
280
+ // Movement velocities
94
281
  this.jumpVelocity = options.jumpVelocity ?? this.jumpVelocity;
95
282
  this.runVelocity = options.runVelocity ?? this.runVelocity;
96
283
  this.walkVelocity = options.walkVelocity ?? this.walkVelocity;
97
- this.canWalk = options.canWalk ?? this.canWalk;
98
- this.canRun = options.canRun ?? this.canRun;
99
- this.canJump = options.canJump ?? this.canJump;
284
+ this.swimFastVelocity = options.swimFastVelocity ?? this.swimFastVelocity;
285
+ this.swimSlowVelocity = options.swimSlowVelocity ?? this.swimSlowVelocity;
286
+ this.swimUpwardVelocity = options.swimUpwardVelocity ?? this.swimUpwardVelocity;
287
+
288
+ // Swimming physics
289
+ this.swimGravity = options.swimGravity ?? this.swimGravity;
290
+ this.swimMaxGravityVelocity = options.swimMaxGravityVelocity ?? this.swimMaxGravityVelocity;
291
+
292
+ // Animation overrides
293
+ this.idleLoopedAnimations = options.idleLoopedAnimations ?? this.idleLoopedAnimations;
294
+ this.interactOneshotAnimations = options.interactOneshotAnimations ?? this.interactOneshotAnimations;
295
+ this.jumpOneshotAnimations = options.jumpOneshotAnimations ?? this.jumpOneshotAnimations;
296
+ this.jumpLandHeavyOneshotAnimations = options.jumpLandHeavyOneshotAnimations ?? this.jumpLandHeavyOneshotAnimations;
297
+ this.jumpLandLightOneshotAnimations = options.jumpLandLightOneshotAnimations ?? this.jumpLandLightOneshotAnimations;
298
+ this.runLoopedAnimations = options.runLoopedAnimations ?? this.runLoopedAnimations;
299
+ this.swimLoopedAnimations = options.swimLoopedAnimations ?? this.swimLoopedAnimations;
300
+ this.swimIdleLoopedAnimations = options.swimIdleLoopedAnimations ?? this.swimIdleLoopedAnimations;
301
+ this.walkLoopedAnimations = options.walkLoopedAnimations ?? this.walkLoopedAnimations;
100
302
  }
101
303
 
304
+ /** Whether the entity is moving from player inputs. */
305
+ public get isActivelyMoving(): boolean { return this._isActivelyMoving; }
306
+
102
307
  /** Whether the entity is grounded. */
103
308
  public get isGrounded(): boolean { return this._groundContactCount > 0; }
104
309
 
105
310
  /** Whether the entity is on a platform, a platform is any entity with a kinematic rigid body. */
106
311
  public get isOnPlatform(): boolean { return !!this._platform; }
107
312
 
313
+ /** Whether the entity is swimming, this is determined by if the entity is in a liquid block. */
314
+ public get isSwimming(): boolean { return this._liquidContactCount > 0; }
315
+
108
316
  /** The platform the entity is on, if any. */
109
317
  public get platform(): Entity | undefined { return this._platform; }
110
318
 
@@ -112,54 +320,111 @@ export default class MyEntityController extends BaseEntityController {
112
320
  * Called when the controller is attached to an entity.
113
321
  * @param entity - The entity to attach the controller to.
114
322
  */
115
- public attach(entity: Entity) {
323
+ public override attach(entity: Entity) {
324
+ super.attach(entity);
325
+
326
+ // Alter applyImpulse to handle external velocities within internal movement velocity conflicts.
327
+ this._internalApplyImpulse = entity.applyImpulse.bind(entity);
328
+ entity.applyImpulse = (impulse: Vector3Like) => {
329
+ // Convert impulses to velocity (impulse = mass * velocity)
330
+ const mass = entity.mass || 1;
331
+ this._externalVelocity.x += impulse.x / mass;
332
+ this._externalVelocity.y += impulse.y / mass;
333
+ this._externalVelocity.z += impulse.z / mass;
334
+ };
335
+
116
336
  this._stepAudio = new Audio({
117
337
  uri: 'audio/sfx/step/stone/stone-step-04.mp3',
118
338
  loop: true,
119
339
  volume: 0.1,
340
+ referenceDistance: 2,
341
+ cutoffDistance: 15,
120
342
  attachedToEntity: entity,
121
343
  });
122
344
 
345
+ entity.setCcdEnabled(true);
123
346
  entity.lockAllRotations(); // prevent physics from applying rotation to the entity, we can still explicitly set it.
124
- };
347
+
348
+ // Handle swimming when in contact with a liquid block
349
+ entity.on(EntityEvent.BLOCK_COLLISION, ({ blockType, started }) => {
350
+ if (!blockType.isLiquid || !this.canSwim(this)) {
351
+ return;
352
+ }
353
+
354
+ // Slow the linear velocity of the entity when
355
+ // first entering the liquid to feel more natural
356
+ if (this._liquidContactCount <= 0 && started) {
357
+ const currentLinearVelocity = entity.linearVelocity;
358
+ entity.setLinearVelocity({
359
+ x: currentLinearVelocity.x * this.swimGravity,
360
+ y: currentLinearVelocity.y * this.swimGravity,
361
+ z: currentLinearVelocity.z * this.swimGravity,
362
+ });
363
+ }
364
+
365
+ this._liquidContactCount += started ? 1 : -1;
366
+
367
+ if (this._liquidContactCount > 0) {
368
+ entity.setGravityScale(this.swimGravity);
369
+ entity.stopAllModelLoopedAnimations(this.swimLoopedAnimations);
370
+ this._swimUpwardCooldownAt = performance.now() + MyEntityController.SWIM_UPWARD_COOLDOWN_MS;
371
+ } else {
372
+ entity.setGravityScale(1);
373
+ entity.stopModelAnimations(this.swimLoopedAnimations);
374
+ }
375
+ });
376
+ }
125
377
 
126
378
  /**
127
379
  * Called when the controlled entity is spawned.
128
- * In MyEntityController, this function is used to create
380
+ * In DefaultPlayerEntityController, this function is used to create
129
381
  * the colliders for the entity for wall and ground detection.
130
382
  * @param entity - The entity that is spawned.
131
383
  */
132
- public spawn(entity: Entity) {
384
+ public spawn(entity: Entity): void {
133
385
  if (!entity.isSpawned) {
134
- throw new Error('MyEntityController.createColliders(): Entity is not spawned!');
386
+ return ErrorHandler.error('MyEntityController.spawn(): Entity is not spawned!');
135
387
  }
136
388
 
137
389
  // Ground sensor
138
390
  entity.createAndAddChildCollider({
139
391
  shape: ColliderShape.CYLINDER,
140
- radius: 0.23,
141
- halfHeight: 0.125,
392
+ radius: MyEntityController.GROUND_SENSOR_RADIUS_SCALE * (entity.height / MyEntityController.BASE_ENTITY_HEIGHT),
393
+ halfHeight: MyEntityController.GROUND_SENSOR_HEIGHT_SCALE * (entity.height / MyEntityController.BASE_ENTITY_HEIGHT),
142
394
  collisionGroups: {
143
395
  belongsTo: [ CollisionGroup.ENTITY_SENSOR ],
144
- collidesWith: [ CollisionGroup.BLOCK, CollisionGroup.ENTITY ],
396
+ collidesWith: [ CollisionGroup.BLOCK, CollisionGroup.ENTITY, CollisionGroup.ENVIRONMENT_ENTITY ],
145
397
  },
146
398
  isSensor: true,
147
- relativePosition: { x: 0, y: -0.75, z: 0 },
399
+ relativePosition: { x: 0, y: -entity.height / 2, z: 0 },
148
400
  tag: 'groundSensor',
149
401
  onCollision: (_other: BlockType | Entity, started: boolean) => {
402
+ if (!entity.isSpawned) { return; }
403
+
150
404
  // Ground contact
151
- this._groundContactCount += started ? 1 : -1;
405
+ if (!(_other instanceof BlockType) || !_other.isLiquid) {
406
+ // Landing detection: check before updating ground count
407
+ if (started && this._groundContactCount === 0 && entity.linearVelocity.y < -1) {
408
+ if (entity.linearVelocity.y < MyEntityController.JUMP_LAND_HEAVY_VELOCITY_THRESHOLD) {
409
+ entity.startModelOneshotAnimations(this.jumpLandHeavyOneshotAnimations);
410
+ } else {
411
+ entity.startModelOneshotAnimations(this.jumpLandLightOneshotAnimations);
412
+ }
413
+ }
414
+
415
+ this._groundContactCount += started ? 1 : -1;
416
+ }
152
417
 
153
- if (!this._groundContactCount) {
154
- entity.startModelOneshotAnimations([ 'jump_loop' ]);
418
+ if (!this._groundContactCount && !this.isSwimming) {
419
+ entity.startModelOneshotAnimations(this.jumpOneshotAnimations);
155
420
  } else {
156
- entity.stopModelAnimations([ 'jump_loop' ]);
421
+ entity.stopModelAnimations(this.jumpOneshotAnimations);
157
422
  }
158
423
 
159
424
  // Platform contact
160
- if (!(_other instanceof Entity) || !_other.isKinematic) return;
425
+ if (!(_other instanceof Entity)) return;
161
426
 
162
- if (started) {
427
+ if (started && this.sticksToPlatforms) {
163
428
  this._platform = _other;
164
429
  } else if (_other === this._platform && !started) {
165
430
  this._platform = undefined;
@@ -167,25 +432,26 @@ export default class MyEntityController extends BaseEntityController {
167
432
  },
168
433
  });
169
434
 
170
-
171
435
  // Wall collider
172
436
  entity.createAndAddChildCollider({
173
437
  shape: ColliderShape.CAPSULE,
174
- halfHeight: 0.30,
175
- radius: 0.37,
438
+ halfHeight: MyEntityController.WALL_COLLIDER_HEIGHT_SCALE * (entity.height / MyEntityController.BASE_ENTITY_HEIGHT),
439
+ radius: MyEntityController.WALL_COLLIDER_RADIUS_SCALE * (entity.height / MyEntityController.BASE_ENTITY_HEIGHT),
176
440
  collisionGroups: {
177
441
  belongsTo: [ CollisionGroup.ENTITY_SENSOR ],
178
- collidesWith: [ CollisionGroup.BLOCK ],
442
+ collidesWith: [ CollisionGroup.BLOCK, CollisionGroup.ENTITY, CollisionGroup.ENVIRONMENT_ENTITY ],
179
443
  },
180
444
  friction: 0,
181
445
  frictionCombineRule: CoefficientCombineRule.Min,
182
446
  tag: 'wallCollider',
183
447
  });
184
- };
448
+ }
185
449
 
186
450
  /**
187
451
  * Ticks the player movement for the entity controller,
188
- * overriding the default implementation.
452
+ * overriding the default implementation. If the entity to tick
453
+ * is a child entity, only the event will be emitted but the default
454
+ * movement logic will not be applied.
189
455
  *
190
456
  * @param entity - The entity to tick.
191
457
  * @param input - The current input state of the player.
@@ -196,128 +462,209 @@ export default class MyEntityController extends BaseEntityController {
196
462
  if (!entity.isSpawned || !entity.world) return;
197
463
 
198
464
  super.tickWithPlayerInput(entity, input, cameraOrientation, deltaTimeMs);
465
+ if (entity.parent) return;
199
466
 
200
- const { w, a, s, d, sp, sh, ml } = input;
467
+ // Input and state setup
468
+ const { w, a, s, d, c, sp, sh, ml, jd } = input;
201
469
  const { yaw } = cameraOrientation;
202
470
  const currentVelocity = entity.linearVelocity;
203
- const targetVelocities = { x: 0, y: 0, z: 0 };
204
- const isRunning = sh;
205
-
206
- // Temporary, animations
207
- if (this.isGrounded && (w || a || s || d)) {
208
- if (isRunning) {
209
- const runAnimations = [ 'run_upper', 'run_lower' ];
210
- entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => !runAnimations.includes(v)));
211
- entity.startModelLoopedAnimations(runAnimations);
212
- this._stepAudio?.setPlaybackRate(0.81);
213
- } else {
214
- const walkAnimations = [ 'walk_upper', 'walk_lower' ];
215
- entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => !walkAnimations.includes(v)));
216
- entity.startModelLoopedAnimations(walkAnimations);
217
- this._stepAudio?.setPlaybackRate(0.55);
218
- }
219
471
 
472
+ // Reset reusable target velocities
473
+ this._reusableTargetVelocities.x = 0;
474
+ this._reusableTargetVelocities.y = 0;
475
+ this._reusableTargetVelocities.z = 0;
476
+
477
+ const hasJoystickInput = typeof jd === 'number';
478
+ this._isActivelyMoving = hasJoystickInput || !!(w || a || s || d);
479
+ const isFastMovement = sh;
480
+ const hasConflictingInputs = !hasJoystickInput && ((a && d && !w && !s) || (w && s && !a && !d));
481
+ const canMove = (isFastMovement && this.canRun(this)) || (!isFastMovement && this.canWalk(this));
482
+
483
+ // Update swimming state and handle water entry sinking
484
+ if (this.isSwimming && !this._isFullySubmerged) {
485
+ this._isFullySubmerged = true;
486
+ this._justSubmergedUntil = performance.now() + MyEntityController.WATER_ENTRY_SINKING_MS;
487
+ } else if (!this.isSwimming) {
488
+ this._isFullySubmerged = false;
489
+ this._justSubmergedUntil = 0;
490
+ }
491
+
492
+ // Handle movement animations and audio
493
+ if (this.isGrounded && !this.isSwimming && this._isActivelyMoving && !hasConflictingInputs && canMove) {
494
+ // Ground movement animations
495
+ const animations = isFastMovement ? this.runLoopedAnimations : this.walkLoopedAnimations;
496
+ entity.stopAllModelLoopedAnimations(animations);
497
+ entity.startModelLoopedAnimations(animations);
498
+ this._stepAudio?.setPlaybackRate(isFastMovement ? 0.75 : 0.51);
220
499
  this._stepAudio?.play(entity.world, !this._stepAudio?.isPlaying);
500
+ } else if (this._isFullySubmerged && this.canSwim(this)) {
501
+ this._stepAudio?.pause();
502
+ if (this._isActivelyMoving) {
503
+ entity.stopAllModelLoopedAnimations(this.swimLoopedAnimations);
504
+ entity.startModelLoopedAnimations(this.swimLoopedAnimations);
505
+ } else {
506
+ entity.stopAllModelLoopedAnimations(this.swimIdleLoopedAnimations);
507
+ entity.startModelLoopedAnimations(this.swimIdleLoopedAnimations);
508
+ }
221
509
  } else {
510
+ // Idle animations
222
511
  this._stepAudio?.pause();
223
- const idleAnimations = [ 'idle_upper', 'idle_lower' ];
224
- entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => !idleAnimations.includes(v)));
225
- entity.startModelLoopedAnimations(idleAnimations);
512
+ entity.stopAllModelLoopedAnimations(this.idleLoopedAnimations);
513
+ entity.startModelLoopedAnimations(this.idleLoopedAnimations);
226
514
  }
227
515
 
228
- if (ml) {
229
- entity.startModelOneshotAnimations([ 'simple_interact' ]);
230
-
231
- // break a block
232
- const ray = entity.world.simulation.raycast(
233
- entity.position,
234
- entity.player.camera.facingDirection,
235
- 10,
236
- { filterExcludeRigidBody: entity.rawRigidBody },
237
- );
238
-
239
- if (ray?.hitBlock) {
240
- // Remove the block
241
- entity.world.chunkLattice.setBlock(ray.hitBlock.globalCoordinate, 0);
516
+ // Calculate movement rotation for character facing (avoid string concatenation)
517
+ let movementDiagonalRotation: number | undefined;
518
+ if (this.applyDirectionalMovementRotations && canMove) {
519
+ if (hasJoystickInput) {
520
+ // Joystick: face the exact joystick direction
521
+ movementDiagonalRotation = jd;
522
+ } else {
523
+ // WASD: use discrete directional rotations
524
+ if (w && a && !d && !s) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.wa;
525
+ else if (w && d && !a && !s) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.wd;
526
+ else if (s && a && !w && !d) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.sa;
527
+ else if (s && d && !w && !a) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.sd;
528
+ else if ((s && !w && !a && !d) || (a && s && d && !w)) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.s;
529
+ else if (a && !w && !s && !d) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.a;
530
+ else if (d && !w && !a && !s) movementDiagonalRotation = MyEntityController.MOVEMENT_ROTATIONS.d;
242
531
  }
243
-
244
- input.ml = false;
245
532
  }
246
533
 
247
- // Calculate target horizontal velocities (run/walk)
248
- if ((isRunning && this.canRun(this)) || (!isRunning && this.canWalk(this))) {
249
- const velocity = isRunning ? this.runVelocity : this.walkVelocity;
534
+ // Handle interaction input
535
+ if (ml) {
536
+ entity.startModelOneshotAnimations(this.interactOneshotAnimations);
537
+ input.ml = !this.autoCancelMouseLeftClick;
538
+ }
250
539
 
251
- if (w) {
252
- targetVelocities.x -= velocity * Math.sin(yaw);
253
- targetVelocities.z -= velocity * Math.cos(yaw);
254
- }
255
-
256
- if (s) {
257
- targetVelocities.x += velocity * Math.sin(yaw);
258
- targetVelocities.z += velocity * Math.cos(yaw);
540
+ // Calculate horizontal movement velocities
541
+ if (canMove) {
542
+ const velocity = !this.isSwimming
543
+ ? isFastMovement ? this.runVelocity : this.walkVelocity
544
+ : isFastMovement ? this.swimFastVelocity : this.swimSlowVelocity;
545
+
546
+ if (hasJoystickInput) {
547
+ // Joystick movement: exact direction relative to camera (jd: 0=forward)
548
+ const movementAngle = yaw + jd;
549
+ this._reusableTargetVelocities.x = -velocity * Math.sin(movementAngle);
550
+ this._reusableTargetVelocities.z = -velocity * Math.cos(movementAngle);
551
+ } else {
552
+ // WASD movement: discrete directions relative to camera
553
+ const sinYaw = Math.sin(yaw);
554
+ const cosYaw = Math.cos(yaw);
555
+
556
+ if (w) { this._reusableTargetVelocities.x -= velocity * sinYaw; this._reusableTargetVelocities.z -= velocity * cosYaw; }
557
+ if (s) { this._reusableTargetVelocities.x += velocity * sinYaw; this._reusableTargetVelocities.z += velocity * cosYaw; }
558
+ if (a) { this._reusableTargetVelocities.x -= velocity * cosYaw; this._reusableTargetVelocities.z += velocity * sinYaw; }
559
+ if (d) { this._reusableTargetVelocities.x += velocity * cosYaw; this._reusableTargetVelocities.z -= velocity * sinYaw; }
560
+
561
+ // Normalize diagonal movement to prevent speed boost
562
+ const horizontalSpeed = Math.sqrt(this._reusableTargetVelocities.x * this._reusableTargetVelocities.x + this._reusableTargetVelocities.z * this._reusableTargetVelocities.z);
563
+ if (horizontalSpeed > velocity) {
564
+ const factor = velocity / horizontalSpeed;
565
+ this._reusableTargetVelocities.x *= factor;
566
+ this._reusableTargetVelocities.z *= factor;
567
+ }
259
568
  }
260
-
261
- if (a) {
262
- targetVelocities.x -= velocity * Math.cos(yaw);
263
- targetVelocities.z += velocity * Math.sin(yaw);
569
+ }
570
+
571
+ // Handle swimming physics and vertical movement
572
+ if (this.isSwimming) {
573
+ // Clamp swimming velocities (avoid object spread allocation)
574
+ if (currentVelocity.y < this.swimMaxGravityVelocity) {
575
+ this._reusableVelocityClamp.x = currentVelocity.x;
576
+ this._reusableVelocityClamp.y = this.swimMaxGravityVelocity;
577
+ this._reusableVelocityClamp.z = currentVelocity.z;
578
+ entity.setLinearVelocity(this._reusableVelocityClamp);
264
579
  }
265
-
266
- if (d) {
267
- targetVelocities.x += velocity * Math.cos(yaw);
268
- targetVelocities.z -= velocity * Math.sin(yaw);
580
+ if (currentVelocity.y > this.swimUpwardVelocity * 2) {
581
+ this._reusableVelocityClamp.x = currentVelocity.x;
582
+ this._reusableVelocityClamp.y = this.swimUpwardVelocity * 2;
583
+ this._reusableVelocityClamp.z = currentVelocity.z;
584
+ entity.setLinearVelocity(this._reusableVelocityClamp);
269
585
  }
270
586
 
271
- // Normalize for diagonals
272
- const length = Math.sqrt(targetVelocities.x * targetVelocities.x + targetVelocities.z * targetVelocities.z);
273
- if (length > velocity) {
274
- const factor = velocity / length;
275
- targetVelocities.x *= factor;
276
- targetVelocities.z *= factor;
587
+ // Handle diving and water entry sinking
588
+ if (c) {
589
+ this._reusableTargetVelocities.y = -this.swimUpwardVelocity;
590
+ } else if (performance.now() < this._justSubmergedUntil) {
591
+ this._reusableTargetVelocities.y = -this.swimUpwardVelocity * MyEntityController.WATER_ENTRY_SINKING_FACTOR;
592
+ } else if (!sp) {
593
+ this._reusableTargetVelocities.y = -currentVelocity.y * MyEntityController.SWIMMING_DRAG_FACTOR;
277
594
  }
278
595
  }
279
596
 
280
- // Calculate target vertical velocity (jump)
597
+ // Handle jumping and swimming upward
281
598
  if (sp && this.canJump(this)) {
282
- if (this.isGrounded && currentVelocity.y > -0.001 && currentVelocity.y <= 3) {
283
- targetVelocities.y = this.jumpVelocity;
599
+ if (this.isGrounded && !this.isSwimming && currentVelocity.y > -0.001 && currentVelocity.y <= 3) {
600
+ this._reusableTargetVelocities.y = this.jumpVelocity;
601
+ } else if (this.isSwimming && performance.now() > this._swimUpwardCooldownAt) {
602
+ this._reusableTargetVelocities.y = this.swimUpwardVelocity;
284
603
  }
285
604
  }
286
605
 
287
- // Apply impulse relative to target velocities, taking platform velocity into account
288
- const platformVelocity = this._platform ? this._platform.linearVelocity : { x: 0, y: 0, z: 0 };
289
- const deltaVelocities = {
290
- x: targetVelocities.x - currentVelocity.x + platformVelocity.x,
291
- y: targetVelocities.y + platformVelocity.y,
292
- z: targetVelocities.z - currentVelocity.z + platformVelocity.z,
293
- };
606
+ // Apply physics impulses (avoid platform velocity object allocation)
607
+ const platformVelocity = this._platform?.linearVelocity ?? this._reusablePlatformVelocity;
294
608
 
295
- const hasExternalVelocity =
296
- Math.abs(currentVelocity.x) > this.runVelocity ||
297
- Math.abs(currentVelocity.y) > this.jumpVelocity ||
298
- Math.abs(currentVelocity.z) > this.runVelocity;
609
+ if (this._externalVelocity.y !== 0) {
610
+ this._magnitudeYTracker += this._externalVelocity.y;
611
+ }
612
+
613
+ // Process external impulses if they exist
614
+ if (this._externalVelocity.x !== 0 || this._externalVelocity.y !== 0 || this._externalVelocity.z !== 0) {
615
+ // Only decay horizontal impulses when grounded (physics doesn't decay horizontal velocity in air)
616
+ if (this.isGrounded) {
617
+ // Apply decay to external impulses while preserving direction
618
+ const magnitude = Math.sqrt(
619
+ this._externalVelocity.x * this._externalVelocity.x +
620
+ this._magnitudeYTracker * this._magnitudeYTracker +
621
+ this._externalVelocity.z * this._externalVelocity.z,
622
+ );
623
+
624
+ if (magnitude > 0.01) {
625
+ // Decay the magnitude
626
+ const newMagnitude = Math.max(0, magnitude - MyEntityController.EXTERNAL_IMPULSE_DECAY_RATE);
627
+ const scale = newMagnitude / magnitude;
628
+
629
+ // Apply the scale to preserve direction
630
+ this._externalVelocity.x *= scale;
631
+ this._magnitudeYTracker *= scale; // Also scale the Y tracker
632
+ this._externalVelocity.z *= scale;
633
+ } else {
634
+ // Clear very small values
635
+ this._externalVelocity.x = 0;
636
+ this._externalVelocity.y = 0;
637
+ this._magnitudeYTracker = 0; // Clear the Y tracker
638
+ this._externalVelocity.z = 0;
639
+ }
640
+ }
641
+ }
299
642
 
300
- if (!hasExternalVelocity) { // allow external velocities to resolve, otherwise our deltas will cancel them out.
301
- if (Object.values(deltaVelocities).some(v => v !== 0)) {
302
- const mass = entity.mass;
643
+ // Calculate total target velocity (player input + external + platform)
644
+ const deltaX = this._reusableTargetVelocities.x + this._externalVelocity.x - currentVelocity.x + platformVelocity.x;
645
+ const deltaY = this._reusableTargetVelocities.y + this._externalVelocity.y + platformVelocity.y;
646
+ const deltaZ = this._reusableTargetVelocities.z + this._externalVelocity.z - currentVelocity.z + platformVelocity.z;
303
647
 
304
- entity.applyImpulse({ // multiply by mass for the impulse to result in applying the correct target velocity
305
- x: deltaVelocities.x * mass,
306
- y: deltaVelocities.y * mass,
307
- z: deltaVelocities.z * mass,
308
- });
309
- }
648
+ this._externalVelocity.y = 0;
649
+
650
+ if (deltaX !== 0 || deltaY !== 0 || deltaZ !== 0) {
651
+ const mass = entity.mass;
652
+ this._reusableImpulse.x = deltaX * mass;
653
+ this._reusableImpulse.y = deltaY * mass;
654
+ this._reusableImpulse.z = deltaZ * mass;
655
+ this._internalApplyImpulse(this._reusableImpulse);
310
656
  }
311
657
 
312
- // Apply rotation
313
- if (yaw !== undefined) {
314
- const halfYaw = yaw / 2;
658
+ // Apply character rotation
659
+ if (yaw !== undefined && (this.faceForwardOnStop || this.isActivelyMoving)) {
660
+ const finalYaw = movementDiagonalRotation !== undefined ? yaw + movementDiagonalRotation : yaw;
661
+ const halfFinalYaw = finalYaw * 0.5;
315
662
 
316
663
  entity.setRotation({
317
664
  x: 0,
318
- y: Math.fround(Math.sin(halfYaw)),
665
+ y: Math.sin(halfFinalYaw),
319
666
  z: 0,
320
- w: Math.fround(Math.cos(halfYaw)),
667
+ w: Math.cos(halfFinalYaw),
321
668
  });
322
669
  }
323
670
  }