diff --git a/assets/idle.glb b/assets/idle.glb new file mode 100644 index 0000000..2dba8a2 Binary files /dev/null and b/assets/idle.glb differ diff --git a/assets/jump.glb b/assets/jump.glb new file mode 100644 index 0000000..c292b34 Binary files /dev/null and b/assets/jump.glb differ diff --git a/assets/run.glb b/assets/run.glb new file mode 100644 index 0000000..f293b23 Binary files /dev/null and b/assets/run.glb differ diff --git a/assets/sounds/avatar/avatar_footstep_jump01.wav b/assets/sounds/avatar/avatar_footstep_jump01.wav new file mode 100644 index 0000000..231547a Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_jump01.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_jump02.wav b/assets/sounds/avatar/avatar_footstep_jump02.wav new file mode 100644 index 0000000..b679386 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_jump02.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_jump03.wav b/assets/sounds/avatar/avatar_footstep_jump03.wav new file mode 100644 index 0000000..4f213a5 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_jump03.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_land01.wav b/assets/sounds/avatar/avatar_footstep_land01.wav new file mode 100644 index 0000000..42b049d Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_land01.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_land02.wav b/assets/sounds/avatar/avatar_footstep_land02.wav new file mode 100644 index 0000000..b39291e Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_land02.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run01.wav b/assets/sounds/avatar/avatar_footstep_run01.wav new file mode 100644 index 0000000..24ee90b Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run01.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run02.wav b/assets/sounds/avatar/avatar_footstep_run02.wav new file mode 100644 index 0000000..70a370d Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run02.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run03.wav b/assets/sounds/avatar/avatar_footstep_run03.wav new file mode 100644 index 0000000..744c6ec Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run03.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run04.wav b/assets/sounds/avatar/avatar_footstep_run04.wav new file mode 100644 index 0000000..403e427 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run04.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run05.wav b/assets/sounds/avatar/avatar_footstep_run05.wav new file mode 100644 index 0000000..13fbbc4 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run05.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run06.wav b/assets/sounds/avatar/avatar_footstep_run06.wav new file mode 100644 index 0000000..0c942de Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run06.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run07.wav b/assets/sounds/avatar/avatar_footstep_run07.wav new file mode 100644 index 0000000..58fffe1 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run07.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_run08.wav b/assets/sounds/avatar/avatar_footstep_run08.wav new file mode 100644 index 0000000..7f8498b Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_run08.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk01.wav b/assets/sounds/avatar/avatar_footstep_walk01.wav new file mode 100644 index 0000000..1313545 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk01.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk02.wav b/assets/sounds/avatar/avatar_footstep_walk02.wav new file mode 100644 index 0000000..edfaa79 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk02.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk03.wav b/assets/sounds/avatar/avatar_footstep_walk03.wav new file mode 100644 index 0000000..53101cc Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk03.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk04.wav b/assets/sounds/avatar/avatar_footstep_walk04.wav new file mode 100644 index 0000000..42a7418 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk04.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk05.wav b/assets/sounds/avatar/avatar_footstep_walk05.wav new file mode 100644 index 0000000..db645ac Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk05.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk06.wav b/assets/sounds/avatar/avatar_footstep_walk06.wav new file mode 100644 index 0000000..fefd332 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk06.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk07.wav b/assets/sounds/avatar/avatar_footstep_walk07.wav new file mode 100644 index 0000000..f6aff7d Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk07.wav differ diff --git a/assets/sounds/avatar/avatar_footstep_walk08.wav b/assets/sounds/avatar/avatar_footstep_walk08.wav new file mode 100644 index 0000000..0114416 Binary files /dev/null and b/assets/sounds/avatar/avatar_footstep_walk08.wav differ diff --git a/assets/walk.glb b/assets/walk.glb new file mode 100644 index 0000000..7c83565 Binary files /dev/null and b/assets/walk.glb differ diff --git a/package-lock.json b/package-lock.json index 839a20c..66aee21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,7 @@ "name": "ui-canvas-information", "version": "1.0.0", "dependencies": { - "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/js-runtime": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/walk-player-to/@dcl/js-runtime/dcl-js-runtime-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/sdk": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/sdk-commands": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-commands-7.20.5-22901328357.commit-f984718.tgz" + "@dcl/sdk": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/dcl-sdk-7.22.5-24715381227.commit-c17cf4f.tgz" }, "engines": { "node": ">=16.0.0", @@ -58,9 +55,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -86,27 +83,34 @@ "license": "Apache-2.0" }, "node_modules/@dcl/crypto": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@dcl/crypto/-/crypto-3.4.5.tgz", - "integrity": "sha512-uneyjOAOx7pi5kabZsLmPm9kSLkCk4Cok8FUsvT+6k8RquqkjKqocvkGVOMaoWsfU6S3mkLOyaeqEKmOy4ErxA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@dcl/crypto/-/crypto-3.5.0.tgz", + "integrity": "sha512-o0dv97qoWdUUFcQOrviLa3ukWMmaT4uZUFI3IQwMgf0Dp2LrV908y0Z+19Y0Zee+EoE4fJZWcB2bGbbc6dek2A==", "license": "Apache-2.0", "dependencies": { - "@dcl/schemas": "^9.2.0", + "@dcl/schemas": "^25.2.0", "eth-connect": "^6.0.3", "ethereum-cryptography": "^1.0.3" } }, "node_modules/@dcl/crypto/node_modules/@dcl/schemas": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@dcl/schemas/-/schemas-9.15.0.tgz", - "integrity": "sha512-nip5rsOcJplNfBWeImwezuHLprM0gLW03kEeqGIvT9J6HnEBTtvIwkk9+NSt7hzFKEvWGI+C23vyNWbG3nU+SQ==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@dcl/schemas/-/schemas-25.3.0.tgz", + "integrity": "sha512-ChFW3jU3ELN6YsRvs8TZIueBR8/DDxFcWPOeCoPafjLzSRK4GX9wHYrD3Crent07C3i3tm1rX8L/2rw+S39bzQ==", "license": "Apache-2.0", "dependencies": { "ajv": "^8.11.0", "ajv-errors": "^3.0.0", - "ajv-keywords": "^5.1.0" + "ajv-keywords": "^5.1.0", + "mitt": "^3.0.1" } }, + "node_modules/@dcl/ecs": { + "version": "7.22.5-24715381227.commit-c17cf4f", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/ecs/dcl-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", + "integrity": "sha512-b/jsWCwYl/ZaUL6twX9X92WokbO0xHdkaRsrhuB7BuC3LW+kkBUVbWYvLtHIYvfEACb2iGtK4tFjRKNmy7wUHA==", + "license": "Apache-2.0" + }, "node_modules/@dcl/ecs-math": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@dcl/ecs-math/-/ecs-math-2.1.0.tgz", @@ -150,9 +154,9 @@ } }, "node_modules/@dcl/inspector/node_modules/@dcl/asset-packs": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/@dcl/asset-packs/-/asset-packs-2.12.1.tgz", - "integrity": "sha512-PlOBTjbNMU/R09fw5XlBonf90bvoEZyIbLO5LJvoUEYoofRrsi/pEne5/NHR+9Xv4pjIIEESspaZMbEwStTjbg==", + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/@dcl/asset-packs/-/asset-packs-2.14.3.tgz", + "integrity": "sha512-egSrVRg7hNITc+ppiovIYjhdXGwKVeue2ROI9u1G4+Lzos1CTFyX2V1HnYIDb1S1M5vrfNMlfCAFSOGnNim2Rw==", "license": "ISC", "dependencies": { "@types/glob": "^8.1.0", @@ -180,9 +184,9 @@ } }, "node_modules/@dcl/inspector/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -216,21 +220,21 @@ } }, "node_modules/@dcl/inspector/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/@dcl/inspector/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -265,9 +269,9 @@ } }, "node_modules/@dcl/js-runtime": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/walk-player-to/@dcl/js-runtime/dcl-js-runtime-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-dkJPnCgWE2BAXB2mVc6U8yn7PA7PHASnHZDmCoDUnmkjh0bMVvyX480ZgBI21hMq16bA0ng4seJJv/XPjasj5A==", + "version": "7.22.5-24715381227.commit-c17cf4f", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/scene-driven-movement-animations/@dcl/js-runtime/dcl-js-runtime-7.22.5-24715381227.commit-c17cf4f.tgz", + "integrity": "sha512-UQ4wC+DQh36g3Q2bGgKzre2BTukejWav+tqYDVehoTZ3DBpFtKRH74BGNjdo4oFyKMy3TmPc8G8IvsUPY+I0Jw==", "license": "Apache-2.0" }, "node_modules/@dcl/linker-dapp": { @@ -307,9 +311,9 @@ } }, "node_modules/@dcl/protocol": { - "version": "1.0.0-22900906704.commit-104038a", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-22900906704.commit-104038a.tgz", - "integrity": "sha512-IXilJqWA/KoRNbhxCdSHqJFSu1E29bTI7rVg9T1AkSYNg3KeBpv4XcsyZHbJfRpamxImwVQDhLsAtW7ejxXc1w==", + "version": "1.0.0-24682464295.commit-6dfb0c7", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-24682464295.commit-6dfb0c7.tgz", + "integrity": "sha512-9Yh8QiDWmnRYSp+SWfjgiLSK/f2loPqdfTWyV96hCTiLaLyPm/AD80LYwDXVuYXdrpr/vHHgISwVMTU/9zTn8w==", "license": "Apache-2.0", "dependencies": { "@dcl/ts-proto": "1.154.0", @@ -335,22 +339,16 @@ "license": "Apache-2.0" }, "node_modules/@dcl/react-ecs": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/react-ecs/dcl-react-ecs-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-v29ObDKSemvfSqiaFkfzFQgw/9XIaBAp+zifBnTIkH0W/xUD5B090bDMWYR0HqGOHbVAY0YoafvMesHkSudOuQ==", + "version": "7.22.5-24715381227.commit-c17cf4f", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/react-ecs/dcl-react-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", + "integrity": "sha512-rq4eEartmNVLQChc22qfKp4jmALl64Wmd4ch/RSD6DXO3O07EPqeGvAxsu1VaBLgXEfQYRWwLLwzMCOnJbAm7Q==", "license": "Apache-2.0", "dependencies": { - "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", + "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/ecs/dcl-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", "react": "^18.2.0", "react-reconciler": "^0.29.0" } }, - "node_modules/@dcl/react-ecs/node_modules/@dcl/ecs": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-EGf7Dux6yo/nxwC09YWJfmBuyer/vB6lL6Lw9EEliLGt2WKFuEjoPwSfiQaZMOeHhJINZs+3KC2Ybpj/kzOppQ==", - "license": "Apache-2.0" - }, "node_modules/@dcl/rpc": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@dcl/rpc/-/rpc-1.1.2.tgz", @@ -373,35 +371,35 @@ } }, "node_modules/@dcl/sdk": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-+5uLXS8rnRWEoBUgL0Ha3jQVZHxPQA5Xr4NwNt+GbnTxZ7mr3bHy79riMurYjQiBzOR+xF2m5SQp/Dn++VWjhA==", + "version": "7.22.5-24715381227.commit-c17cf4f", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/dcl-sdk-7.22.5-24715381227.commit-c17cf4f.tgz", + "integrity": "sha512-LXpvP/kQktEJb2MNDCbuDjPOC7QN0il88EWEkD6bNGpWU4GOWdpaqi816Y3y2xjwi0KTx9GgVREu7DDlyPMppw==", "license": "Apache-2.0", "dependencies": { - "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", + "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/ecs/dcl-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", "@dcl/ecs-math": "2.1.0", "@dcl/explorer": "1.0.164509-20240802172549.commit-fb95b9b", - "@dcl/js-runtime": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/walk-player-to/@dcl/js-runtime/dcl-js-runtime-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/react-ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/react-ecs/dcl-react-ecs-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/sdk-commands": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-commands-7.20.5-22901328357.commit-f984718.tgz", + "@dcl/js-runtime": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/scene-driven-movement-animations/@dcl/js-runtime/dcl-js-runtime-7.22.5-24715381227.commit-c17cf4f.tgz", + "@dcl/react-ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/react-ecs/dcl-react-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", + "@dcl/sdk-commands": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/dcl-sdk-commands-7.22.5-24715381227.commit-c17cf4f.tgz", "text-encoding": "0.7.0" } }, "node_modules/@dcl/sdk-commands": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-commands-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-pXS3X0qEsGmGF0+kh8aUF3IMHdT9ZZ2XP6iRt3fZejOWw0doRU+rGXoPsaNaAOwTTifEuP96H+UyvvYE9DAbBw==", + "version": "7.22.5-24715381227.commit-c17cf4f", + "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/dcl-sdk-commands-7.22.5-24715381227.commit-c17cf4f.tgz", + "integrity": "sha512-exNjUknoj5OpnUBGMxzXiHgnd04MUOcq27d8N4sA3p7F1z+h+Hjyvl5pdWnT53vwwBgJYLVOZA++M5yCb0h6lw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@dcl/crypto": "^3.4.4", - "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", + "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/@dcl/ecs/dcl-ecs-7.22.5-24715381227.commit-c17cf4f.tgz", "@dcl/gltf-validator-ts": "1.0.14", "@dcl/hashing": "1.1.3", "@dcl/inspector": "7.25.0", "@dcl/linker-dapp": "^0.14.2", "@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be", - "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-22900906704.commit-104038a.tgz", + "@dcl/protocol": "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-24682464295.commit-6dfb0c7.tgz", "@dcl/quests-client": "^1.0.3", "@dcl/quests-manager": "^0.1.4", "@dcl/rpc": "^1.1.1", @@ -437,18 +435,6 @@ "sdk-commands": "dist/index.js" } }, - "node_modules/@dcl/sdk-commands/node_modules/@dcl/ecs": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-EGf7Dux6yo/nxwC09YWJfmBuyer/vB6lL6Lw9EEliLGt2WKFuEjoPwSfiQaZMOeHhJINZs+3KC2Ybpj/kzOppQ==", - "license": "Apache-2.0" - }, - "node_modules/@dcl/sdk/node_modules/@dcl/ecs": { - "version": "7.20.5-22901328357.commit-f984718", - "resolved": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/@dcl/ecs/dcl-ecs-7.20.5-22901328357.commit-f984718.tgz", - "integrity": "sha512-EGf7Dux6yo/nxwC09YWJfmBuyer/vB6lL6Lw9EEliLGt2WKFuEjoPwSfiQaZMOeHhJINZs+3KC2Ybpj/kzOppQ==", - "license": "Apache-2.0" - }, "node_modules/@dcl/ts-proto": { "version": "1.154.0", "resolved": "https://registry.npmjs.org/@dcl/ts-proto/-/ts-proto-1.154.0.tgz", @@ -889,9 +875,9 @@ "license": "MIT" }, "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", "license": "Apache-2.0", "engines": { "node": ">=8.0.0" @@ -1070,12 +1056,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.4.0.tgz", - "integrity": "sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/node-fetch": { @@ -1163,9 +1149,9 @@ } }, "node_modules/@well-known-components/interfaces/node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "version": "20.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", + "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1318,9 +1304,9 @@ } }, "node_modules/archiver-utils/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1470,9 +1456,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -2350,9 +2336,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2382,29 +2368,29 @@ } }, "node_modules/i18next": { - "version": "25.8.17", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.17.tgz", - "integrity": "sha512-vWtCttyn5bpOK4hWbRAe1ZXkA+Yzcn2OcACT+WJavtfGMcxzkfvXTLMeOU8MUhRmAySKjU4VVuKlo0sSGeBokA==", + "version": "25.10.10", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.10.10.tgz", + "integrity": "sha512-cqUW2Z3EkRx7NqSyywjkgCLK7KLCL6IFVFcONG7nVYIJ3ekZ1/N5jUsihHV6Bq37NfhgtczxJcxduELtjTwkuQ==", "funding": [ { "type": "individual", - "url": "https://locize.com" + "url": "https://www.locize.com/i18next" }, { "type": "individual", - "url": "https://locize.com/i18next.html" + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" }, { "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + "url": "https://www.locize.com" } ], "license": "MIT", "dependencies": { - "@babel/runtime": "^7.28.6" + "@babel/runtime": "^7.29.2" }, "peerDependencies": { - "typescript": "^5" + "typescript": "^5 || ^6" }, "peerDependenciesMeta": { "typescript": { @@ -2413,9 +2399,9 @@ } }, "node_modules/i18next-fs-backend": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.6.1.tgz", - "integrity": "sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.6.4.tgz", + "integrity": "sha512-lzbUnowXYd5RFO8flpQhd9khYWNgrzwtxHw1kktJCiTRBaAEiLB2t9EPSXRj8qlC7WcEgFDIsmBUixyludcznw==", "license": "MIT" }, "node_modules/ieee754": { @@ -2523,9 +2509,9 @@ "license": "Apache-2.0" }, "node_modules/ipfs-unixfs/node_modules/protobufjs": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", - "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "version": "6.11.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.5.tgz", + "integrity": "sha512-OKjVH3hDoXdIZ/s5MLv8O2X0s+wOxGfV7ar6WFSKGaSAxi/6gYn3px5POS4vi+mc/0zCOdL7Jkwrj0oT1Yst2A==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -2575,9 +2561,9 @@ "license": "Apache-2.0" }, "node_modules/ipld-dag-pb/node_modules/protobufjs": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", - "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "version": "6.11.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.5.tgz", + "integrity": "sha512-OKjVH3hDoXdIZ/s5MLv8O2X0s+wOxGfV7ar6WFSKGaSAxi/6gYn3px5POS4vi+mc/0zCOdL7Jkwrj0oT1Yst2A==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -3252,9 +3238,9 @@ "license": "MIT" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -3805,9 +3791,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "license": "MIT" }, "node_modules/util-deprecate": { @@ -3893,9 +3879,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -4000,9 +3986,9 @@ } }, "node_modules/zip-stream/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", diff --git a/package.json b/package.json index fc7d8b4..1afb8f6 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,7 @@ "description": "ECS7 ", "version": "1.0.0", "dependencies": { - "@dcl/ecs": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/js-runtime": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/feat/walk-player-to/@dcl/js-runtime/dcl-js-runtime-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/sdk": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-7.20.5-22901328357.commit-f984718.tgz", - "@dcl/sdk-commands": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1349/merge/dcl-sdk-commands-7.20.5-22901328357.commit-f984718.tgz" + "@dcl/sdk": "https://sdk-team-cdn.decentraland.org/@dcl/js-sdk-toolchain/branch/1377/merge/dcl-sdk-7.22.5-24715381227.commit-c17cf4f.tgz" }, "engines": { "node": ">=16.0.0", diff --git a/src/ground.ts b/src/ground.ts index e88b167..599f12a 100644 --- a/src/ground.ts +++ b/src/ground.ts @@ -62,7 +62,7 @@ export function initGroundRaycast() { function recordGroundState() { prevGrounded = grounded; - grounded = ((groundHitTick == tick) || (playerPosition.y < 0.01)) && prevActualVelocity.y <= 0.01; + grounded = ((groundHitTick == tick) || (playerPosition.y < 0.01)); if (playerPosition.y < 0.01) { Vector3.copyFrom(VEC3_UP, groundNormal); } diff --git a/src/index.ts b/src/index.ts index 5b2bd3c..d457341 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,57 @@ -import { AvatarMovement, AvatarMovementInfo, engine, Transform } from '@dcl/sdk/ecs' +import { AvatarAnimationState, AvatarMovement, AvatarMovementInfo, engine, MovementAnimation, Transform } from '@dcl/sdk/ecs' import { Quaternion, Vector3 } from '@dcl/sdk/math'; import { getExplorerConfiguration } from '~system/EnvironmentApi'; -import { initGroundRaycast, updateGroundAdjust } from './ground'; +import { grounded, initGroundRaycast, updateGroundAdjust } from './ground'; import { dampVelocity, orientation, updateHorizontalVelocity } from './horizontal'; -import { initStepCasts, updateVerticalVelocity } from './vertical'; +import { currentJumpHeight, initStepCasts, jumpStartHeight, updateVerticalVelocity } from './vertical'; import { initParamters as initParameters } from './parameters'; import { initWalkSystem, updateEngineWalk, consumeWalkResult } from './walk'; -import { MAX_SPEED } from './constants'; +import { GRAVITY, MAX_SPEED } from './constants'; + +// Avatar-bus audio clip pools published via MovementAnimation.sounds. Engine +// plays each listed clip once per frame on the avatar's local audio bus — the +// `sounds` field is single-frame fire-and-forget, so we only include it on the +// tick the event actually fires. Timings and variant pools mirror the native +// built-ins in `crates/collectibles/src/emotes.rs` so this scene-driven path +// behaves the same as the velocity-based fallback. +const WALK_STEP_SOUNDS = [ + 'assets/sounds/avatar/avatar_footstep_walk01.wav', + 'assets/sounds/avatar/avatar_footstep_walk02.wav', + 'assets/sounds/avatar/avatar_footstep_walk03.wav', + 'assets/sounds/avatar/avatar_footstep_walk04.wav', + 'assets/sounds/avatar/avatar_footstep_walk05.wav', + 'assets/sounds/avatar/avatar_footstep_walk06.wav', + 'assets/sounds/avatar/avatar_footstep_walk07.wav', + 'assets/sounds/avatar/avatar_footstep_walk08.wav', +]; +const RUN_STEP_SOUNDS = [ + 'assets/sounds/avatar/avatar_footstep_run01.wav', + 'assets/sounds/avatar/avatar_footstep_run02.wav', + 'assets/sounds/avatar/avatar_footstep_run03.wav', + 'assets/sounds/avatar/avatar_footstep_run04.wav', + 'assets/sounds/avatar/avatar_footstep_run05.wav', + 'assets/sounds/avatar/avatar_footstep_run06.wav', + 'assets/sounds/avatar/avatar_footstep_run07.wav', + 'assets/sounds/avatar/avatar_footstep_run08.wav', +]; +const JUMP_SOUNDS = [ + 'assets/sounds/avatar/avatar_footstep_jump01.wav', + 'assets/sounds/avatar/avatar_footstep_jump02.wav', + 'assets/sounds/avatar/avatar_footstep_jump03.wav', +]; +const LAND_SOUNDS = [ + 'assets/sounds/avatar/avatar_footstep_land01.wav', + 'assets/sounds/avatar/avatar_footstep_land02.wav', +]; + +function pickRandom(pool: string[]): string { + return pool[Math.floor(Math.random() * pool.length)]; +} + +// Clip-relative playback times (seconds) at which the walk/run loops trigger +// a footstep. Native config: walk.(0.41, 0.91), run.(0.21, 0.54). +const WALK_STEP_TIMES = [0.41, 0.91]; +const RUN_STEP_TIMES = [0.21, 0.54]; // export all the functions required to make the scene work export * from '@dcl/sdk' @@ -62,6 +107,7 @@ function initFrame() { playerRotation = playerTransform.rotation; const movementInfo = AvatarMovementInfo.getOrNull(engine.PlayerEntity); + activeAnimationState = movementInfo?.activeAnimationState; if (movementInfo !== null) { Vector3.copyFrom(movementInfo.requestedVelocity ?? Vector3.Zero(), prevRequestedVelocity); Vector3.copyFrom(movementInfo.actualVelocity ?? Vector3.Zero(), prevActualVelocity); @@ -83,12 +129,180 @@ function initFrame() { } } +// Tracks the last jumpStartHeight we observed so we can detect a new jump +// (undefined -> defined) and seek the jump clip back to 0 on its first frame. +var prevJumpStartHeight: number | undefined = undefined; +// True from touchdown until the engine reports the non-looped landing clip has +// played through. While true, keep re-requesting the landing so the engine +// holds it; once activeAnimationState shows it has completed, fall through. +var requestingLanding = false; +// Max Y reached while airborne; reset on landing. Used to gate the landing +// sound to drops of >0.5m so stepping off a small curb stays silent. +var maxUngroundedY = -Infinity; +var wasJumpingOrFalling = false; +// Mirror of the engine's currently-active scene animation state. Read in +// initFrame; consulted in selectAnimation to decide when to stop the landing. +var activeAnimationState: AvatarAnimationState | undefined = undefined; +// Last-observed playback phase of the currently-active scene animation, used to +// detect when the clip wrapped past a footstep trigger time since the previous +// frame. Keyed per src so switching clip resets tracking. +var prevSoundTrackedSrc: string | undefined = undefined; +var prevSoundTrackedTime: number = 0; + +// Detects whether the clip's playback time crossed any of the given trigger +// timestamps (in seconds) while playing forward between `prev` and `cur`. +// Backward motion (negative animation speed, e.g. while turning in place +// with the walk clip's speed driven by signed directional velocity) is +// ignored so we don't fire a storm of sounds as the clip scrubs back and +// forth. A genuine loop wrap is distinguished from backward play by +// requiring the apparent reverse jump to span more than half the clip. +function stepTriggered(prev: number, cur: number, duration: number, triggers: number[]): boolean { + if (cur === prev) return false; + const isLoopWrap = cur < prev && duration > 0 && prev - cur > duration * 0.5; + if (cur < prev && !isLoopWrap) return false; + for (const t of triggers) { + if (isLoopWrap) { + if (t > prev || t <= cur) return true; + } else if (t > prev && t <= cur) { + return true; + } + } + return false; +} + +function selectAnimation(): MovementAnimation { + const jumpingOrFalling = jumpStartHeight !== undefined || !grounded; + const newJump = jumpStartHeight !== undefined && prevJumpStartHeight === undefined; + prevJumpStartHeight = jumpStartHeight; + + if (jumpingOrFalling) { + maxUngroundedY = Math.max(maxUngroundedY, playerPosition.y); + } + // Ungrounded -> grounded transition: the frame the landing sound may fire. + const justLanded = wasJumpingOrFalling && !jumpingOrFalling; + wasJumpingOrFalling = jumpingOrFalling; + + if (jumpingOrFalling) { + requestingLanding = true; + // Match the jump clip's ascent timing to the physical ascent: time-to-peak + // under gravity = sqrt(2h/g). Speed 0.5/ttp means the clip hits its apex + // (midpoint, t=0.5) at roughly the same moment the avatar does. + const gravityMag = Math.abs(GRAVITY.y); + const timeToPeak = Math.sqrt(2 * Math.max(currentJumpHeight, 0.01) / gravityMag); + const ascentSpeed = 0.5 / timeToPeak; + // Once the clip has played past its apex pose (midpoint), freeze it via + // speed 0 so long falls from high places don't loop the clip back to the + // takeoff pose. We deliberately don't re-seek every frame — the engine + // preserves the current playback position, and an explicit seek would + // add a visible hiccup to the pose. + const s = activeAnimationState; + const atApex = s !== undefined + && s.src === 'assets/jump.glb' + && s.playbackTime >= 0.5; + // Jump takeoff sound fires for exactly one frame on the newJump tick. + return { + src: 'assets/jump.glb', + speed: atApex ? 0 : ascentSpeed, + loop: true, + idle: false, + transitionSeconds: 0.1, + playbackTime: newJump ? 0 : undefined, + sounds: newJump ? [pickRandom(JUMP_SOUNDS)] : [], + }; + } + + // Landing: play the non-looped jump clip until the engine reports it has + // finished. `loopCount >= 1` means a non-looping clip ran past its end; + // `playbackTime >= duration` covers the tick where it first hits the end. + if (requestingLanding) { + const s = activeAnimationState; + const landingClipFinished = s !== undefined + && s.src === 'assets/jump.glb' + && !s.loop + && (s.loopCount >= 1 || s.playbackTime >= s.duration); + if (landingClipFinished) { + requestingLanding = false; + } else { + // Fire the landing sound on the touchdown frame only, and only if the + // fall was substantial. Covers both jumps and uncommanded walk-offs. + var landSounds: string[] = []; + if (justLanded) { + if (maxUngroundedY - playerPosition.y > 0.5) { + landSounds = [pickRandom(LAND_SOUNDS)]; + } + maxUngroundedY = -Infinity; + } + return { + src: 'assets/jump.glb', + speed: 1.5, + loop: false, + idle: false, + transitionSeconds: 0.1, + sounds: landSounds, + }; + } + } + + // Directional (signed) forward speed — matches engine's damped_velocity projected + // onto gt.forward(); lets the walk/run anim play reversed when moving backward. + const forward = Vector3.rotate(Vector3.Forward(), playerRotation); + const directionalVelLen = velocity.x * forward.x + velocity.z * forward.z; + + if (velocityLength > 0.1) { + if (velocityLength <= 2.6) { + return { + src: 'assets/walk.glb', + speed: directionalVelLen / 1.5, + loop: true, + idle: false, + transitionSeconds: 0.4, + sounds: footstepsFor('assets/walk.glb', WALK_STEP_TIMES, WALK_STEP_SOUNDS), + }; + } + return { + src: 'assets/run.glb', + speed: directionalVelLen / 4.5, + loop: true, + idle: false, + transitionSeconds: 0.4, + sounds: footstepsFor('assets/run.glb', RUN_STEP_TIMES, RUN_STEP_SOUNDS), + }; + } + + return { + src: 'assets/idle.glb', + speed: 1.0, + loop: true, + idle: true, + transitionSeconds: 0.4, + sounds: [], + }; +} + +// Detects a footstep trigger crossing for the currently-playing clip. Returns a +// single-frame sounds list (or empty) so remote clients see each step as an +// independent transition. +function footstepsFor(src: string, triggers: number[], pool: string[]): string[] { + const s = activeAnimationState; + if (s === undefined || s.src !== src) { + prevSoundTrackedSrc = src; + prevSoundTrackedTime = 0; + return []; + } + const cur = s.playbackTime; + const prev = prevSoundTrackedSrc === src ? prevSoundTrackedTime : cur; + prevSoundTrackedSrc = src; + prevSoundTrackedTime = cur; + return stepTriggered(prev, cur, s.duration, triggers) ? [pickRandom(pool)] : []; +} + function writeMovement() { AvatarMovement.createOrReplace(engine.PlayerEntity, { velocity, orientation: -orientation, groundDirection: Vector3.Down(), walkSuccess: consumeWalkResult(), + animation: selectAnimation(), }) Vector3.copyFrom(velocity, lastPublished); diff --git a/src/vertical.ts b/src/vertical.ts index 2c97ae3..5dff7c0 100644 --- a/src/vertical.ts +++ b/src/vertical.ts @@ -30,10 +30,24 @@ function applyGravity() { } export var jumpStartHeight: number | undefined = undefined; +// The jump height applicable to the current (or next) jump — blended between +// walk-jump and sprint-jump based on horizontal speed. Exported so the animation +// selector can size the jump clip's playback speed to match the ascent duration. +export var currentJumpHeight = 0; var jumpWasPressed = false; +var jumpReleased = false; function applyJump() { const jumpIsPressed = inputSystem.isPressed(InputAction.IA_JUMP); + // Track release so a re-press mid-jump doesn't re-engage the continuing-jump + // branch with stale state — that branch sets velocity.y = min(requiredSpeed, + // jumpSpeedCap), and jumpSpeedCap derives from the decayed prev velocity so + // it collapses to a negative, driving velocity.y deeply negative while + // jumpStartHeight stays defined (keeping the avatar in jump animation). + if (!jumpIsPressed && jumpStartHeight !== undefined) { + jumpReleased = true; + } + // Use the more conservative of prev requested vs prev actual so external // forces (impulses, moving platforms) don't inflate sprint jump height/speed. const prevReqHorizLen = Math.sqrt(prevRequestedVelocity.x * prevRequestedVelocity.x + prevRequestedVelocity.z * prevRequestedVelocity.z); @@ -43,7 +57,7 @@ function applyJump() { (naturalHorizSpeed - jogSpeed) / (sprintSpeed - jogSpeed) )); - const currentJumpHeight = jumpHeight + (sprintJumpHeight - jumpHeight) * sprintRatio; + currentJumpHeight = jumpHeight + (sprintJumpHeight - jumpHeight) * sprintRatio; const currentJumpSpeed = JUMP_SPEED + (JUMP_SPEED_SPRINT - JUMP_SPEED) * sprintRatio; // Same rationale for the vertical cap: don't let external vertical forces @@ -58,10 +72,11 @@ function applyJump() { // new jump jumpStartHeight = playerPosition.y; jumpSpeedCap = currentJumpSpeed; + jumpReleased = false; } if (jumpStartHeight !== undefined) { - if (jumpIsPressed && playerPosition.y + 1e-3 < jumpStartHeight + currentJumpHeight) { + if (jumpIsPressed && !jumpReleased && playerPosition.y + 1e-3 < jumpStartHeight + currentJumpHeight) { // continuing jump const jumpHeightRemaining = (jumpStartHeight + currentJumpHeight - playerPosition.y); const requiredJumpTime = Math.sqrt(jumpHeightRemaining * 2 / JUMP_DECEL); @@ -88,7 +103,6 @@ function snapToGround() { if ( jumpStartHeight === undefined // not jumping && !stepping // not stepping - && prevRequestedVelocity.y < 0 // not trying to move up (strictly < 0 so snap is skipped when requestedVelocity is zero, e.g. during engine-controlled movement) && prevGrounded // was grounded last frame && groundDistance < GROUND_SNAP_HEIGHT // close enough ) {