//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); }
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; }
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)); }
/// <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); } }
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); }