diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs
index 2e8d128c3..5bc49abc8 100644
--- a/Dalamud/Game/ClientState/ClientState.cs
+++ b/Dalamud/Game/ClientState/ClientState.cs
@@ -1,6 +1,8 @@
+using System.Linq;
using System.Runtime.InteropServices;
using Dalamud.Data;
+using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.Gui;
@@ -123,6 +125,27 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
/// Gets client state address resolver.
///
internal ClientStateAddressResolver AddressResolver => this.address;
+
+ ///
+ public bool IsClientIdle(out ConditionFlag blockingFlag)
+ {
+ blockingFlag = 0;
+ if (this.LocalPlayer is null) return true;
+
+ var condition = Service.GetNullable();
+
+ var blockingConditions = condition.AsReadOnlySet().Except([
+ ConditionFlag.NormalConditions,
+ ConditionFlag.Jumping,
+ ConditionFlag.Mounted,
+ ConditionFlag.UsingParasol]);
+
+ blockingFlag = blockingConditions.FirstOrDefault();
+ return blockingFlag == 0;
+ }
+
+ ///
+ public bool IsClientIdle() => this.IsClientIdle(out _);
///
/// Dispose of managed and unmanaged resources.
@@ -271,6 +294,12 @@ internal class ClientStatePluginScoped : IInternalDisposableService, IClientStat
///
public bool IsGPosing => this.clientStateService.IsGPosing;
+ ///
+ public bool IsClientIdle(out ConditionFlag blockingFlag) => this.clientStateService.IsClientIdle(out blockingFlag);
+
+ ///
+ public bool IsClientIdle() => this.clientStateService.IsClientIdle();
+
///
void IInternalDisposableService.DisposeService()
{
diff --git a/Dalamud/Game/ClientState/Conditions/Condition.cs b/Dalamud/Game/ClientState/Conditions/Condition.cs
index faafe05e0..b5cb77275 100644
--- a/Dalamud/Game/ClientState/Conditions/Condition.cs
+++ b/Dalamud/Game/ClientState/Conditions/Condition.cs
@@ -71,6 +71,22 @@ internal sealed class Condition : IInternalDisposableService, ICondition
///
void IInternalDisposableService.DisposeService() => this.Dispose(true);
+
+ ///
+ public IReadOnlySet AsReadOnlySet()
+ {
+ var result = new HashSet();
+
+ for (var i = 0; i < MaxConditionEntries; i++)
+ {
+ if (this[i])
+ {
+ result.Add((ConditionFlag)i);
+ }
+ }
+
+ return result;
+ }
///
public bool Any()
@@ -100,37 +116,26 @@ internal sealed class Condition : IInternalDisposableService, ICondition
return false;
}
+
+ ///
+ public bool AnyExcept(params ConditionFlag[] excluded)
+ {
+ return !this.AsReadOnlySet().Intersect(excluded).Any();
+ }
///
public bool OnlyAny(params ConditionFlag[] other)
{
- var resultSet = this.AsReadOnlySet();
- return !resultSet.Except(other).Any();
+ return !this.AsReadOnlySet().Except(other).Any();
}
///
- public bool OnlyAll(params ConditionFlag[] other)
+ public bool EqualTo(params ConditionFlag[] other)
{
var resultSet = this.AsReadOnlySet();
return resultSet.SetEquals(other);
}
- ///
- public IReadOnlySet AsReadOnlySet()
- {
- var result = new HashSet();
-
- for (var i = 0; i < MaxConditionEntries; i++)
- {
- if (this[i])
- {
- result.Add((ConditionFlag)i);
- }
- }
-
- return result;
- }
-
private void Dispose(bool disposing)
{
if (this.isDisposed)
@@ -217,12 +222,15 @@ internal class ConditionPluginScoped : IInternalDisposableService, ICondition
///
public bool Any(params ConditionFlag[] flags) => this.conditionService.Any(flags);
+
+ ///
+ public bool AnyExcept(params ConditionFlag[] except) => this.conditionService.AnyExcept(except);
///
public bool OnlyAny(params ConditionFlag[] other) => this.conditionService.OnlyAny(other);
///
- public bool OnlyAll(params ConditionFlag[] other) => this.conditionService.OnlyAll(other);
+ public bool EqualTo(params ConditionFlag[] other) => this.conditionService.EqualTo(other);
private void ConditionChangedForward(ConditionFlag flag, bool value) => this.ConditionChange?.Invoke(flag, value);
}
diff --git a/Dalamud/Plugin/Services/IClientState.cs b/Dalamud/Plugin/Services/IClientState.cs
index 95d5259e6..089a78d42 100644
--- a/Dalamud/Plugin/Services/IClientState.cs
+++ b/Dalamud/Plugin/Services/IClientState.cs
@@ -1,3 +1,4 @@
+using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.SubKinds;
namespace Dalamud.Plugin.Services;
@@ -81,4 +82,19 @@ public interface IClientState
/// Gets a value indicating whether the client is currently in Group Pose (GPose) mode.
///
public bool IsGPosing { get; }
+
+ ///
+ /// Check whether the client is currently "idle". This means a player is not logged in, or is notctively in combat
+ /// or doing anything that we may not want to disrupt.
+ ///
+ /// An outvar containing the first observed condition blocking the "idle" state. 0 if idle.
+ /// Returns true if the client is idle, false otherwise.
+ public bool IsClientIdle(out ConditionFlag blockingFlag);
+
+ ///
+ /// Check whether the client is currently "idle". This means a player is not logged in, or is notctively in combat
+ /// or doing anything that we may not want to disrupt.
+ ///
+ /// Returns true if the client is idle, false otherwise.
+ public bool IsClientIdle() => this.IsClientIdle(out _);
}
diff --git a/Dalamud/Plugin/Services/ICondition.cs b/Dalamud/Plugin/Services/ICondition.cs
index 7215cdac6..4ea9e7f76 100644
--- a/Dalamud/Plugin/Services/ICondition.cs
+++ b/Dalamud/Plugin/Services/ICondition.cs
@@ -40,6 +40,12 @@ public interface ICondition
///
public bool this[ConditionFlag flag] => this[(int)flag];
+
+ ///
+ /// Convert the conditions array to a set of all set condition flags.
+ ///
+ /// Returns a set.
+ public IReadOnlySet AsReadOnlySet();
///
/// Check if any condition flags are set.
@@ -55,8 +61,14 @@ public interface ICondition
public bool Any(params ConditionFlag[] flags);
///
- /// Check that *only* any of the condition flags specified are set. Useful to test if the client is in one of any
- /// of a few specific condiiton states.
+ /// Check that the specified condition flags are *not* present in the current conditions.
+ ///
+ /// The array of flags to check.
+ /// Returns false if any of the listed conditions are present, true otherwise.
+ public bool AnyExcept(params ConditionFlag[] except);
+
+ ///
+ /// Check that *only* any of the condition flags specified are set.
///
/// The array of flags to check.
/// Returns a bool.
@@ -68,11 +80,5 @@ public interface ICondition
///
/// The array of flags to check.
/// Returns a bool.
- public bool OnlyAll(params ConditionFlag[] other);
-
- ///
- /// Convert the conditions array to a set of all set condition flags.
- ///
- /// Returns a set.
- public IReadOnlySet AsReadOnlySet();
+ public bool EqualTo(params ConditionFlag[] other);
}