Skip to content

Commit

Permalink
fix: sdk avatar shape (#2742)
Browse files Browse the repository at this point in the history
* For the global entity representing the SDK avatar (non-player avatar), replaced the TransformComponent by the now needed CharacterTransform
* Fixed SDK avatars cleanup
* Updated test to cover the new need
* Minor code cleanup
* Edited nametag systems to support non player avatars
  • Loading branch information
pravusjif authored Nov 27, 2024
1 parent 9ff4126 commit cb4611b
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ private void UpdateAvatarFromSDKComponent(ref PBAvatarShape pbAvatarShape, ref A
avatarShapeComponent.WearablePromise.ForgetLoading(World);

WearablePromise newPromise = CreateWearablePromise(pbAvatarShape, partition);
avatarShapeComponent.ID = pbAvatarShape.Id;
avatarShapeComponent.Name = pbAvatarShape.Name;
avatarShapeComponent.WearablePromise = newPromise;

avatarShapeComponent.BodyShape = pbAvatarShape;
avatarShapeComponent.HairColor = pbAvatarShape.GetHairColor().ToUnityColor();
avatarShapeComponent.SkinColor = pbAvatarShape.GetSkinColor().ToUnityColor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using DCL.CharacterMotion.Platforms;
using DCL.CharacterMotion.Settings;
using DCL.Diagnostics;
using DCL.ECSComponents;
using ECS.Abstract;
using ECS.Unity.Transforms.Components;
using UnityEngine;
Expand All @@ -32,7 +33,7 @@ protected override void Update(float t)
}

[Query]
[None(typeof(PlayerLookAtIntent))]
[None(typeof(PlayerLookAtIntent), typeof(PBAvatarShape))]
private void LerpRotation(
[Data] float dt,
ref ICharacterControllerSettings settings,
Expand All @@ -55,6 +56,7 @@ private void LerpRotation(
}

[Query]
[None(typeof(PBAvatarShape))]
private void ForceLookAt(in Entity entity, ref CharacterRigidTransform rigidTransform, ref CharacterTransform transform, in PlayerLookAtIntent lookAtIntent)
{
// Rotate player to look at camera target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Arch.SystemGroups.DefaultSystemGroups;
using Cysharp.Threading.Tasks;
using DCL.Character.Components;
using DCL.ECSComponents;
using DCL.MapRenderer.CoordsUtils;
using DCL.MapRenderer.Culling;
using MVC;
Expand Down Expand Up @@ -54,8 +55,9 @@ public void CreateSystems(ref ArchSystemsWorldBuilder<World> builder)
system.Activate();
}

[All(typeof(PlayerComponent))]
[Query]
[All(typeof(PlayerComponent))]
[None(typeof(PBAvatarShape))]
private void SetPlayerTransform(in CharacterTransform transformComponent)
{
SetPosition(transformComponent.Transform.position);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using DCL.AvatarRendering.AvatarShape.Components;
using DCL.Character.Components;
using DCL.CharacterPreview.Components;
using DCL.ECSComponents;
using DCL.MapRenderer.CoordsUtils;
using DCL.MapRenderer.Culling;
using DCL.MapRenderer.MapLayers.UsersMarker;
Expand Down Expand Up @@ -59,7 +60,7 @@ public void CreateSystems(ref ArchSystemsWorldBuilder<World> builder)
}

[Query]
[None(typeof(PlayerComponent), typeof(CharacterPreviewComponent), typeof(DeleteEntityIntention))]
[None(typeof(PlayerComponent), typeof(CharacterPreviewComponent), typeof(PBAvatarShape), typeof(DeleteEntityIntention))]
private void SetPlayerMarker(in CharacterTransform transformComponent, in AvatarShapeComponent avatarShape)
{
if (!isEnabled)
Expand Down
3 changes: 2 additions & 1 deletion Explorer/Assets/DCL/Minimap/Minimap.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"GUID:766b242fb43af451aaa331f39872177d",
"GUID:d832748739a186646b8656bdbd447ad0",
"GUID:286980af24684da6acc1caa413039811",
"GUID:1300820cd310d4584b09afde765bdd16"
"GUID:1300820cd310d4584b09afde765bdd16",
"GUID:3c7b57a14671040bd8c549056adc04f5"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
4 changes: 3 additions & 1 deletion Explorer/Assets/DCL/Minimap/MinimapController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using DCL.Chat.Commands;
using DCL.Chat.MessageBus;
using DCL.Diagnostics;
using DCL.ECSComponents;
using DCL.ExplorePanel;
using DCL.MapRenderer;
using DCL.MapRenderer.CommonBehavior;
Expand Down Expand Up @@ -155,8 +156,9 @@ private void HidePinInMinimapEdge()
}


[All(typeof(PlayerComponent))]
[Query]
[All(typeof(PlayerComponent))]
[None(typeof(PBAvatarShape))]
private void QueryPlayerPosition(in CharacterTransform transformComponent)
{
Vector3 position = transformComponent.Position;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using DCL.CharacterMotion.Settings;
using DCL.CharacterMotion.Utils;
using DCL.Diagnostics;
using DCL.ECSComponents;
using DCL.Multiplayer.Movement.Settings;
using ECS.Abstract;
using ECS.LifeCycle.Components;
Expand Down Expand Up @@ -47,7 +48,7 @@ private void HandleFirstMessage(ref CharacterTransform transComp, in NetworkMove
}

[Query]
[None(typeof(PlayerComponent), typeof(DeleteEntityIntention))]
[None(typeof(PlayerComponent), typeof(PBAvatarShape), typeof(DeleteEntityIntention))]
private void UpdateRemotePlayersMovement([Data] float deltaTime, ref CharacterTransform transComp,
ref RemotePlayerMovementComponent remotePlayerMovement, ref InterpolationComponent intComp, ref ExtrapolationComponent extComp)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using CrdtEcsBridge.Components;
using DCL.Character.Components;
using DCL.Diagnostics;
using DCL.ECSComponents;
using DCL.Multiplayer.Profiles.Systems;
using DCL.Multiplayer.SDK.Components;
using DCL.Profiles;
Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void Update(float t)

[Query]
[All(typeof(Profile))]
[None(typeof(PlayerCRDTEntity), typeof(DeleteEntityIntention))]
[None(typeof(PlayerCRDTEntity), typeof(PBAvatarShape), typeof(DeleteEntityIntention))]
private void AddPlayerCRDTEntity(Entity entity, in CharacterTransform characterTransform)
{
// Reserve entity straight-away, numeration will be preserved across all scenes
Expand All @@ -63,7 +64,7 @@ private void AddPlayerCRDTEntity(Entity entity, in CharacterTransform characterT
}

[Query]
[None(typeof(DeleteEntityIntention))]
[None(typeof(DeleteEntityIntention), typeof(PBAvatarShape))]
private void ModifyPlayerScene(in CharacterTransform characterTransform, ref PlayerCRDTEntity playerCRDTEntity)
{
ResolvePlayerCRDTScene(characterTransform, ref playerCRDTEntity, playerCRDTEntity.CRDTEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
using DCL.Multiplayer.SDK.Components;
using DCL.Optimization.Pools;
using ECS.Abstract;
using ECS.Groups;
using ECS.LifeCycle.Components;
using Utility;
using Quaternion = UnityEngine.Quaternion;
using Vector3 = UnityEngine.Vector3;

namespace DCL.Multiplayer.SDK.Systems.GlobalWorld
{
Expand Down
8 changes: 4 additions & 4 deletions Explorer/Assets/DCL/NameTags/NametagView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,27 @@ public void InjectConfiguration(ChatBubbleConfigurationSO chatBubbleConfiguratio
messageContentAnchoredPosition = new (0, chatBubbleConfiguration.bubbleMarginOffsetHeight / 3);
}

public void SetUsername(string username, string walletId, bool hasClaimedName)
public void SetUsername(string username, string walletId, bool hasClaimedName, bool useVerifiedIcon)
{
ResetElement();

cts.SafeCancelAndDispose();
cts = new CancellationTokenSource();

isClaimedName = hasClaimedName;
VerifiedIcon.gameObject.SetActive(hasClaimedName);
VerifiedIcon.gameObject.SetActive(hasClaimedName && useVerifiedIcon);
Username.text = hasClaimedName ? username : $"{username}<color=#FFFFFF66><font=\"LiberationSans SDF\">#{walletId}</font></color>";
Username.rectTransform.sizeDelta = new Vector2(Username.preferredWidth, DEFAULT_HEIGHT);
MessageContent.color = startingTextColor;

float nametagMarginOffsetHeight = chatBubbleConfiguration?.nametagMarginOffsetHeight ?? DEFAULT_MARGIN_OFFSET_HEIGHT;
float nametagMarginOffsetWidth = chatBubbleConfiguration?.nametagMarginOffsetWidth ?? DEFAULT_MARGIN_OFFSET_WIDTH;

if (hasClaimedName)
if (hasClaimedName && useVerifiedIcon)
{
usernamePos.x = Username.rectTransform.anchoredPosition.x;
verifiedIconInitialPosition = new Vector2(Username.rectTransform.anchoredPosition.x + (Username.preferredWidth / 2) + (VerifiedIcon.sizeDelta.x / 2) - (nametagMarginOffsetHeight / 2), 0);
VerifiedIcon.anchoredPosition = verifiedIconInitialPosition;
usernamePos.x = Username.rectTransform.anchoredPosition.x;
usernamePos.x -= VerifiedIcon.sizeDelta.x / 2;
Username.rectTransform.anchoredPosition = usernamePos;
Background.size = new Vector2(Username.preferredWidth + nametagMarginOffsetWidth + VerifiedIcon.sizeDelta.x, Username.preferredHeight + nametagMarginOffsetHeight);
Expand Down
48 changes: 36 additions & 12 deletions Explorer/Assets/DCL/NameTags/Systems/NametagPlacementSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using ECS.Prioritization.Components;
using System.Runtime.CompilerServices;
using DCL.AvatarRendering.AvatarShape.UnityInterface;
using DCL.ECSComponents;
using UnityEngine;
using UnityEngine.Pool;

Expand All @@ -29,6 +30,7 @@ namespace DCL.Nametags
public partial class NametagPlacementSystem : BaseUnityLoopSystem
{
private const float NAMETAG_SCALE_MULTIPLIER = 0.15f;
private const string NAMETAG_DEFAULT_WALLET_ID = "0000";

private readonly IObjectPool<NametagView> nametagViewPool;
private readonly ChatEntryConfigurationSO chatEntryConfiguration;
Expand Down Expand Up @@ -67,26 +69,33 @@ protected override void Update(float t)
CameraComponent camera = playerCamera.GetCameraComponent(World);

UpdateTagQuery(World, camera);
AddTagQuery(World, camera);
AddTagForPlayerAvatarsQuery(World, camera);
AddTagForNonPlayerAvatarsQuery(World, camera);
ProcessChatBubbleComponentsQuery(World);
UpdateOwnTagQuery(World, camera);
RemoveUnusedChatBubbleComponentsQuery(World);
}

[Query]
[None(typeof(NametagView), typeof(DeleteEntityIntention))]
private void AddTag([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent, in Profile profile)
[None(typeof(NametagView), typeof(PBAvatarShape), typeof(DeleteEntityIntention))]
private void AddTagForPlayerAvatars([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent, in Profile profile)
{
if (partitionComponent.IsBehind || IsOutOfRenderRange(camera, characterTransform) || (camera.Mode == CameraMode.FirstPerson && World.Has<PlayerComponent>(e))) return;

NametagView nametagView = nametagViewPool.Get();
nametagView.Id = avatarShape.ID;
nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name);
nametagView.InjectConfiguration(chatBubbleConfigurationSo);
nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName);
nametagView.gameObject.name = avatarShape.ID;
UpdateTagTransparencyAndScale(nametagView, camera.Camera, characterTransform.Position);
NametagView nametagView = CreateNameTagView(in avatarShape, profile.HasClaimedName, true);
UpdateTagPosition(nametagView, camera.Camera, characterTransform.Position);

World.Add(e, nametagView);
}

[Query]
[None(typeof(NametagView), typeof(Profile), typeof(DeleteEntityIntention))]
[All(typeof(PBAvatarShape))]
private void AddTagForNonPlayerAvatars([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent)
{
if (partitionComponent.IsBehind || IsOutOfRenderRange(camera, characterTransform) || string.IsNullOrEmpty(avatarShape.Name)) return;

NametagView nametagView = CreateNameTagView(in avatarShape, true, false);
UpdateTagPosition(nametagView, camera.Camera, characterTransform.Position);

World.Add(e, nametagView);
Expand All @@ -104,14 +113,15 @@ private void EnableTag(in NametagView nametagView)
}

[Query]
[None(typeof(PBAvatarShape))]
private void UpdateOwnTag([Data] in CameraComponent camera, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in Profile profile, in NametagView nametagView)
{
if (nametagView.Id == avatarShape.ID)
return;

nametagView.Id = avatarShape.ID;
nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name);
nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName);
nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName, true);
nametagView.gameObject.name = avatarShape.ID;
UpdateTagTransparencyAndScale(nametagView, camera.Camera, characterTransform.Position);

Expand All @@ -128,7 +138,6 @@ private void ProcessChatBubbleComponents(Entity e, in ChatBubbleComponent chatBu
World.Remove<ChatBubbleComponent>(e);
}


[Query]
[All(typeof(ChatBubbleComponent))]
//This query is used to remove the ChatBubbleComponent from the entity if the chat bubble has not been displayed
Expand Down Expand Up @@ -177,5 +186,20 @@ private void UpdateTagTransparencyAndScale(NametagView view, Camera camera, Vect

private bool IsOutOfRenderRange(CameraComponent camera, CharacterTransform characterTransform) =>
Vector3.Distance(camera.Camera.transform.position, characterTransform.Position) > chatBubbleConfigurationSo.maxDistance;

private NametagView CreateNameTagView(in AvatarShapeComponent avatarShape, bool hasClaimedName, bool useVerifiedIcon)
{
NametagView nametagView = nametagViewPool.Get();
nametagView.gameObject.name = avatarShape.ID;
nametagView.Id = avatarShape.ID;
nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name);
nametagView.InjectConfiguration(chatBubbleConfigurationSo);

int walletIdLastDigitsIndex = avatarShape.ID.Length - 4;
string walletId = walletIdLastDigitsIndex >= 0 ? avatarShape.ID.Substring(walletIdLastDigitsIndex) : NAMETAG_DEFAULT_WALLET_ID;
nametagView.SetUsername(avatarShape.Name, walletId, hasClaimedName, useVerifiedIcon);

return nametagView;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using Arch.System;
using Arch.SystemGroups;
using Arch.SystemGroups.Throttling;
using DCL.Character.Components;
using DCL.Diagnostics;
using DCL.ECSComponents;
using ECS.Abstract;
using DCL.Utilities;
using ECS.LifeCycle;
using ECS.LifeCycle.Components;
using ECS.Prioritization.Components;
Expand Down Expand Up @@ -37,10 +37,10 @@ protected override void Update(float t)
}

[Query]
[None(typeof(SDKAvatarShapeComponent))]
private void LoadAvatarShape(in Entity entity, ref PBAvatarShape pbAvatarShape, ref PartitionComponent partitionComponent, ref TransformComponent transformComponent)
[None(typeof(SDKAvatarShapeComponent), typeof(DeleteEntityIntention))]
private void LoadAvatarShape(Entity entity, ref PBAvatarShape pbAvatarShape, ref PartitionComponent partitionComponent, ref TransformComponent transformComponent)
{
World.Add(entity, new SDKAvatarShapeComponent(globalWorld.Create(pbAvatarShape, partitionComponent, transformComponent)));
World.Add(entity, new SDKAvatarShapeComponent(globalWorld.Create(pbAvatarShape, partitionComponent, new CharacterTransform(transformComponent.Transform))));
}

[Query]
Expand All @@ -54,32 +54,38 @@ private void UpdateAvatarShape(ref PBAvatarShape pbAvatarShape, ref SDKAvatarSha

[Query]
[None(typeof(PBAvatarShape), typeof(DeleteEntityIntention))]
private void HandleComponentRemoval(in Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent)
private void HandleComponentRemoval(Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent)
{
// If the component is removed at scene-world, the global-world representation should disappear entirely
globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention());
MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity);

World.Remove<SDKAvatarShapeComponent>(entity);
}

[Query]
[All(typeof(DeleteEntityIntention))]
private void HandleEntityDestruction(in Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent)
private void HandleEntityDestruction(Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent)
{
MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity);
World.Remove<SDKAvatarShapeComponent>(entity);
World.Remove<PBAvatarShape>(entity);
globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention());
}

[Query]
public void FinalizeComponents(ref SDKAvatarShapeComponent sdkAvatarShapeComponent)
{
globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention());
}
public void FinalizeComponents(ref SDKAvatarShapeComponent sdkAvatarShapeComponent) =>
MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity);

public void FinalizeComponents(in Query query)
{
public void FinalizeComponents(in Query query) =>
FinalizeComponentsQuery(World);

public void MarkGlobalWorldEntityForDeletion(Entity globalEntity)
{
// Has to be removed, otherwise scene loading may break after teleportation (no error anywhere to know why)
globalWorld.Remove<CharacterTransform>(globalEntity);

// Has to be deferred because many times it happens that the entity is marked for deletion AFTER the
// AvatarCleanUpSystem.Update() and BEFORE the DestroyEntitiesSystem.Update(), probably has to do with
// non-synchronicity between global and scene ECS worlds. AvatarCleanUpSystem resets the DeferDeletion.
globalWorld.Add(globalEntity, new DeleteEntityIntention() { DeferDeletion = true });
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Arch.Core;
using DCL.ECSComponents;
using DCL.Utilities;
using ECS.LifeCycle.Components;
using ECS.Prioritization.Components;
using ECS.TestSuite;
using ECS.Unity.AvatarShape.Components;
using ECS.Unity.AvatarShape.Systems;
using NUnit.Framework;
using DCL.Character.Components;

namespace ECS.Unity.AvatarShape.Tests
{
Expand Down Expand Up @@ -40,7 +40,7 @@ public void ForwardSDKAvatarShapeInstantiationToGlobalWorldSystems()

Assert.AreEqual(1, world.CountEntities(new QueryDescription().WithAll<PBAvatarShape, SDKAvatarShapeComponent>()));
Assert.AreEqual(1, globalWorld.CountEntities(new QueryDescription().WithAll<PBAvatarShape>()));
globalWorld.Query(new QueryDescription().WithAll<PBAvatarShape>(), (ref PBAvatarShape comp) => Assert.AreEqual(pbAvatarShapeComponent.Name, comp.Name));
globalWorld.Query(new QueryDescription().WithAll<PBAvatarShape, CharacterTransform>(), (ref PBAvatarShape comp) => Assert.AreEqual(pbAvatarShapeComponent.Name, comp.Name));
}

[Test]
Expand Down
Loading

0 comments on commit cb4611b

Please sign in to comment.