The IClientState service provides access to the current state of the game client, including information about the player’s location, login status, and various game state events.
Getting Started
Inject the service into your plugin:
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
public class MyPlugin : IDalamudPlugin
{
private readonly IClientState clientState;
public MyPlugin(IClientState clientState)
{
this.clientState = clientState;
// Subscribe to events
this.clientState.Login += OnLogin;
this.clientState.TerritoryChanged += OnTerritoryChanged;
}
private void OnLogin()
{
// Player has logged in
}
private void OnTerritoryChanged(ushort territoryId)
{
// Player changed zones
}
public void Dispose()
{
this.clientState.Login -= OnLogin;
this.clientState.TerritoryChanged -= OnTerritoryChanged;
}
}
Properties
ClientLanguage
Gets the language of the client.
ClientLanguage ClientLanguage { get; }
Example:
var language = clientState.ClientLanguage;
if (language == ClientLanguage.English)
{
// Show English text
}
TerritoryType
Gets the current territory the player resides in.
ushort TerritoryType { get; }
Example:
var currentTerritory = clientState.TerritoryType;
if (currentTerritory == 886) // The Tempest
{
// Do something specific to this zone
}
MapId
Gets the current map the player resides in.
Instance
Gets the instance number of the current zone, used when multiple copies of an area are active.
IsLoggedIn
Gets a value indicating whether a character is logged in.
Example:
if (clientState.IsLoggedIn)
{
// Player is logged in and ready
}
IsPvP
Gets a value indicating whether the user is playing PvP.
IsPvPExcludingDen
Gets a value indicating whether the user is playing PvP, excluding the Wolves’ Den.
bool IsPvPExcludingDen { get; }
IsGPosing
Gets a value indicating whether the client is currently in Group Pose (GPose) mode.
Methods
IsClientIdle
Check whether the client is currently “idle”. This means a player is not logged in, or is not actively in combat or doing anything that we may not want to disrupt.
bool IsClientIdle(out ConditionFlag blockingFlag)
bool IsClientIdle()
An output parameter containing the first observed condition blocking the “idle” state. 0 if idle.
Returns: true if the client is idle, false otherwise.
Example:
if (clientState.IsClientIdle(out var blockingFlag))
{
// Safe to perform background operations
}
else
{
// Player is busy with: blockingFlag
}
Events
ZoneInit
Event that gets fired when the game initializes a zone.
event Action<ZoneInitEventArgs> ZoneInit
Example:
clientState.ZoneInit += (args) =>
{
// Zone is initializing
};
TerritoryChanged
Event that gets fired when the current territory changes.
event Action<ushort> TerritoryChanged
Example:
clientState.TerritoryChanged += (territoryId) =>
{
chatGui.Print($"Entered territory: {territoryId}");
};
MapIdChanged
Event that gets fired when the current map changes.
event Action<uint> MapIdChanged
InstanceChanged
Event that gets fired when the current zone instance changes.
event Action<uint> InstanceChanged
ClassJobChanged
Event that fires when a character’s ClassJob changed.
event ClassJobChangeDelegate? ClassJobChanged
Delegate signature:
public delegate void ClassJobChangeDelegate(uint classJobId)
Example:
clientState.ClassJobChanged += (classJobId) =>
{
chatGui.Print($"Switched to job: {classJobId}");
};
LevelChanged
Event that fires when any character level changes, including levels for a not-currently-active ClassJob (e.g. PvP matches, DoH/DoL).
event LevelChangeDelegate? LevelChanged
Delegate signature:
public delegate void LevelChangeDelegate(uint classJobId, uint level)
The level of the corresponding ClassJob
Example:
clientState.LevelChanged += (classJobId, level) =>
{
chatGui.Print($"Job {classJobId} is now level {level}!");
};
Login
Event that fires when a character is logging in, and the local character object is available.
Example:
clientState.Login += () =>
{
chatGui.Print("Welcome back!");
};
Logout
Event that fires when a character is logging out.
event LogoutDelegate Logout
Delegate signature:
public delegate void LogoutDelegate(int type, int code)
EnterPvP
Event that fires when a character is entering PvP.
LeavePvP
Event that fires when a character is leaving PvP.
CfPop
Event that gets fired when a duty is ready.
event Action<Lumina.Excel.Sheets.ContentFinderCondition> CfPop
Example:
clientState.CfPop += (content) =>
{
// Duty finder queue has popped
chatGui.Print($"Duty ready: {content.Name}");
};
Common Use Cases
Zone-Specific Logic
public void CheckTerritory()
{
if (!clientState.IsLoggedIn)
return;
var territory = clientState.TerritoryType;
switch (territory)
{
case 886: // The Tempest
// Enable specific features
break;
default:
// Default behavior
break;
}
}
Tracking Player Progress
private void Initialize()
{
clientState.LevelChanged += (classJobId, level) =>
{
// Save level progress
SaveLevelData(classJobId, level);
if (level % 10 == 0)
{
chatGui.Print($"Congratulations on reaching level {level}!");
}
};
}
Safe Background Operations
public void PerformBackgroundTask()
{
if (clientState.IsClientIdle(out var blockingFlag))
{
// Safe to perform operations
ProcessData();
}
else
{
// Defer operation
Logger.Debug($"Client busy: {blockingFlag}");
}
}
Always unsubscribe from events in your plugin’s Dispose method to prevent memory leaks.
The LocalPlayer and LocalContentId properties are obsolete. Use IPlayerState or IObjectTable.LocalPlayer instead.