Merge branch 'master' into mathmerge
This commit is contained in:
@@ -112,19 +112,14 @@ namespace Content.Server.AI.Utility.Actions
|
||||
UpdateBlackboard(context);
|
||||
var considerations = GetConsiderations(context);
|
||||
DebugTools.Assert(considerations.Count > 0);
|
||||
// I used the IAUS video although I did have some confusion on how to structure it overall
|
||||
// as some of the slides seemed contradictory
|
||||
|
||||
// Ideally we should early-out each action as cheaply as possible if it's not valid
|
||||
|
||||
// We also need some way to tell if the action isn't going to
|
||||
// have a better score than the current action (if applicable) and early-out that way as well.
|
||||
|
||||
// 23:00 Building a better centaur
|
||||
// Overall structure is based on Building a better centaur
|
||||
// Ideally we should early-out each action as cheaply as possible if it's not valid, thus
|
||||
// the finalScore can only go down over time.
|
||||
|
||||
var finalScore = 1.0f;
|
||||
var minThreshold = min / Bonus;
|
||||
context.GetState<ConsiderationState>().SetValue(considerations.Count);
|
||||
// See 10:09 for this and the adjustments
|
||||
|
||||
foreach (var consideration in considerations)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Content.Server.AI.Operators;
|
||||
@@ -6,11 +6,13 @@ using Content.Server.AI.Utility.Actions;
|
||||
using Content.Server.AI.Utility.BehaviorSets;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States.Utility;
|
||||
using Content.Server.GameObjects.Components.Damage;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.EntitySystems.AI;
|
||||
using Content.Server.GameObjects.EntitySystems.AI.LoadBalancer;
|
||||
using Content.Server.GameObjects.EntitySystems.JobQueues;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Robust.Server.AI;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -63,6 +65,13 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
{
|
||||
SortActions();
|
||||
}
|
||||
|
||||
if (BehaviorSets.Count == 1 && !EntitySystem.Get<AiSystem>().IsAwake(this))
|
||||
{
|
||||
IoCManager.Resolve<IEntityManager>()
|
||||
.EventBus
|
||||
.RaiseEvent(EventSource.Local, new SleepAiMessage(this, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveBehaviorSet(Type behaviorSet)
|
||||
@@ -74,6 +83,13 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
BehaviorSets.Remove(behaviorSet);
|
||||
SortActions();
|
||||
}
|
||||
|
||||
if (BehaviorSets.Count == 0)
|
||||
{
|
||||
IoCManager.Resolve<IEntityManager>()
|
||||
.EventBus
|
||||
.RaiseEvent(EventSource.Local, new SleepAiMessage(this, true));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,38 +130,42 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
_planCooldownRemaining = PlanCooldown;
|
||||
_blackboard = new Blackboard(SelfEntity);
|
||||
_planner = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AiActionSystem>();
|
||||
if (SelfEntity.TryGetComponent(out DamageableComponent damageableComponent))
|
||||
if (SelfEntity.TryGetComponent(out IDamageableComponent damageableComponent))
|
||||
{
|
||||
damageableComponent.DamageThresholdPassed += DamageThresholdHandle;
|
||||
damageableComponent.HealthChangedEvent += DeathHandle;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
// TODO: If DamageableComponent removed still need to unsubscribe?
|
||||
if (SelfEntity.TryGetComponent(out DamageableComponent damageableComponent))
|
||||
if (SelfEntity.TryGetComponent(out IDamageableComponent damageableComponent))
|
||||
{
|
||||
damageableComponent.DamageThresholdPassed -= DamageThresholdHandle;
|
||||
damageableComponent.HealthChangedEvent -= DeathHandle;
|
||||
}
|
||||
|
||||
var currentOp = CurrentAction?.ActionOperators.Peek();
|
||||
currentOp?.Shutdown(Outcome.Failed);
|
||||
}
|
||||
|
||||
private void DamageThresholdHandle(object sender, DamageThresholdPassedEventArgs eventArgs)
|
||||
private void DeathHandle(HealthChangedEventArgs eventArgs)
|
||||
{
|
||||
if (!SelfEntity.TryGetComponent(out SpeciesComponent speciesComponent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var oldDeadState = _isDead;
|
||||
_isDead = eventArgs.Damageable.CurrentDamageState == DamageState.Dead || eventArgs.Damageable.CurrentDamageState == DamageState.Critical;
|
||||
|
||||
if (speciesComponent.CurrentDamageState is DeadState)
|
||||
if (oldDeadState != _isDead)
|
||||
{
|
||||
_isDead = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isDead = false;
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
switch (_isDead)
|
||||
{
|
||||
case true:
|
||||
entityManager.EventBus.RaiseEvent(EventSource.Local, new SleepAiMessage(this, true));
|
||||
break;
|
||||
case false:
|
||||
entityManager.EventBus.RaiseEvent(EventSource.Local, new SleepAiMessage(this, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,16 +200,6 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
// If we can't do anything then there's no point thinking
|
||||
if (_isDead || BehaviorSets.Count == 0)
|
||||
{
|
||||
_actionCancellation?.Cancel();
|
||||
_blackboard.GetState<LastUtilityScoreState>().SetValue(0.0f);
|
||||
CurrentAction?.Shutdown();
|
||||
CurrentAction = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we asked for a new action we don't want to dump the existing one.
|
||||
if (_actionRequest != null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
@@ -11,13 +11,12 @@ namespace Content.Server.AI.Utility.Considerations.Combat
|
||||
{
|
||||
var target = context.GetState<TargetEntityState>().GetValue();
|
||||
|
||||
if (target == null || !target.TryGetComponent(out DamageableComponent damageableComponent))
|
||||
if (target == null || !target.TryGetComponent(out IDamageableComponent damageableComponent))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Just went with max health
|
||||
return damageableComponent.CurrentDamage[DamageType.Total] / 300.0f;
|
||||
return damageableComponent.TotalDamage / 300.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
|
||||
namespace Content.Server.AI.Utility.Considerations.Combat
|
||||
{
|
||||
@@ -10,12 +10,12 @@ namespace Content.Server.AI.Utility.Considerations.Combat
|
||||
{
|
||||
var target = context.GetState<TargetEntityState>().GetValue();
|
||||
|
||||
if (target == null || !target.TryGetComponent(out SpeciesComponent speciesComponent))
|
||||
if (target == null || !target.TryGetComponent(out IDamageableComponent damageableComponent))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (speciesComponent.CurrentDamageState is CriticalState)
|
||||
if (damageableComponent.CurrentDamageState == DamageState.Critical)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
|
||||
namespace Content.Server.AI.Utility.Considerations.Combat
|
||||
{
|
||||
@@ -10,12 +10,12 @@ namespace Content.Server.AI.Utility.Considerations.Combat
|
||||
{
|
||||
var target = context.GetState<TargetEntityState>().GetValue();
|
||||
|
||||
if (target == null || !target.TryGetComponent(out SpeciesComponent speciesComponent))
|
||||
if (target == null || !target.TryGetComponent(out IDamageableComponent damageableComponent))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (speciesComponent.CurrentDamageState is DeadState)
|
||||
if (damageableComponent.CurrentDamageState == DamageState.Dead)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@@ -13,18 +13,27 @@ namespace Content.Server.AI.Utility.Considerations
|
||||
private float GetAdjustedScore(Blackboard context)
|
||||
{
|
||||
var score = GetScore(context);
|
||||
/*
|
||||
* Now using the geometric mean
|
||||
* for n scores you take the n-th root of the scores multiplied
|
||||
* e.g. a, b, c scores you take Math.Pow(a * b * c, 1/3)
|
||||
* To get the ACTUAL geometric mean at any one stage you'd need to divide by the running consideration count
|
||||
* however, the downside to this is it will fluctuate up and down over time.
|
||||
* For our purposes if we go below the minimum threshold we want to cut it off, thus we take a
|
||||
* "running geometric mean" which can only ever go down (and by the final value will equal the actual geometric mean).
|
||||
*/
|
||||
|
||||
// Previously we used a makeupvalue method although the geometric mean is less punishing for more considerations
|
||||
var considerationsCount = context.GetState<ConsiderationState>().GetValue();
|
||||
var modificationFactor = 1.0f - 1.0f / considerationsCount;
|
||||
var makeUpValue = (1.0f - score) * modificationFactor;
|
||||
var adjustedScore = score + makeUpValue * score;
|
||||
return MathHelper.Clamp(adjustedScore, 0.0f, 1.0f);
|
||||
var adjustedScore = MathF.Pow(score, 1 / (float) considerationsCount);
|
||||
return FloatMath.Clamp(adjustedScore, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private static float BoolCurve(float x)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
return x == 1.0f ? 1.0f : 0.0f;
|
||||
return x > 0.0f ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
public Func<float> BoolCurve(Blackboard context)
|
||||
@@ -42,7 +51,7 @@ namespace Content.Server.AI.Utility.Considerations
|
||||
private static float InverseBoolCurve(float x)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
return x == 1.0f ? 0.0f : 1.0f;
|
||||
return x == 0.0f ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
public Func<float> InverseBoolCurve(Blackboard context)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.AI.Utility.Actions;
|
||||
using Content.Server.AI.Utility.Actions.Combat.Melee;
|
||||
@@ -7,8 +7,8 @@ using Content.Server.AI.Utility.Considerations.Combat.Melee;
|
||||
using Content.Server.AI.Utils;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(owner.Transform.GridPosition, typeof(SpeciesComponent),
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(owner.Transform.GridPosition, typeof(IDamageableComponent),
|
||||
controller.VisionRadius))
|
||||
{
|
||||
if (entity.HasComponent<BasicActorComponent>() && entity != owner)
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
|
||||
{
|
||||
var owner = context.GetState<SelfState>().GetValue();
|
||||
|
||||
foreach (var entity in context.GetState<NearbySpeciesState>().GetValue())
|
||||
foreach (var entity in context.GetState<NearbyBodiesState>().GetValue())
|
||||
{
|
||||
yield return new MeleeWeaponAttackEntity(owner, entity, Bonus);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.AI.Utility.Actions;
|
||||
using Content.Server.AI.Utility.Actions.Combat.Melee;
|
||||
@@ -7,8 +7,8 @@ using Content.Server.AI.Utility.Considerations.Combat.Melee;
|
||||
using Content.Server.AI.Utils;
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(owner.Transform.GridPosition, typeof(SpeciesComponent),
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(owner.Transform.GridPosition, typeof(IBodyManagerComponent),
|
||||
controller.VisionRadius))
|
||||
{
|
||||
if (entity.HasComponent<BasicActorComponent>() && entity != owner)
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace Content.Server.AI.WorldState.States.Inventory
|
||||
{
|
||||
foreach (var item in handsComponent.GetAllHeldItems())
|
||||
{
|
||||
if (item.Owner.Deleted)
|
||||
continue;
|
||||
|
||||
yield return item.Owner;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.AI.Utils;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Mobs
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class NearbySpeciesState : CachedStateData<List<IEntity>>
|
||||
public sealed class NearbyBodiesState : CachedStateData<List<IEntity>>
|
||||
{
|
||||
public override string Name => "NearbySpecies";
|
||||
public override string Name => "NearbyBodies";
|
||||
|
||||
protected override List<IEntity> GetTrueValue()
|
||||
{
|
||||
@@ -21,7 +21,7 @@ namespace Content.Server.AI.WorldState.States.Mobs
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(Owner.Transform.GridPosition, typeof(SpeciesComponent), controller.VisionRadius))
|
||||
foreach (var entity in Visibility.GetEntitiesInRange(Owner.Transform.GridPosition, typeof(IBodyManagerComponent), controller.VisionRadius))
|
||||
{
|
||||
if (entity == Owner) continue;
|
||||
result.Add(entity);
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -27,7 +27,7 @@ namespace Content.Server.AI.WorldState.States.Mobs
|
||||
|
||||
foreach (var player in nearbyPlayers)
|
||||
{
|
||||
if (player.AttachedEntity != Owner && player.AttachedEntity.HasComponent<SpeciesComponent>())
|
||||
if (player.AttachedEntity != Owner && player.AttachedEntity.HasComponent<IDamageableComponent>())
|
||||
{
|
||||
result.Add(player.AttachedEntity);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user