Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
184 changes: 167 additions & 17 deletions Components/SAIN Bot Component/Classes/Objects/SAINEnemyClass.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using EFT;
using BepInEx.Logging;
using EFT;
using SAIN.Components;
using static SAIN.UserSettings.VisionConfig;
using SAIN.Helpers;
using UnityEngine;
using UnityEngine.AI;
Expand All @@ -15,60 +17,208 @@ public SAINEnemy(BotOwner bot, IAIDetails person)
{
BotOwner = bot;
Person = person;
Logger = BepInEx.Logging.Logger.CreateLogSource(GetType().Name);
}

private readonly ManualLogSource Logger;

public void Update()
{
UpdateDistance();
UpdateVisible();
UpdatePath();
}

private float RayCastFreq
{
get
{
const float CloseCap = 10f;
const float FarCap = 90f;
const float baseTime = 0.1f;
const float baseTimeAdd = 0.2f;
const float maxTime = 0.5f;

float distance = DistanceFromLastSeen;

float clampedClose = Mathf.Clamp(distance, 0f, CloseCap);
float scaled = clampedClose / CloseCap;
scaled *= baseTimeAdd;
scaled += baseTime;

float result = scaled;

if (distance > CloseCap)
{
float clampedFar = Mathf.Clamp(distance - CloseCap, 0f, FarCap);
float farScale = clampedFar / FarCap;
farScale *= baseTimeAdd;
result += farScale;
}

float clampedResult = Mathf.Clamp(result, 0f, maxTime);

if (DebugTimer < Time.time && DebugVision.Value && Person.GetPlayer.ProfileId == Plugin.MainPlayer.ProfileId)
{
DebugTimer = Time.time + 1f;
Logger.LogDebug($"RayCast Frequency result: [{clampedResult}]");
}
return clampedResult;
}
}

private float DebugTimer = 0f;

private void UpdateDistance()
{
if (DistanceTimer < Time.time)
{
DistanceTimer = Time.time + 0.25f;
float distance = GetMagnitudeToBot(Position);
RealDistance = distance;
LastSeenDistance = IsVisible ? distance : GetMagnitudeToBot(PositionLastSeen);
DistanceFromLastSeen = IsVisible ? 0f : (PositionLastSeen - Position).magnitude;
}
}

public float DistanceFromLastSeen { get; private set; }
public Vector3 Position => Person.Position;

private float GetMagnitudeToBot(Vector3 point)
{
return (BotOwner.Position - point).magnitude;
}

public float RealDistance { get; private set; }
public float LastSeenDistance { get; private set; }
public Vector3 PositionLastSeen { get; private set; }
public float TimeSinceSeen { get; private set; }
public float TimeSeen { get; private set; }
public bool Seen { get; private set; }
public float TimeFirstSeen { get; private set; }
public float TimeLastSeen { get; private set; }

private float DistanceTimer = 0f;
private bool Reacting = false;
private float ReactionTimer = 0f;

private void UpdateVisible()
{
if (CheckVisibleTimer < Time.time)
{
CheckVisibleTimer = Time.time + 0.15f;

bool lineOfSight = CheckEnemyVisible();
CheckVisibleTimer = Time.time + RayCastFreq;

bool lineOfSight = false;
bool visible = false;
if (lineOfSight == true && GoalEnemy?.IsVisible == true)
bool wasVisible = IsVisible;

if (CheckPartsVisible())
{
visible = BotOwner.LookSensor.IsPointInVisibleSector(Person.Position);
lineOfSight = true;
if (GoalEnemy?.IsVisible == true && BotOwner.LookSensor.IsPointInVisibleSector(Person.Position))
{
if (!Reacting)
{
Reacting = true;
ReactionTimer = Time.time + 0.2f;
}
else
{
if (ReactionTimer < Time.time)
{
visible = true;
}
}
}
}
if (visible == true)
{
TimeSeen = Time.time;
if (!Seen)
{
TimeFirstSeen = Time.time;
Seen = true;
}
}
if (visible == false)
{
if (wasVisible)
{
TimeLastSeen = Time.time;
PositionLastSeen = Person.Position;
}
if (Seen)
{
TimeSinceSeen = Time.time - TimeLastSeen;
}
Reacting = false;
}

IsVisible = visible;
InLineOfSight = lineOfSight;
IsVisible = visible;
}
}

private bool CheckEnemyVisible()
private bool CheckPartsVisible()
{
Vector3 HeadPosition = BotOwner.LookSensor._headPoint;
float distance = (Person.Position - BotOwner.Position).magnitude;
float maxDistance = BotOwner.Settings.Current.CurrentVisibleDistance;

LayerMask Mask;

if (distance < 10f)
{
Mask = LayerMaskClass.HighPolyWithTerrainMask;
}
else
if (distance >= maxDistance)
{
Mask = LayerMaskClass.HighPolyWithTerrainMaskAI;
return false;
}

var NoFoliageMask = LayerMaskClass.HighPolyWithTerrainMask;
var FoliageMask = LayerMaskClass.HighPolyWithTerrainMaskAI;
LayerMask Mask = distance < 5f ? NoFoliageMask : FoliageMask;

foreach (var part in Person.MainParts.Values)
{
Vector3 partPos = part.Position;
Vector3 Direction = partPos - HeadPosition;
if (!Physics.Raycast(HeadPosition, Direction, Direction.magnitude, Mask))
float visionCap = Mathf.Clamp(Direction.magnitude, 0f, BotOwner.Settings.Current.CurrentVisibleDistance);
if (!Physics.Raycast(HeadPosition, Direction, out var hit, visionCap, Mask))
{
var weapon = BotOwner.WeaponRoot.position;
Direction = partPos - weapon;
CanShoot = !Physics.Raycast(weapon, Direction, Direction.magnitude, Mask);

if (DebugVision.Value && Mask == NoFoliageMask)
{
DebugGizmos.SingleObjects.Line(HeadPosition, EnemyChestPosition, Color.red, 0.01f, true, 1f, true);
Logger.LogDebug($"[{BotOwner.name}] can see through foliage because distance < 5f");
}

return true;
}
else
{
if (Mask == LayerMaskClass.HighPolyWithTerrainMaskAI)
{
Vector3 hitPos = hit.point;
Vector3 hitToTarget = part.Position - hitPos;
if (hitToTarget.magnitude < 1f)
{
Vector3 directionAwayFromTarget = -hitToTarget.normalized * 0.1f;
Vector3 newRayPos = hitPos + directionAwayFromTarget;
Direction = part.Position - newRayPos;
if (!Physics.Raycast(newRayPos, Direction.normalized, Direction.magnitude, LayerMaskClass.HighPolyWithTerrainMask))
{
if (DebugVision.Value)
{
DebugGizmos.SingleObjects.Line(newRayPos, EnemyChestPosition, Color.red, 0.01f, true, 1f, true);
Logger.LogDebug($"[{BotOwner.name}] can see through foliage because distance < 1f");
}

return true;
}
}

//Vector3 StartToHit = hitPos - HeadPosition;
}
}
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ public class SearchMoveObject : SAINBot

public SearchMoveObject(BotOwner bot, NavMeshAgent agent) : base(bot)
{
Logger = BepInEx.Logging.Logger.CreateLogSource(GetType().Name);
Agent = agent;
Logger = BepInEx.Logging.Logger.CreateLogSource(GetType().Name);
}

private readonly ManualLogSource Logger;

public bool Update(float reachDist = -1f)
{
if (CornerDestination != null && Destination != null)
Expand Down Expand Up @@ -287,8 +289,6 @@ private float GetSignedAngle(Vector3 dirCenter, Vector3 dirOther, Vector3? axis
public Vector3[] PathWay { get; private set; }
public int PathWayIndex { get; private set; }
public int PathWayIndexMax { get; private set; }

private readonly ManualLogSource Logger;
}

public class MoveDangerPoint
Expand Down
43 changes: 1 addition & 42 deletions Components/SAIN Bot Component/SAINComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,33 +87,6 @@ private void UpdateEnemy()

public SAINEnemy Enemy { get; private set; }

public bool ShiftAwayFromCloseWall(Vector3 target, out Vector3 newPos)
{
const float closeDist = 0.75f;

if (CheckTooCloseToWall(target, out var rayHit, closeDist))
{
var direction = (BotOwner.Position - rayHit.point).normalized * 0.8f;
direction.y = 0f;
var movePoint = BotOwner.Position + direction;
if (NavMesh.SamplePosition(movePoint, out var hit, 0.1f, -1))
{
newPos = hit.position;
return true;
}
}
newPos = Vector3.zero;
return false;
}

public bool CheckTooCloseToWall(Vector3 target, out RaycastHit rayHit, float checkDist = 0.75f)
{
Vector3 botPos = BotOwner.Position;
Vector3 direction = target - botPos;
botPos.y = WeaponRoot.y;
return Physics.Raycast(BotOwner.Position, direction, out rayHit, checkDist, LayerMaskClass.HighPolyWithTerrainMask);
}

public void Dispose()
{
StopAllCoroutines();
Expand All @@ -138,25 +111,11 @@ public void Dispose()
public Vector3? GoalTargetPos => BotOwner.Memory.GoalTarget?.GoalTarget?.Position;
public Vector3? GoalEnemyPos => BotOwner.Memory.GoalEnemy?.CurrPosition;

public Vector3 MidPoint(Vector3 target, float lerpVal = 0.5f)
{
return Vector3.Lerp(BotOwner.Position, target, lerpVal);
}
public bool BotIsAtPoint(Vector3 point, float reachDist = 1f)
{
return DistanceToDestination(point) < reachDist;
}

public float DistanceToDestination(Vector3 point)
{
return Vector3.Distance(point, BotOwner.Transform.position);
}

public bool BotHasStamina => BotOwner.GetPlayer.Physical.Stamina.NormalValue > 0f;

public Vector3 UnderFireFromPosition { get; set; }

public bool HasEnemyAndCanShoot => BotOwner.Memory.GoalEnemy?.CanShoot == true && BotOwner.Memory.GoalEnemy?.IsVisible == true;
public bool HasEnemyAndCanShoot => Enemy?.IsVisible == true;

public AILimitClass AILimit { get; private set; }

Expand Down
8 changes: 7 additions & 1 deletion Config/VisionConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal class VisionConfig
public static ConfigEntry<float> AbsoluteMaxVisionDistance { get; private set; }
public static ConfigEntry<bool> NoGlobalFog { get; private set; }
public static ConfigEntry<bool> DebugWeather { get; private set; }
public static ConfigEntry<bool> DebugVision { get; private set; }

public static void Init(ConfigFile Config)
{
Expand All @@ -22,7 +23,12 @@ public static void Init(ConfigFile Config)
new AcceptableValueRange<float>(100f, 800.0f),
new ConfigurationManagerAttributes { IsAdvanced = true, Order = 2 }));

DebugWeather = Config.Bind(debugmode, "Debug Logs", false,
DebugWeather = Config.Bind(debugmode, "Debug Weather", false,
new ConfigDescription("",
null,
new ConfigurationManagerAttributes { IsAdvanced = true, Order = 1 }));

DebugVision = Config.Bind(debugmode, "Debug Vision", false,
new ConfigDescription("",
null,
new ConfigurationManagerAttributes { IsAdvanced = true, Order = 1 }));
Expand Down