/// <inheritdoc /> public override Task HandleMessage(IPeerMessageContext <GameClientPacketPayload> context, FieldValueUpdateEvent payload) { //Assume the update fields aren't null and there is at least 1 foreach (EntityAssociatedData <FieldValueUpdate> update in payload.FieldValueUpdates) { //TODO: We shouldn't assume we know the entity, but technically we should based on order of server-side events. IEntityDataFieldContainer entityDataContainer = null; try { entityDataContainer = EntityDataContainerMap[update.EntityGuid]; } catch (Exception e) { if (Logger.IsWarnEnabled) { Logger.Warn($"Encountered Entity FieldValueUpdate for Unknown Entity: {update.EntityGuid.EntityType}:{update.EntityGuid.EntityId}. Error: {e.Message}"); } throw; } //We have to lock here otherwise we could encounter race conditions with the //change tracking system. lock (entityDataContainer.SyncObj) foreach (var entry in update.Data.FieldValueUpdateMask .EnumerateSetBitsByIndex() .Zip(update.Data.FieldValueUpdates, (setIndex, value) => new { setIndex, value })) { entityDataContainer.SetFieldValue(entry.setIndex, entry.value); } } return(Task.CompletedTask); }
public BaseEntityBehaviourComponent Create([NotNull] NetworkEntityGuid context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } IEntityDataFieldContainer dataFieldContainer = EntityDataMappable.RetrieveEntity(context); GameObject worldObject = WorldObjectMappable.RetrieveEntity(context); Type behaviourType = ComputeExpectedBehaviourType(dataFieldContainer.GetEnumFieldValue <GameObjectType>(GameObjectField.GAMEOBJECT_TYPE_ID)); using (var scope = ReflectionContainer.BeginLifetimeScope(cb => { cb.RegisterInstance(context) .AsSelf(); cb.RegisterInstance(worldObject) .As <GameObject>(); cb.RegisterInstance(dataFieldContainer) .As <IEntityDataFieldContainer>() .As <IReadonlyEntityDataFieldContainer>() .SingleInstance(); cb.RegisterType(behaviourType); })) { return((BaseEntityBehaviourComponent)scope.Resolve(behaviourType)); } }
public BaseClientGameObjectEntityBehaviourComponent(NetworkEntityGuid targetEntity, [NotNull] GameObject rootSceneObject, [NotNull] IEntityDataFieldContainer data) : base(targetEntity) { RootSceneObject = rootSceneObject ?? throw new ArgumentNullException(nameof(rootSceneObject)); Data = data ?? throw new ArgumentNullException(nameof(data)); }
/// <summary> /// Helper extension for setting entity data in <see cref="IEntityDataFieldContainer"/> /// based on the int value of a specified Enum value <see cref="index"/>. /// </summary> /// <param name="container"></param> /// <param name="index"></param> /// <param name="guid"></param> public static void SetFieldValue(this IEntityDataFieldContainer container, int index, NetworkEntityGuid guid) { if (container == null) { throw new ArgumentNullException(nameof(container)); } container.SetFieldValue(index, guid.RawGuidValue); }
/// <summary> /// TODO: Doc /// </summary> /// <param name="container"></param> /// <param name="flag"></param> public static void RemoveBaseObjectFieldFlag(this IEntityDataFieldContainer container, BaseObjectFieldFlags flag) { if (container == null) { throw new ArgumentNullException(nameof(container)); } container.SetFieldValue(BaseObjectField.UNIT_FIELD_FLAGS, (int)((BaseObjectFieldFlags)container.GetFieldValue <int>(BaseObjectField.UNIT_FIELD_FLAGS) & ~flag)); }
protected override void OnEntityCreationFinished(EntityCreationFinishedEventArgs args) { IEntityDataFieldContainer entityData = EntityDataMappable.RetrieveEntity(args.EntityGuid); GameObjectTemplateModel objectTemplateModel = GameObjectTemplateMappable.RetrieveEntity(args.EntityGuid); //We should generally consider this field static. I cannot even IMAGINE how we'd handle a change to this field on either //client or server. entityData.SetFieldValue(GameObjectField.GAMEOBJECT_TYPE_ID, (int)objectTemplateModel.ObjectType); }
/// <summary> /// TODO: Doc /// </summary> /// <param name="container"></param> /// <param name="flag"></param> public static bool HasBaseObjectFieldFlag(this IEntityDataFieldContainer container, BaseObjectFieldFlags flag) { if (container == null) { throw new ArgumentNullException(nameof(container)); } return(((BaseObjectFieldFlags)container.GetFieldValue <int>(BaseObjectField.UNIT_FIELD_FLAGS) & flag) == flag); }
public DefaultAvatarPedestalGameObjectBehaviour(NetworkEntityGuid targetEntity, GameObject rootSceneObject, IEntityDataFieldContainer data, [NotNull] IFactoryCreatable <CustomModelLoaderCancelable, CustomModelLoaderCreationContext> avatarLoaderFactory, [NotNull] ILog logger) : base(targetEntity, rootSceneObject, data) { AvatarLoaderFactory = avatarLoaderFactory ?? throw new ArgumentNullException(nameof(avatarLoaderFactory)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); }
/// <summary> /// Helper extension for setting entity data in <see cref="IEntityDataFieldContainer"/> /// based on the int value of a specified Enum value <see cref="index"/>. /// </summary> /// <typeparam name="TEnumType"></typeparam> /// <param name="container"></param> /// <param name="index"></param> /// <param name="guid"></param> public static void SetFieldValue <TEnumType>(this IEntityDataFieldContainer container, TEnumType index, NetworkEntityGuid guid) where TEnumType : Enum { if (container == null) { throw new ArgumentNullException(nameof(container)); } container.SetFieldValue(GenericMath.Convert <TEnumType, int>(index), guid.RawGuidValue); }
public DefaultGameObjectActorState([NotNull] IEntityDataFieldContainer entityData, [NotNull] NetworkEntityGuid entityGuid, [NotNull] GameObjectInstanceModel instanceModel, [NotNull] GameObjectTemplateModel templateModel, [NotNull] InterestCollection interest) : base(entityData, entityGuid, interest) { InstanceModel = instanceModel ?? throw new ArgumentNullException(nameof(instanceModel)); TemplateModel = templateModel ?? throw new ArgumentNullException(nameof(templateModel)); }
private void GenericInitialValueTest(int index) { //arrange IEntityDataFieldContainer collection = CreateEntityDataCollection(); //act int value = collection.GetFieldValue <int>(index); //assert Assert.AreEqual(default(int), value, $"Value at Index: {index} is suppose to be zero or default value: {default(int)}."); }
private void OnTargetEntityHealthChanged(NetworkEntityGuid entity, EntityDataChangedArgs <int> args) { IEntityDataFieldContainer entityData = EntityDataMappable.RetrieveEntity(entity); //Ignore the changed value. int health = entityData.GetFieldValue <int>(EntityObjectField.UNIT_FIELD_HEALTH); int maxHealth = entityData.GetFieldValue <int>(EntityObjectField.UNIT_FIELD_MAXHEALTH); TargetUnitFrame.HealthBar.BarText.Text = $"{health} / {maxHealth}"; TargetUnitFrame.HealthBar.BarFillable.FillAmount = (float)health / maxHealth; }
/// <inheritdoc /> public DefaultEntityCreationContext(NetworkEntityGuid entityGuid, IMovementData movementData, EntityPrefab prefabType, [NotNull] IEntityDataFieldContainer entityData) { if (!Enum.IsDefined(typeof(EntityPrefab), prefabType)) { throw new InvalidEnumArgumentException(nameof(prefabType), (int)prefabType, typeof(EntityPrefab)); } EntityGuid = entityGuid ?? throw new ArgumentNullException(nameof(entityGuid)); MovementData = movementData ?? throw new ArgumentNullException(nameof(movementData)); PrefabType = prefabType; EntityData = entityData ?? throw new ArgumentNullException(nameof(entityData)); }
protected override void HandleMessage(EntityActorMessageContext messageContext, DefaultEntityActorStateContainer state, EntityActorInitializationSuccessMessage message) { //We should send ourselves the level initialization message because it takes care of stats CharacterDataInstance entity = InitialCharacterDataMappable.RetrieveEntity(state.EntityGuid); IEntityDataFieldContainer entityDataFieldContainer = state.EntityData; entityDataFieldContainer.SetFieldValue((int)PlayerObjectField.PLAYER_TOTAL_EXPERIENCE, entity.Experience); //Set the level from the initial experience data. messageContext.Entity.Tell(new SetEntityActorLevelMessage(LevelStrategy.ComputeLevelFromExperience(entity.Experience))); }
/// <summary> /// Helper extension for setting entity data in <see cref="IEntityDataFieldContainer"/> /// based on the int value of a specified Enum value <see cref="index"/>. /// </summary> /// <typeparam name="TEnumType"></typeparam> /// <typeparam name="TValueType"></typeparam> /// <param name="container"></param> /// <param name="index"></param> /// <param name="value"></param> public static void SetFieldValue <TEnumType, TValueType>(this IEntityDataFieldContainer container, TEnumType index, TValueType value) where TValueType : struct where TEnumType : Enum { if (container == null) { throw new ArgumentNullException(nameof(container)); } container.SetFieldValue(GenericMath.Convert <TEnumType, int>(index), value); }
protected override void OnEntityCreationFinished(EntityCreationFinishedEventArgs args) { IMovementData movementData = MovementDataMappable.RetrieveEntity(args.EntityGuid); IEntityDataFieldContainer dataFieldContainer = EntityDataMappable.RetrieveEntity(args.EntityGuid); EntityCreationData data = new EntityCreationData(args.EntityGuid, movementData, EntityDataUpdateFactory.Create(new EntityFieldUpdateCreationContext(dataFieldContainer, dataFieldContainer.DataSetIndicationArray))); var senderContext = new GenericSingleTargetMessageContext <PlayerSelfSpawnEventPayload>(args.EntityGuid, new PlayerSelfSpawnEventPayload(data)); Sender.Send(senderContext); }
public void Test_Value_Set_Same_Read_Value([EntityDataCollectionTestRange] int index, [Values(1, 2, 3, 4, 5, 6, 7, 8)] int value) { //arrange IEntityDataFieldContainer collection = CreateEntityDataCollection(); //act collection.SetFieldValue <int>(index, value); int getValue = collection.GetFieldValue <int>(index); //assert Assert.AreEqual(value, getValue, $"Set Value: {value} at Index: {index} was wrong Value: {getValue} instead."); }
private void GenericInitialValueTest <TValueType>(int index) where TValueType : struct { //arrange IEntityDataFieldContainer <TestFieldType> collection = CreateEntityDataCollection(); //act TValueType value = collection.GetFieldValue <TValueType>(index); //assert Assert.AreEqual(default(TValueType), value, $"Value at Index: {index} is suppose to be zero or default value: {default(TValueType)}."); }
/// <inheritdoc /> public NetworkEntityNowVisibleEventArgs Create(EntityCreationData context) { NetworkEntityGuid guid = context.EntityGuid; IEntityDataFieldContainer container = CreateInitialEntityFieldContainer(context.InitialFieldValues); ChangeTrackingEntityFieldDataCollectionDecorator trackingEntityFieldDataCollectionDecorator = new ChangeTrackingEntityFieldDataCollectionDecorator(container, context.InitialFieldValues.FieldValueUpdateMask); ChangeTrackableCollection.AddObject(guid, trackingEntityFieldDataCollectionDecorator); MovementBlockMappable.AddObject(guid, context.InitialMovementData); return(new NetworkEntityNowVisibleEventArgs(guid)); }
protected override void OnLocalPlayerTargetChanged(LocalPlayerTargetChangedEventArgs args) { IEntityDataFieldContainer entityData = EntityDataMappable.RetrieveEntity(args.TargetedEntity); EntityDataChangeCallbackService.RegisterCallback <int>(args.TargetedEntity, (int)BaseObjectField.UNIT_FIELD_LEVEL, OnTargetEntityLevelChanged); //Only initialize if we have their values if (entityData.DataSetIndicationArray.Get((int)BaseObjectField.UNIT_FIELD_LEVEL)) { OnTargetEntityLevelChanged(args.TargetedEntity, new EntityDataChangedArgs <int>(0, entityData.GetFieldValue <int>(BaseObjectField.UNIT_FIELD_LEVEL))); } }
public void Test_Value_Set_Multiple_Times_Is_Latest_Value([EntityDataCollectionTestRange] int index, [Values(1, 2, 3, 4, 5, 6, 7, 8)] int value) { //arrange IEntityDataFieldContainer collection = CreateEntityDataCollection(); //act collection.SetFieldValue <int>(index, 5000); //test set to 5000, will check the resulting end value collection.SetFieldValue <int>(index, value); int getValue = collection.GetFieldValue <int>(index); //assert Assert.AreEqual(value, getValue, $"Set Value: {value} at Index: {index} was wrong Value: {getValue} instead."); }
/// <inheritdoc /> protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, PlayerModelChangeRequestPayload payload, NetworkEntityGuid guid) { //At this point, the player wants to change his model. //However we really can't be sure it's a valid model //so we validate it before setting the model id. //TODO: Validate the model id. ProjectVersionStage.AssertAlpha(); IEntityDataFieldContainer entityDataFieldContainer = EntityFieldMap.RetrieveEntity(guid); //This change will be broadcast to anyone interested. entityDataFieldContainer.SetFieldValue(BaseObjectField.UNIT_FIELD_DISPLAYID, payload.ModelId); return(Task.CompletedTask); }
/// <inheritdoc /> public void InvokeChangeEvents(NetworkEntityGuid entity, IEntityDataFieldContainer fieldContainer, int field) { //We aren't watching ANY data changes for this particular entity. if (!CallbackMap.ContainsKey(entity)) { return; } //If we have any registered callbacks for this entity's data change we should dispatch it (they will all be called) if (CallbackMap[entity].ContainsKey(field)) { CallbackMap[entity][field]?.Invoke(fieldContainer); } }
protected override void OnEventFired(object source, EntityCreationStartingEventArgs args) { //Only do creatures. if (args.EntityGuid.EntityType != EntityType.Creature) { return; } IEntityDataFieldContainer dataContainer = EntityDataMappable.RetrieveEntity(args.EntityGuid); CreatureTemplateModel template = CreatureTemplateMappable.RetrieveEntity(args.EntityGuid); //Initialize the creature display model ID. dataContainer.SetFieldValue(BaseObjectField.UNIT_FIELD_DISPLAYID, template.ModelId); }
public void Test_DataIndexSetTracking_Indicates_Set_Indicies([EntityDataCollectionTestRange] int index1, [EntityDataCollectionTestRange] int index2, [Values(-1, 0, 1, 2)] int value1, [Values(-1, 0, 1, 2)] int value2) { //arrange IEntityDataFieldContainer collection = CreateEntityDataCollection(); //act collection.SetFieldValue <int>(index1, value1); collection.SetFieldValue <int>(index2, value2); bool isSet1 = collection.DataSetIndicationArray.Get(index1); bool isSet2 = collection.DataSetIndicationArray.Get(index2); //assert Assert.True(isSet1, $"Index: {index1} being set should have caused indication array to be set."); Assert.True(isSet2, $"Index: {index2} being set should have caused indication array to be set."); }
protected override void OnEntityCreationFinished(EntityCreationFinishedEventArgs args) { IEntityDataFieldContainer dataContainer = EntityDataMappable.RetrieveEntity(args.EntityGuid); switch (dataContainer.GetEnumFieldValue <GameObjectType>(GameObjectField.GAMEOBJECT_TYPE_ID)) { //Visual doesn't have behaviours case GameObjectType.Visual: return; default: CreateBehaviourComponent(args.EntityGuid); break; } }
protected override void OnEntityCreationFinished(EntityCreationFinishedEventArgs args) { IEntityDataFieldContainer data = EntityDataContainer.RetrieveEntity(args.EntityGuid); UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { var characterAppearance = await CharacterService.GetCharacterAppearance(args.EntityGuid.EntityId); //Even if the character has logged off we're just setting an unused data container so it's ok. if (characterAppearance.isSuccessful) { data.SetFieldValue(BaseObjectField.UNIT_FIELD_DISPLAYID, characterAppearance.Result.AvatarModelId); } }); }
/// <summary> /// Overloaded constructor which will actually take an initial <see cref="ChangeTrackingArray"/>. /// Useful for initial creation if you want initial values to be viewed as changes. /// </summary> /// <param name="entityDataCollection"></param> /// <param name="initialChangeTrackBitArray"></param> public ChangeTrackingEntityFieldDataCollectionDecorator(IEntityDataFieldContainer entityDataCollection, [NotNull] WireReadyBitArray initialChangeTrackBitArray) { if (initialChangeTrackBitArray == null) { throw new ArgumentNullException(nameof(initialChangeTrackBitArray)); } if (initialChangeTrackBitArray.Length != entityDataCollection.DataSetIndicationArray.Length) { throw new InvalidOperationException($"Cannot set fields in {nameof(ChangeTrackingEntityFieldDataCollectionDecorator)} since provided collections {nameof(entityDataCollection)} and {nameof(initialChangeTrackBitArray)} do not have matching lengths."); } EntityDataCollection = entityDataCollection ?? throw new ArgumentNullException(nameof(entityDataCollection)); ChangeTrackingArray = initialChangeTrackBitArray; //just the size of the initial data indiciation bitarray //TODO: Technically we can't ASSUME it has any changes, but probably more efficient to than to check. HasPendingChanges = true; }
protected override void OnLocalPlayerTargetChanged(LocalPlayerTargetChangedEventArgs args) { IEntityDataFieldContainer entityData = EntityDataMappable.RetrieveEntity(args.TargetedEntity); foreach (var unreg in Unregisterables) { unreg.Unregister(); } Unregisterables.Clear(); //Listen for both max and current health. Unregisterables.Add(EntityDataChangeCallbackService.RegisterCallback <int>(args.TargetedEntity, (int)EntityObjectField.UNIT_FIELD_HEALTH, OnTargetEntityHealthChanged)); Unregisterables.Add(EntityDataChangeCallbackService.RegisterCallback <int>(args.TargetedEntity, (int)EntityObjectField.UNIT_FIELD_MAXHEALTH, OnTargetEntityHealthChanged)); //Only initialize if we have their values if (entityData.DataSetIndicationArray.Get((int)EntityObjectField.UNIT_FIELD_HEALTH)) { OnTargetEntityHealthChanged(args.TargetedEntity, new EntityDataChangedArgs <int>(0, 0)); } }
public void Test_ChangeTracker_Doesnt_Set_Change_Bits_On_Same_Value_After_Clear_FieldValueUpdate() { //arrange WireReadyBitArray bitArray = new WireReadyBitArray(1328); bitArray.Set(1, true); bitArray.Set(2, true); bitArray.Set(4, true); //Reference the actual client's visibile field update computation. IEntityDataFieldContainer dataCollection = NetworkVisibilityCreationBlockToVisibilityEventFactory.CreateInitialEntityFieldContainer(new FieldValueUpdate(bitArray, new int[] { 5, 4, 7 })); ChangeTrackingEntityFieldDataCollectionDecorator collection = new ChangeTrackingEntityFieldDataCollectionDecorator(dataCollection, bitArray); FieldValueUpdateFactory updateFactory = new FieldValueUpdateFactory(); //act FieldValueUpdate fieldValueUpdate = updateFactory.Create(new EntityFieldUpdateCreationContext(collection, collection.ChangeTrackingArray)); Assert.AreEqual(3, fieldValueUpdate.FieldValueUpdateMask.EnumerateSetBitsByIndex().Count(), $"Found more than 1 set bit."); Assert.AreEqual(5, fieldValueUpdate.FieldValueUpdates.First(), $"Serialized value was not expected value."); Assert.AreEqual(1, fieldValueUpdate.FieldValueUpdateMask.EnumerateSetBitsByIndex().First(), $"Index: {1} was expected to be first index."); collection.ClearTrackedChanges(); //Check they're event before setting them again Assert.AreEqual(collection.GetFieldValue <int>(1), 5, $"Values not the same."); Assert.AreEqual(collection.GetFieldValue <int>(2), 4, $"Values not the same."); collection.SetFieldValue(1, 5); collection.SetFieldValue(2, 4); fieldValueUpdate = updateFactory.Create(new EntityFieldUpdateCreationContext(collection, collection.ChangeTrackingArray)); //assert Assert.AreEqual(0, fieldValueUpdate.FieldValueUpdateMask.EnumerateSetBitsByIndex().Count(), $"Found more than 1 set bit."); Assert.AreEqual(0, fieldValueUpdate.FieldValueUpdates.Count, $"Field updates should be empty due to no changes.."); }