Skip to content

Commit 346cba0

Browse files
authored
feat: support scene named spawn points (#9369)
# Pull Request Description ## What does this PR change? Adds **named spawn point selection** to the teleport pipeline (part of #6848). Scenes already declare named spawn points in `scene.json`; until now the explorer always ran the default selection (default-flagged → closest). This PR lets a teleport request a spawn point **by name**, end-to-end. **Core mechanism** (single chokepoint, applies to every entry point below): - `TeleportUtils.PickSpawnPoint` gains `string? spawnPointName`. When set and matched (**case-insensitive**), that point is used directly, bypassing the default/closest logic. - Unmatched name → **soft fallback** to the default selection + `ReportHub` warning (`Spawn point '<name>' not found in scene, falling back to default spawn point selection`). The teleport itself never fails because of a bad name. - Duplicate names → first in declaration order wins (+ warning). - Everything *after* selection is unchanged: coordinate-range points (`"x": [min, max]`) still scatter arriving players randomly within the range; `cameraTarget` still applies. **Entry points wired in this PR:** | Entry point | Syntax | |---|---| | `/goto` (Genesis) | `/goto x,y/spawnPoint` | | `/goto` (worlds) | `/goto world/spawnPoint`, `/goto world/x,y/spawnPoint` | | `/goto-local` | `/goto-local x,y/spawnPoint`, `/goto-local spawnPoint` (current scene) | | Deep link (cold start + runtime) | `decentraland://?realm=...&spawnpoint=spawnPoint` | | Launch parameter (CLI / CI) | `Explorer.exe --realm ... --spawnpoint spawnPoint` | **Also included:** - `/goto` parsing extracted into pure `ChatParamUtils.ParseGotoTarget` with full grammar-table unit tests (`ChatParamUtilsShould`); `GoToChatCommand` is now a thin dispatcher. - The chat command handler now trims trailing whitespace, so `/goto 0,0 ` (trailing space) no longer fails validation — for all commands. - **Already-in-realm named teleport**: `/goto world/name` (and the runtime deep link with `spawnpoint` but no `position`) used while already inside the target realm now teleports to the named spawn point of the scene the player stands in, instead of stopping at `🟡 You are already in ...`. Without a name the old message is kept. - Unit tests: `TeleportUtilsShould` (named selection core), `ChatParamUtilsShould` (grammar), `RealmLaunchSettingsShould` (deep link / CLI arg parsing), `ChatTeleporterShould` (already-in-realm branching). **Out of scope:** SDK entry points (`teleportTo` / `changeRealm` with `spawnPoint`) — they require protocol + js-sdk-toolchain changes first; nothing for them in this repo yet. ## Test Instructions **Steps (standard run)**: ```bash metaforge explorer run 9369 ``` ### Prerequisites - A world with named spawn points. **Test world: `flutterecho.dcl.eth`** (4x4 parcels, spotlight cubes in each corner, physics playground near the origin corner), deployed with: | Name | Position | What it's for | |---|---|---| | `spawn` (default) | 2, 0, 2 | default landing (regression) | | `center` | 32, 0, 32 | scene center | | `physics` | 15, 0, 12 | inside the physics playground | | `far-light` | 60, 0, 60 | far corner; has `cameraTarget` looking back at scene center | | `mid-corner` | 4, 0, 60 | another corner | | `scatter` | x∈[26,38], z∈[26,38] | coordinate-range scatter | | `twin` (declared twice) | 10, 0, 50 and 50, 0, 10 | duplicate-name resolution | - The "not found" / "duplicate" warnings go to **logs, not chat**: ```bash metaforge explorer logs tail --filter "spawn point" ``` ### Test Cases #### 1. `/goto` — world forms 1. From Genesis: `/goto flutterecho/center` → realm change, land at scene center (32, 32). No coordinates given: the world manifest picks the parcel, the name picks the point. 2. From Genesis: `/goto flutterecho.dcl.eth/0,0/far-light` → land at the far corner **and** the camera faces back toward scene center (`cameraTarget`). 3. Already inside the world: `/goto flutterecho/0,0/physics` → teleport within the world to the physics playground. 4. Already inside the world: `/goto flutterecho/center` → **in-world teleport** to the scene center, no realm change (the name targets a spawn point of the scene you are standing in). 5. Already inside the world: `/goto flutterecho` (no name) → `🟡 You are already in...`, no teleport (pre-existing behavior, unchanged). 6. Regression: `/goto flutterecho` from Genesis → land at the default `spawn` (2, 2), exactly as before. #### 2. `/goto` — Genesis form 1. `/goto x,y/name` against any Genesis scene that declares named spawn points → lands at the named point. 2. Fallback path works on **any** parcel: `/goto 0,0/nosuch` → normal teleport to 0,0 + warning in logs. 3. Regression: `/goto 0,0`, `/goto random`, `/goto crowd` behave exactly as before. 4. From inside a world: `/goto 0,0/name` → realm change to Genesis carries the name (it is not dropped). #### 3. `/goto-local` (inside the world / any realm) 1. `/goto-local 0,0/center` → parcel + name form. 2. `/goto-local physics` → **bare-name form**: teleports to the named point of the scene you are currently standing in. 3. `/goto-local far-light` → also verify camera orientation. 4. Reserved words are not names: `/goto-local random` / `/goto-local crowd` → `🔴 Invalid parameters` + usage. 5. `/goto-local nosuch` → teleport to your current parcel, default spawn selection + warning in logs (soft fallback). 6. Regression: `/goto-local 0,0` unchanged. #### 4. Deep link — cold start (client closed) ``` decentraland://?realm=flutterecho.dcl.eth&dclenv=org&spawnpoint=physics ``` 1. Client starts and the **initial** landing is the physics playground (not the default `spawn`). 2. With a position: `decentraland://?realm=flutterecho.dcl.eth&dclenv=org&position=0,0&spawnpoint=far-light`. 3. Bad name: `...&spawnpoint=nosuch` → lands at default spawn + warning in logs. #### 5. Deep link — runtime (client already running) 1. While standing in another realm (e.g. Genesis), open the same deep link from the OS → realm change, land at the named point. 2. Already **inside** the world, deep link with `position` + `spawnpoint` → in-world teleport to the named point. 3. Already **inside** the world, deep link with `spawnpoint` but **without** `position` (`decentraland://?realm=flutterecho.dcl.eth&dclenv=org&spawnpoint=far-light`) → in-world teleport to the named spawn point of the current scene (previously this silently did nothing). 4. Already inside the world, deep link with `realm` only (no `position`, no `spawnpoint`) → nothing happens (pre-existing "already in realm" behavior, unchanged). #### 6. Launch parameters (cmd / CI) ```powershell Explorer.exe --realm flutterecho.dcl.eth --dclenv org --spawnpoint physics ``` 1. Same expectations as the cold-start deep link (CLI args and deep link query params share one parser). 2. Genesis variant: `--realm <genesis peer> --position 0,0 --spawnpoint <name>`. #### 7. Cross-cutting edge cases (any entry point) 1. **Case-insensitivity**: `/goto-local PHYSICS`, `/goto flutterecho/Far-Light`, `...&spawnpoint=CENTER` → all match. 2. **Range scatter**: `/goto-local scatter` several times in a row → each landing is a *different* spot within the 26..38 square (players must not stack on one point). 3. **Duplicate names**: `/goto-local twin` repeatedly → always lands at (10, 50) (first declared), never (50, 10); warning about duplicates in logs. 4. **Unknown name**: never breaks the teleport — always default selection + `Spawn point '<name>' not found...` in logs. Nothing red in chat. 5. **Trailing whitespace**: `/goto flutterecho/center ` (trailing spaces) → works (previously any trailing space failed validation of any command). 6. **Grammar junk** stays world-names (unchanged behavior): `/goto myworld//lobby`, `/goto myworld/0,0/` → treated as a (non-existent) world → `🔴 ... doesn't exist or not reachable`. 7. **`/goto flutterecho/random`** → `random` here is a spawn point *name* (soft fallback if the scene has none), not the random-parcel flag. 8. **Initial world entry without a name** (jump-in, navmap, plain deep link) → default spawn, no behavior change.
1 parent c821324 commit 346cba0

49 files changed

Lines changed: 1093 additions & 253 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# pr-comment-test-failures.yml
2+
---
3+
name: Comment Test Failures on PR
4+
5+
# Runs in the trusted base-repo context after the (possibly fork) "Unity Test"
6+
# run completes, so it can comment with write permissions without exposing them
7+
# to the untrusted test job. Mirrors pr-comment-warnings.yml.
8+
on:
9+
workflow_run:
10+
types:
11+
- "completed"
12+
workflows:
13+
- "Unity Test"
14+
workflow_dispatch:
15+
16+
permissions:
17+
contents: read
18+
pull-requests: write
19+
20+
jobs:
21+
comment:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Resolve PR number
25+
id: pr
26+
env:
27+
WORKFLOW_RUN_EVENT_OBJ: ${{ toJSON(github.event.workflow_run) }}
28+
run: |
29+
PR_NUMBER=$(jq -r '.pull_requests[0].number' <<< "$WORKFLOW_RUN_EVENT_OBJ")
30+
echo "PR number: $PR_NUMBER"
31+
if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then
32+
echo "No PR associated with this run, skipping."
33+
echo "pr-number=" >> "$GITHUB_OUTPUT"
34+
else
35+
echo "pr-number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
36+
fi
37+
38+
- name: Download editmode failed-test results
39+
if: steps.pr.outputs.pr-number != ''
40+
id: download-editmode
41+
continue-on-error: true
42+
uses: actions/download-artifact@v4
43+
with:
44+
name: failed-tests-editmode
45+
run-id: ${{ github.event.workflow_run.id }}
46+
github-token: ${{ github.token }}
47+
path: failed-tests/editmode
48+
49+
- name: Download playmode failed-test results
50+
if: steps.pr.outputs.pr-number != ''
51+
id: download-playmode
52+
continue-on-error: true
53+
uses: actions/download-artifact@v4
54+
with:
55+
name: failed-tests-playmode
56+
run-id: ${{ github.event.workflow_run.id }}
57+
github-token: ${{ github.token }}
58+
path: failed-tests/playmode
59+
60+
- name: Compose comment body
61+
if: steps.pr.outputs.pr-number != '' && (steps.download-editmode.outcome == 'success' || steps.download-playmode.outcome == 'success')
62+
id: body
63+
run: |
64+
DELIM="EOF_$(uuidgen)"
65+
{
66+
echo "body<<$DELIM"
67+
echo "<!-- test-failures -->"
68+
69+
passed=0
70+
failed=0
71+
any_results=false
72+
for mode in editmode playmode; do
73+
file="failed-tests/$mode/failed-tests-$mode.json"
74+
[ -f "$file" ] || continue
75+
[ "$(jq -r '.hasResults' "$file")" = "true" ] && any_results=true
76+
# The artifact comes from the untrusted pull_request job - never let a
77+
# non-numeric value reach the arithmetic context.
78+
p=$(jq -r '.passed' "$file"); [[ "$p" =~ ^[0-9]+$ ]] || p=0
79+
passed=$((passed + p))
80+
failed=$((failed + $(jq -r '.failed | length' "$file")))
81+
done
82+
83+
if [ "$any_results" = "false" ]; then
84+
echo "**Test results not found** — the test run likely crashed or timed out before producing results; check the \`Unity Tests\` checks."
85+
elif [ "$failed" -eq 0 ]; then
86+
echo "**Tests: $passed passed, 0 failed** ✅"
87+
else
88+
echo "**Tests: $passed passed, $failed failed**"
89+
echo ""
90+
echo "<details><summary>Failed tests ($failed)</summary>"
91+
echo ""
92+
for mode in editmode playmode; do
93+
file="failed-tests/$mode/failed-tests-$mode.json"
94+
[ -f "$file" ] || continue
95+
jq -r --arg mode "$mode" '.failed[] | "- [\($mode)] \(. | gsub("[\r\n]"; " "))"' "$file"
96+
done
97+
echo ""
98+
echo "</details>"
99+
fi
100+
echo "$DELIM"
101+
} >> "$GITHUB_OUTPUT"
102+
103+
- name: Find existing comment
104+
if: steps.body.outcome == 'success'
105+
uses: peter-evans/find-comment@v2
106+
id: find-comment
107+
with:
108+
issue-number: ${{ steps.pr.outputs.pr-number }}
109+
comment-author: 'github-actions[bot]'
110+
body-includes: '<!-- test-failures -->'
111+
112+
- name: Upsert comment
113+
if: steps.body.outcome == 'success'
114+
uses: peter-evans/create-or-update-comment@v3
115+
with:
116+
issue-number: ${{ steps.pr.outputs.pr-number }}
117+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
118+
edit-mode: replace
119+
body: ${{ steps.body.outputs.body }}

.github/workflows/pr-comment-warnings.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ jobs:
7070
BASELINE: ${{ steps.result.outputs.baseline }}
7171
ALLOW_EQUAL: ${{ steps.result.outputs.allow-equal }}
7272
run: |
73+
DELIM="EOF_$(uuidgen)"
7374
{
74-
echo "body<<EOF"
75+
echo "body<<$DELIM"
7576
echo "<!-- warning-ratchet -->"
7677
blocked=false
7778
if [ -z "$BASELINE" ]; then
@@ -85,26 +86,24 @@ jobs:
8586
blocked=true
8687
fi
8788
88-
# Always list the warnings/errors in files this PR changed; expand only when blocking.
89+
# Always list the warnings/errors in files this PR changed, collapsed by default.
8990
total=$(jq -r '.pr_findings_total // 0' warning-result.json)
9091
if [ "$total" -gt 0 ]; then
91-
open_attr=""
92-
[ "$blocked" = "true" ] && open_attr=" open"
9392
echo ""
94-
echo "<details$open_attr><summary>Warnings/errors in files changed by this PR ($total)</summary>"
93+
echo "<details><summary>Warnings/errors in files changed by this PR ($total)</summary>"
9594
echo ""
96-
echo "| File | Line | Rule | Message |"
97-
echo "| --- | --- | --- | --- |"
98-
jq -r '.pr_findings[] | "| \(.file) | \(.line) | \(.rule) | \(.message | gsub("[|\r\n]"; " ")) |"' warning-result.json
95+
echo '```'
96+
jq -r '.pr_findings[] | "\(.file):\(.line) \(.rule) \(.message | gsub("[\r\n]"; " "))"' warning-result.json
9997
shown=$(jq -r '.pr_findings | length' warning-result.json)
10098
if [ "$total" -gt "$shown" ]; then
10199
echo ""
102-
echo "_…and $((total - shown)) more (see the \`csharp-lint-reports\` artifact)._"
100+
echo "…and $((total - shown)) more (see the csharp-lint-reports artifact)."
103101
fi
102+
echo '```'
104103
echo ""
105104
echo "</details>"
106105
fi
107-
echo "EOF"
106+
echo "$DELIM"
108107
} >> "$GITHUB_OUTPUT"
109108
110109
- name: Find existing comment

.github/workflows/test.yml

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ jobs:
444444
env:
445445
COUNT: ${{ steps.warnings.outputs.count }}
446446
BASELINE: ${{ steps.baseline.outputs.baseline }}
447+
FINDINGS_TOTAL: ${{ steps.pr-findings.outputs.total || 0 }}
447448
run: |
448449
if [ -z "$COUNT" ]; then
449450
echo "No warning count computed (lint produced no result) - skipping comment payload."
@@ -455,7 +456,7 @@ jobs:
455456
--arg baseline "$BASELINE" \
456457
--argjson allow_equal "$IS_RELEASE_OR_HOTFIX" \
457458
--slurpfile findings pr-findings.json \
458-
--argjson findings_total "${{ steps.pr-findings.outputs.total || 0 }}" \
459+
--argjson findings_total "$FINDINGS_TOTAL" \
459460
'{pr: $pr, count: $count, baseline: (if $baseline == "" then null else ($baseline | tonumber) end), allow_equal: $allow_equal, pr_findings: ($findings[0] // []), pr_findings_total: $findings_total}' \
460461
> warning-result.json
461462
cat warning-result.json
@@ -691,6 +692,65 @@ jobs:
691692
fail-on-error: true
692693
fail-on-empty: true
693694
use-actions-summary: true
695+
list-suites: failed
696+
list-tests: failed
697+
698+
# Extracts just the failed test-case fullnames from the NUnit XML results, so the
699+
# trusted pr-comment-test-failures.yml companion (workflow_run) can post a small,
700+
# copy-pasteable PR comment - a dev can grab a name and re-run it locally instead of
701+
# reading the full report.
702+
- name: Extract failed test names
703+
if: always() && github.event_name == 'pull_request'
704+
env:
705+
ARTIFACTS_PATH: ${{ steps.testRunner.outputs.artifactsPath }}
706+
TEST_MODE: ${{ matrix.testMode }}
707+
run: |
708+
python3 - <<'PY'
709+
import glob, json, os, xml.etree.ElementTree as ET
710+
711+
artifacts_path = os.environ["ARTIFACTS_PATH"]
712+
test_mode = os.environ["TEST_MODE"]
713+
714+
xml_files = glob.glob(f"{artifacts_path}/*.xml")
715+
total = 0
716+
passed = 0
717+
failed = []
718+
719+
for path in xml_files:
720+
try:
721+
root = ET.parse(path).getroot()
722+
except ET.ParseError:
723+
continue
724+
for test_case in root.iter("test-case"):
725+
case_result = test_case.get("result")
726+
if case_result is None:
727+
continue
728+
total += 1
729+
if case_result == "Passed":
730+
passed += 1
731+
elif case_result == "Failed":
732+
failed.append(test_case.get("fullname") or test_case.get("name"))
733+
734+
result = {
735+
"hasResults": len(xml_files) > 0,
736+
"total": total,
737+
"passed": passed,
738+
"failed": sorted(set(failed)),
739+
}
740+
741+
with open(f"failed-tests-{test_mode}.json", "w") as f:
742+
json.dump(result, f)
743+
744+
print(f"[{test_mode}] xml files: {len(xml_files)}, total: {total}, passed: {passed}, failed: {len(result['failed'])}")
745+
PY
746+
747+
- name: Upload failed test names
748+
if: always() && github.event_name == 'pull_request'
749+
uses: actions/upload-artifact@v4
750+
with:
751+
name: failed-tests-${{ matrix.testMode }}
752+
path: failed-tests-${{ matrix.testMode }}.json
753+
if-no-files-found: ignore
694754

695755
# Upload artifact
696756
- uses: actions/upload-artifact@v6

Explorer/Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/Tests/SystemSpecUtilsShould.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void SetUp()
3333
[TearDown]
3434
public void TearDown()
3535
{
36-
FeatureFlagsConfiguration.Reset(true);
36+
FeatureFlagsConfiguration.Reset();
3737
}
3838

3939
[Test]
@@ -194,13 +194,13 @@ public void ValidateMemorySizeSufficient(int actualMB, int requiredMB, bool expe
194194
public void ValidateVramSizeSufficient(int actualVramMB, bool expectedResult)
195195
{
196196
// Arrange: The requirement for this test suite is 6GB.
197-
const int requiredVramMB = 6144; // 6 * 1024
197+
const int REQUIRED_VRAM_MB = 6144; // 6 * 1024
198198

199199
// Act: Call the method being tested.
200-
bool isSufficient = SystemSpecUtils.IsMemorySizeSufficient(actualVramMB, requiredVramMB);
200+
bool isSufficient = SystemSpecUtils.IsMemorySizeSufficient(actualVramMB, REQUIRED_VRAM_MB);
201201

202202
// Assert: Verify the result is what we expect.
203-
Assert.AreEqual(expectedResult, isSufficient, $"Failed on VRAM actual: {actualVramMB}MB, required: {requiredVramMB}MB");
203+
Assert.AreEqual(expectedResult, isSufficient, $"Failed on VRAM actual: {actualVramMB}MB, required: {REQUIRED_VRAM_MB}MB");
204204
}
205205
}
206206
}

Explorer/Assets/DCL/AuthenticationScreenFlow/Tests/AvatarRandomizerShould.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using CommunicationData.URLHelpers;
22
using DCL.AvatarRendering.Loading.Components;
3-
using DCL.AuthenticationScreenFlow;
43
using NUnit.Framework;
54
using System.Collections.Generic;
65
using System.Linq;
@@ -20,9 +19,8 @@ public class AvatarRandomizerShould
2019
private const string FACIAL_HAIR = "facial_hair";
2120
private const string HAT = "hat";
2221
private const string EYEWEAR = "eyewear";
23-
private const string BODY_SHAPE = "body_shape";
2422

25-
private AvatarRandomizer randomizer;
23+
private AvatarRandomizer randomizer = null!;
2624

2725
[SetUp]
2826
public void SetUp()

Explorer/Assets/DCL/AvatarAnimation/Editor/AvatarTrack.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-

2-
using DCL.AvatarRendering.AvatarShape.UnityInterface;
1+
using DCL.AvatarRendering.AvatarShape.UnityInterface;
32
using UnityEngine.Timeline;
43

5-
namespace DCL.AvatarAnimation
4+
namespace DCL.AvatarAnimation.Editor
65
{
76
/// <summary>
87
/// A timeline track intented for animating avatars.

Explorer/Assets/DCL/AvatarAnimation/Editor/BaseAvatarPlayableBehaviour.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-

2-
using Arch.Core;
1+
using Arch.Core;
32
using DCL.AvatarRendering.AvatarShape.UnityInterface;
43
using Global.Dynamic;
54
using UnityEngine.Playables;
65

7-
namespace DCL.AvatarAnimation
6+
namespace DCL.AvatarAnimation.Editor
87
{
98
/// <summary>
109
/// A playable / clip for the Unity timeline that performs some animations on an AvatarBase.
1110
/// Inherit from this class to create new playable behaviours for the avatar.
1211
/// </summary>
1312
public class BaseAvatarPlayableBehaviour : PlayableBehaviour
1413
{
15-
static readonly private QueryDescription ALL_AVATARS_QUERY_DESCRIPTION = new QueryDescription().WithAll<AvatarBase>();
14+
private static readonly QueryDescription ALL_AVATARS_QUERY_DESCRIPTION = new QueryDescription().WithAll<AvatarBase>();
1615

1716
/// <summary>
1817
/// Gets the Entity corresponding to the AvatarBase assigned to the track. It may be Entity.Null.

Explorer/Assets/DCL/AvatarAnimation/Editor/MoveAvatarPlayableAsset.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-

2-
using DCL.CharacterMotion.Components;
1+
using DCL.CharacterMotion.Components;
32
using System.ComponentModel;
43
using UnityEngine;
54
using UnityEngine.Playables;
65
using UnityEngine.Timeline;
76

8-
namespace DCL.AvatarAnimation
7+
namespace DCL.AvatarAnimation.Editor
98
{
109
[DisplayName("Avatar movement clip")]
1110
public class MoveAvatarPlayableAsset : PlayableAsset, ITimelineClipAsset

Explorer/Assets/DCL/AvatarAnimation/Editor/MoveAvatarPlayableBehaviour.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-

2-
using Arch.Core;
1+
using Arch.Core;
32
using DCL.AvatarRendering.AvatarShape.UnityInterface;
43
using DCL.CharacterMotion.Components;
54
using Global.Dynamic;
6-
using UnityEngine.Playables;
75
using UnityEngine;
6+
using UnityEngine.Playables;
87

9-
namespace DCL.AvatarAnimation
8+
namespace DCL.AvatarAnimation.Editor
109
{
1110
/// <summary>
1211
/// A playable / clip for the Unity timeline that makes an avatar move and / or rotate. When the clip is not playing, the avatar does not move.

Explorer/Assets/DCL/AvatarAnimation/Editor/TeleportAvatarPlayableAsset.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-

2-
using System.ComponentModel;
1+
using System.ComponentModel;
32
using UnityEngine;
43
using UnityEngine.Playables;
54
using UnityEngine.Timeline;
65

7-
namespace DCL.AvatarAnimation
6+
namespace DCL.AvatarAnimation.Editor
87
{
98
[DisplayName("Avatar teleport clip")]
109
public class TeleportAvatarPlayableAsset : PlayableAsset, ITimelineClipAsset

0 commit comments

Comments
 (0)