< Summary

Class:DCL.EntityIdHelper
Assembly:DCL.Runtime.Interfaces
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/Interfaces/EntityIdHelper.cs
Covered lines:50
Uncovered lines:0
Coverable lines:50
Total lines:156
Line coverage:100% (50 of 50)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
EntityIdHelper()0%110100%
GetOriginalId(...)0%11110100%
ToBase36EntityId(...)0%220100%
EntityFromLegacyEntityString(...)0%110100%
GetConvertedEntityId(...)0%770100%
entityIdFromDictionary(...)0%880100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/Interfaces/EntityIdHelper.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Text;
 5using System.Text.RegularExpressions;
 6using DCL.Models;
 7using UnityEngine;
 8
 9namespace DCL
 10{
 11    public class EntityIdHelper
 12    {
 59313        internal Dictionary<long, string> entityIdToLegacyId = new Dictionary<long, string>();
 59314        internal Dictionary<string, long> invalidEntities = new Dictionary<string, long>();
 15
 59316        private int invalidEntityCounter = -1;
 17
 18        public string GetOriginalId(long entityId)
 19        {
 20            // if the entityId is less than 512, then it is considered well-known.
 4721            if (entityId < 512)
 22            {
 23                switch (entityId)
 24                {
 25                    case (long)SpecialEntityId.SCENE_ROOT_ENTITY:
 126                        return SpecialEntityIdLegacyLiteral.SCENE_ROOT_ENTITY;
 27
 28                    case (long)SpecialEntityId.FIRST_PERSON_CAMERA_ENTITY_REFERENCE:
 129                        return SpecialEntityIdLegacyLiteral.FIRST_PERSON_CAMERA_ENTITY_REFERENCE;
 30
 31                    case (long)SpecialEntityId.AVATAR_ENTITY_REFERENCE:
 132                        return SpecialEntityIdLegacyLiteral.AVATAR_ENTITY_REFERENCE;
 33
 34                    case (long)SpecialEntityId.AVATAR_POSITION_REFERENCE:
 135                        return SpecialEntityIdLegacyLiteral.AVATAR_POSITION_REFERENCE;
 36
 37                    case (long)SpecialEntityId.THIRD_PERSON_CAMERA_ENTITY_REFERENCE:
 138                        return SpecialEntityIdLegacyLiteral.THIRD_PERSON_CAMERA_ENTITY_REFERENCE;
 39                }
 40            }
 41
 42            // if it has the 0x8000_0000 mask, then it *should* be stored in the entityIdToLegacyId map
 4243            if ((entityId & 0x80000000) != 0 && entityIdToLegacyId.ContainsKey(entityId))
 44            {
 45                // the entity has the 0x80000000 mask signaling it was an invalid ID
 246                return entityIdToLegacyId[entityId];
 47            }
 48
 49            // lastly, fallback to generating the entityId based on the number.
 4050            return ToBase36EntityId(entityId);
 51        }
 52
 53        private string ToBase36EntityId(long value)
 54        {
 55            // TODO(mendez): the string builder approach can be better. It does use more allocations
 56            //               than the optimal. The ideal scenario would use a `stackalloc char[13]` instead
 57            //               of StringBuilder but my knowledge and tools for C# are limited at the moment
 58            const string base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
 4059            var sb = new StringBuilder(13);
 60
 4061            value = value >> 9; // recover from bit-shift
 4062            value -= 1; // recover the added 1
 63
 64            do
 65            {
 5866                sb.Insert(0, base36[(byte)(value % 36)]);
 5867                value /= 36;
 5868            } while (value != 0);
 69
 70            // E prefix for entities
 4071            sb.Insert(0, "E");
 72
 4073            return sb.ToString();
 74        }
 75
 76        public long EntityFromLegacyEntityString(string entityId)
 77        {
 5178            long entityIdLong = GetConvertedEntityId(entityId);
 5179            return entityIdLong;
 80        }
 81
 82        private long GetConvertedEntityId(string entityId)
 83        {
 84            // entity Ids in base36 start with E
 5185            if (entityId[0] == 'E')
 86            {
 3187                long result = 1;
 3188                long power = 1;
 19289                for (var i = entityId.Length - 1; i > 0; i--)
 90                {
 6791                    char charCode = entityId[i];
 6792                    bool isNumber = charCode >= '0' && charCode <= '9';
 6793                    bool isBase36Letter = charCode >= 'a' && charCode <= 'z';
 6794                    if (isNumber)
 2195                        result += (charCode - '0') * power;
 4696                    else if (isBase36Letter)
 4497                        result += (10 + (charCode - 'a')) * power;
 98                    else // non base36, fallback to entityIdFromDictionary
 299                        return entityIdFromDictionary(entityId);
 100
 65101                    power *= 36;
 102                }
 103
 104                // reserve 512 entity ids (<<9)
 29105                long newEntityIdLong = result << 9;
 106
 29107                return newEntityIdLong;
 108            }
 109
 110            // non standard entity, fallback to entityIdFromDictionary
 20111            return entityIdFromDictionary(entityId);
 112        }
 113
 114        private long entityIdFromDictionary(string entityId)
 115        {
 116            // first we try against well known and lesser used entities
 117            switch (entityId)
 118            {
 119                case SpecialEntityIdLegacyLiteral.SCENE_ROOT_ENTITY:
 2120                    return (long) SpecialEntityId.SCENE_ROOT_ENTITY;
 121
 122                case SpecialEntityIdLegacyLiteral.FIRST_PERSON_CAMERA_ENTITY_REFERENCE:
 2123                    return (long) SpecialEntityId.FIRST_PERSON_CAMERA_ENTITY_REFERENCE;
 124
 125                case SpecialEntityIdLegacyLiteral.AVATAR_ENTITY_REFERENCE:
 2126                    return (long) SpecialEntityId.AVATAR_ENTITY_REFERENCE;
 127
 128                case SpecialEntityIdLegacyLiteral.AVATAR_POSITION_REFERENCE:
 2129                    return (long) SpecialEntityId.AVATAR_POSITION_REFERENCE;
 130
 131                case SpecialEntityIdLegacyLiteral.THIRD_PERSON_CAMERA_ENTITY_REFERENCE:
 2132                    return (long) SpecialEntityId.THIRD_PERSON_CAMERA_ENTITY_REFERENCE;
 133            }
 134
 135            // secondly, test if it was already seen in invalidEntities
 12136            if (invalidEntities.ContainsKey(entityId))
 137            {
 2138                return invalidEntities[entityId];
 139            }
 140            else
 141            {
 142                // generate the new ID, uses the mask 0x8000_0000
 10143                var newEntityIdLong = ++invalidEntityCounter | 0x80000000;
 144
 145                // store the mapping from newEntityIdLong->original
 10146                if (!entityIdToLegacyId.ContainsKey(newEntityIdLong))
 10147                    entityIdToLegacyId[newEntityIdLong] = entityId;
 148
 149                // store the mapping original->newEntityIdLong
 10150                invalidEntities.Add(entityId, newEntityIdLong);
 151
 10152                return newEntityIdLong;
 153            }
 154        }
 155    }
 156}