Example #1
0
        //Public and static because it's referenced in a unit test. That design oddity is
        //worth the absolute critical design fault that was uncovered and now protected by a test.
        public static unsafe IEntityDataFieldContainer CreateInitialEntityFieldContainer(FieldValueUpdate fieldValueData)
        {
            //TODO: We could pool this.
            //we actually CAN'T use the field enum length or count. Since TrinityCore may send additional bytes at the end so that
            //it's evently divisible by 32.
            byte[] internalEntityDataBytes = new byte[fieldValueData.FieldValueUpdateMask.Length * sizeof(int)];

            //It's absolutely CRITICAL that we don't use the sent fieldvalue internal bits for the set indication data
            //BECAUSE it also will be used as the initial changed values/change array. So we do the one-time copy here to avoid this critical
            //fault which is now covered by tests.
            byte[] copiedFieldUpdateMask = new byte[fieldValueData.FieldValueUpdateMask.InternalIntegerArray.Count];
            Buffer.BlockCopy(fieldValueData.FieldValueUpdateMask.InternalIntegerArray.ToArrayTryAvoidCopy(), 0, copiedFieldUpdateMask, 0, fieldValueData.FieldValueUpdateMask.InternalIntegerArray.Count);

            IEntityDataFieldContainer t = new EntityFieldDataCollection(new WireReadyBitArray(copiedFieldUpdateMask), internalEntityDataBytes);

            int updateDiffIndex = 0;

            foreach (int setIndex in t.DataSetIndicationArray.EnumerateSetBitsByIndex())
            {
                int   value = fieldValueData.FieldValueUpdates.ElementAt(updateDiffIndex);
                byte *bytes = (byte *)&value;

                //TODO: Would it be faster to buffer copy?
                //The way wow works is these are 4 byte chunks
                for (int i = 0; i < 4; i++)
                {
                    internalEntityDataBytes[setIndex * sizeof(int) + i] = *(bytes + i);
                }

                updateDiffIndex++;
            }

            return(t);
        }
Example #2
0
        public FullCharacterDataSaveRequest(bool shouldReleaseCharacterSession, bool isPositionSaved, [NotNull] ZoneServerCharacterLocationSaveRequest characterLocationData, [NotNull] EntityFieldDataCollection playerDataSnapshot)
        {
            ShouldReleaseCharacterSession = shouldReleaseCharacterSession;
            this.isPositionSaved          = isPositionSaved;
            CharacterLocationData         = characterLocationData ?? throw new ArgumentNullException(nameof(characterLocationData));
            PlayerDataSnapshot            = playerDataSnapshot ?? throw new ArgumentNullException(nameof(playerDataSnapshot));

            //Snapshot current time.
            UtcTickTimeStamp = DateTime.UtcNow.Ticks;
        }
Example #3
0
        protected override void OnEventFired(object source, EntityCreationRequestedEventArgs args)
        {
            NetworkEntityGuid guid = args.EntityGuid;

            //TODO: handle non-players
            //TODO: Fix the issue with having to hardcore the field count.
            //Build the update values stuff and initialize the initial movement data.
            EntityFieldDataCollection container = new EntityFieldDataCollection(ComputeEntityDataFieldLength(args.EntityGuid));

            DataCollectionMappable.AddObject(guid, container);
            ChangeTrackableCollection.AddObject(guid, new ChangeTrackingEntityFieldDataCollectionDecorator(container));
            EntityDataContainer.AddObject(guid, ChangeTrackableCollection.RetrieveEntity(guid));
        }
Example #4
0
        /// <inheritdoc />
        public async Task SaveAsync(NetworkEntityGuid guid)
        {
            //We can only handle players at the moment, not sure how NPC data would be saved.
            if (guid.EntityType != EntityType.Player)
            {
                return;
            }

            //Player ALWAYS has this existing.
            EntitySaveableConfiguration saveConfig = PersistenceConfiguration.RetrieveEntity(guid);
            EntityFieldDataCollection   entityData = EntityDataMappable.RetrieveEntity(guid);

            await ZonePersistenceQueueable.SaveFullCharacterDataAsync(guid.EntityId, new FullCharacterDataSaveRequest(true, saveConfig.isCurrentPositionSaveable, CreatedLocationSaveData(guid), entityData));

            //We cleanup player data on the zoneserver in a different place
            //here, because we needed it until this very last moment.
            foreach (var ed in DataCollections)
            {
                ed.RemoveEntityEntry(guid);
            }
        }
Example #5
0
        public void Test_Can_Register_Long_Callback_With_Correct_Value()
        {
            //arrange
            Mock <IEnumerable>              testCallback    = new Mock <IEnumerable>(MockBehavior.Loose);
            IEntityDataFieldContainer       fieldData       = new EntityFieldDataCollection(8);
            EntityDataChangeCallbackManager callbackManager = new EntityDataChangeCallbackManager();

            fieldData.SetFieldValue(1, new NetworkEntityGuid(ulong.MaxValue));

            //act
            callbackManager.RegisterCallback <ulong>(new NetworkEntityGuid((ulong)1), 1, (eg, args) =>
            {
                Assert.AreEqual(ulong.MaxValue, args.NewValue);

                //Call so we can check for test purposes
                testCallback.Object.GetEnumerator();
            });

            callbackManager.InvokeChangeEvents(new NetworkEntityGuid((ulong)1), fieldData, 1);

            //assert
            testCallback.Verify(enumerable => enumerable.GetEnumerator(), Times.Once);
        }