4 Commits

Author SHA1 Message Date
KnackAtNite 415a1ec283 Fix NullReferenceException when Target is null (v0.0.3.14)
Debug Build and Test / Build against Latest Dalamud (push) Has been cancelled
Debug Build and Test / Build against Staging Dalamud (push) Has been cancelled
Release Build and Publish / Release Build against Staging Dalamud and deploy to MyDalamudPlugins (release) Has been cancelled
- Add null check for e.Target before dereferencing in FlyTextArtist.Draw
- Prevents crash when fly text events reference despawned characters
- Bump version to 0.0.3.14

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 14:15:35 -05:00
KnackAtNite 4e4b2bd32d v0.0.3.13: Fix KeyNotFoundException when status ID not in sheet (return row not cache)
Debug Build and Test / Build against Latest Dalamud (push) Has been cancelled
Debug Build and Test / Build against Staging Dalamud (push) Has been cancelled
Release Build and Publish / Release Build against Staging Dalamud and deploy to MyDalamudPlugins (release) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 23:51:10 -05:00
KnackAtNite 931381e254 v0.0.3.12: Fix crash when status ID not in sheet (e.g. DRK dash 6620)
Debug Build and Test / Build against Latest Dalamud (push) Has been cancelled
Debug Build and Test / Build against Staging Dalamud (push) Has been cancelled
Release Build and Publish / Release Build against Staging Dalamud and deploy to MyDalamudPlugins (release) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 20:41:45 -05:00
KnackAtNite dd3f464860 v0.0.3.11: Separate Player AutoAttack Dealt and Taken config
Debug Build and Test / Build against Latest Dalamud (push) Has been cancelled
Debug Build and Test / Build against Staging Dalamud (push) Has been cancelled
Release Build and Publish / Release Build against Staging Dalamud and deploy to MyDalamudPlugins (release) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 23:08:45 -05:00
8 changed files with 103 additions and 16 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>cultbaus</Authors> <Authors>cultbaus</Authors>
<Company>-</Company> <Company>-</Company>
<Version>0.0.3.10</Version> <Version>0.0.3.14</Version>
<Description>This plugin manipulates flytext.</Description> <Description>This plugin manipulates flytext.</Description>
<Copyright>-</Copyright> <Copyright>-</Copyright>
<PackageProjectUrl>https://github.com/cultbaus/CBT</PackageProjectUrl> <PackageProjectUrl>https://github.com/cultbaus/CBT</PackageProjectUrl>
+6 -6
View File
@@ -79,34 +79,34 @@ public unsafe class SheetManager : S.IDisposable
private Action? GetActionRow(int actionID) private Action? GetActionRow(int actionID)
{ {
var row = LuminaActionSheet?.GetRow((uint)actionID); var row = LuminaActionSheet?.GetRowOrDefault((uint)actionID);
if (row != null) if (row != null)
{ {
this.actionCache[actionID] = row; this.actionCache[actionID] = row;
} }
return this.actionCache[actionID]; return row;
} }
private Status? GetStatusRow(int value1) private Status? GetStatusRow(int value1)
{ {
var row = LuminaStatusSheet?.GetRow((uint)value1); var row = LuminaStatusSheet?.GetRowOrDefault((uint)value1);
if (row != null) if (row != null)
{ {
this.statusCache[value1] = row; this.statusCache[value1] = row;
} }
return this.statusCache[value1]; return row;
} }
private Item? GetItemRow(int value1) private Item? GetItemRow(int value1)
{ {
var row = LuminaItemSheet?.GetRow((uint)value1); var row = LuminaItemSheet?.GetRowOrDefault((uint)value1);
if (row != null) if (row != null)
{ {
this.itemCache[value1] = row; this.itemCache[value1] = row;
} }
return this.itemCache[value1]; return row;
} }
} }
+1 -1
View File
@@ -31,7 +31,7 @@ public unsafe class FlyTextArtist
flyTextEvents.ForEach(e => flyTextEvents.ForEach(e =>
{ {
if (e.Kind != FlyTextKind.None) if (e.Kind != FlyTextKind.None && e.Target != null)
{ {
var qt = Service.Tree.GetQuadTree(e.Target->GetGameObjectId().ObjectId); var qt = Service.Tree.GetQuadTree(e.Target->GetGameObjectId().ObjectId);
+17
View File
@@ -48,6 +48,23 @@ public class KindTab : Tab
} }
} }
if (this.Current.InCategory(FlyTextCategory.AutoAttack))
{
GuiArtist.DrawLabelPrefix("Configure for", sameLine: false);
ImGui.SameLine();
var isTaken = this.UsePlayerAutoAttackTakenConfig;
if (ImGui.RadioButton("Player AutoAttack Dealt", !isTaken))
{
this.UsePlayerAutoAttackTakenConfig = false;
}
ImGui.SameLine();
if (ImGui.RadioButton("Player AutoAttack Taken", isTaken))
{
this.UsePlayerAutoAttackTakenConfig = true;
}
}
if (this.CurrentEnabled) if (this.CurrentEnabled)
{ {
this.DrawFontConfigurations(); this.DrawFontConfigurations();
+12 -1
View File
@@ -32,6 +32,11 @@ public abstract class Tab
/// </summary> /// </summary>
protected bool UsePlayerDamageTakenConfig { get; set; } protected bool UsePlayerDamageTakenConfig { get; set; }
/// <summary>
/// When true and current kind is AutoAttack, configuration edits apply to Player AutoAttack Taken instead of Dealt.
/// </summary>
protected bool UsePlayerAutoAttackTakenConfig { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether. /// Gets or sets a value indicating whether.
/// </summary> /// </summary>
@@ -241,7 +246,7 @@ public abstract class Tab
public abstract void OnClose(); public abstract void OnClose();
/// <summary> /// <summary>
/// Gets the config dictionary to use for the current kind (FlyTextKinds or FlyTextKindsPlayerDamageTaken for AbilityDamage when editing Taken). /// Gets the config dictionary to use for the current kind (FlyTextKinds or the appropriate Player * Taken dict when editing Taken).
/// </summary> /// </summary>
protected Dictionary<FlyTextKind, FlyTextConfiguration> GetCurrentConfigDictionary() protected Dictionary<FlyTextKind, FlyTextConfiguration> GetCurrentConfigDictionary()
{ {
@@ -251,6 +256,12 @@ public abstract class Tab
return Service.Configuration.FlyTextKindsPlayerDamageTaken; return Service.Configuration.FlyTextKindsPlayerDamageTaken;
} }
if (this.Current.InCategory(FlyTextCategory.AutoAttack) && this.UsePlayerAutoAttackTakenConfig
&& Service.Configuration.FlyTextKindsPlayerAutoAttackTaken != null)
{
return Service.Configuration.FlyTextKindsPlayerAutoAttackTaken;
}
return Service.Configuration.FlyTextKinds; return Service.Configuration.FlyTextKinds;
} }
+17 -1
View File
@@ -92,7 +92,7 @@ public sealed partial class Plugin : IDalamudPlugin
=> this.configWindow.IsOpen = true; => this.configWindow.IsOpen = true;
/// <summary> /// <summary>
/// Migrates existing config: ensures FlyTextKindsPlayerDamageTaken is populated for AbilityDamage kinds (e.g. from older saves). /// Migrates existing config: ensures FlyTextKindsPlayerDamageTaken and FlyTextKindsPlayerAutoAttackTaken are populated (e.g. from older saves).
/// </summary> /// </summary>
private static void MigratePlayerDamageTakenConfig() private static void MigratePlayerDamageTakenConfig()
{ {
@@ -112,6 +112,22 @@ public sealed partial class Plugin : IDalamudPlugin
} }
} }
} }
if (config.FlyTextKindsPlayerAutoAttackTaken == null || config.FlyTextKindsPlayerAutoAttackTaken.Count == 0)
{
config.FlyTextKindsPlayerAutoAttackTaken = [];
foreach (var kind in FlyTextCategoryExtension.GetKindsFor(FlyTextCategory.AutoAttack))
{
if (config.FlyTextKinds.TryGetValue(kind, out var existing))
{
config.FlyTextKindsPlayerAutoAttackTaken[kind] = new FlyTextConfiguration(existing);
}
else
{
config.FlyTextKindsPlayerAutoAttackTaken[kind] = new FlyTextConfiguration();
}
}
}
} }
/// <summary> /// <summary>
+36
View File
@@ -68,6 +68,12 @@ public class PluginConfiguration : IPluginConfiguration
kind => kind, kind => kind,
kind => new FlyTextConfiguration()); kind => new FlyTextConfiguration());
this.FlyTextKindsPlayerAutoAttackTaken = FlyTextCategoryExtension
.GetKindsFor(FlyTextCategory.AutoAttack)
.ToDictionary(
kind => kind,
kind => new FlyTextConfiguration());
FlyTextCategory.AbilityDamage FlyTextCategory.AbilityDamage
.ForEachKind(kind => .ForEachKind(kind =>
{ {
@@ -90,6 +96,9 @@ public class PluginConfiguration : IPluginConfiguration
{ {
this.FlyTextKinds[kind].Font.Color = new Vector4(1, 1, 1, 1); this.FlyTextKinds[kind].Font.Color = new Vector4(1, 1, 1, 1);
this.FlyTextKinds[kind].Font.Size = 18f; this.FlyTextKinds[kind].Font.Size = 18f;
this.FlyTextKindsPlayerAutoAttackTaken[kind].Font.Color = new Vector4(1, 1, 1, 1);
this.FlyTextKindsPlayerAutoAttackTaken[kind].Font.Size = 18f;
}); });
FlyTextCategory.AbilityHealing FlyTextCategory.AbilityHealing
@@ -179,6 +188,27 @@ public class PluginConfiguration : IPluginConfiguration
this.FlyTextKindsPlayerDamageTaken[kind].Filter.Self = false; this.FlyTextKindsPlayerDamageTaken[kind].Filter.Self = false;
} }
}); });
FlyTextCategoryExtension
.GetKindsFor(FlyTextCategory.AutoAttack)
.ToList()
.ForEach(kind =>
{
if (kind.ShouldFilter(FlyTextFilter.Party))
{
this.FlyTextKindsPlayerAutoAttackTaken[kind].Filter.Party = false;
}
if (kind.ShouldFilter(FlyTextFilter.Enemy))
{
this.FlyTextKindsPlayerAutoAttackTaken[kind].Filter.Enemy = false;
}
if (kind.ShouldFilter(FlyTextFilter.Self))
{
this.FlyTextKindsPlayerAutoAttackTaken[kind].Filter.Self = false;
}
});
} }
/// <summary> /// <summary>
@@ -197,6 +227,12 @@ public class PluginConfiguration : IPluginConfiguration
/// </summary> /// </summary>
public Dictionary<FlyTextKind, FlyTextConfiguration> FlyTextKindsPlayerDamageTaken { get; set; } = []; public Dictionary<FlyTextKind, FlyTextConfiguration> FlyTextKindsPlayerDamageTaken { get; set; } = [];
/// <summary>
/// Gets or sets the configuration for auto attack when the player is the target (auto attack taken).
/// When the player deals auto attack, <see cref="FlyTextKinds"/> is used; when the player takes auto attack, this is used.
/// </summary>
public Dictionary<FlyTextKind, FlyTextConfiguration> FlyTextKindsPlayerAutoAttackTaken { get; set; } = [];
/// <summary> /// <summary>
/// Gets or sets the FlyTextCategory Category Configuration options. /// Gets or sets the FlyTextCategory Category Configuration options.
/// </summary> /// </summary>
+13 -6
View File
@@ -104,7 +104,7 @@ public unsafe partial class PluginManager
=> Service.Configuration.FlyTextKinds.TryGetValue(kind, out var config) ? config : null; => Service.Configuration.FlyTextKinds.TryGetValue(kind, out var config) ? config : null;
/// <summary> /// <summary>
/// Get the config for an event. For AbilityDamage kinds, returns Player Damage Taken config when the player is the target, otherwise the normal (Dealt) config. /// Get the config for an event. For AbilityDamage kinds, returns Player Damage Taken config when the player is the target; for AutoAttack, returns Player AutoAttack Taken config when the player is the target; otherwise the normal (Dealt) config.
/// </summary> /// </summary>
/// <param name="kind">Kind of the event.</param> /// <param name="kind">Kind of the event.</param>
/// <param name="source">Source character.</param> /// <param name="source">Source character.</param>
@@ -112,12 +112,19 @@ public unsafe partial class PluginManager
/// <returns>The configuration to use for this event.</returns> /// <returns>The configuration to use for this event.</returns>
public static FlyTextConfiguration? GetConfigForEvent(FlyTextKind kind, Character* source, Character* target) public static FlyTextConfiguration? GetConfigForEvent(FlyTextKind kind, Character* source, Character* target)
{ {
if (kind.InCategory(FlyTextCategory.AbilityDamage) if (target != null && IsPlayerCharacter(target))
&& target != null
&& IsPlayerCharacter(target)
&& Service.Configuration.FlyTextKindsPlayerDamageTaken?.TryGetValue(kind, out var takenConfig) == true)
{ {
return takenConfig; if (kind.InCategory(FlyTextCategory.AbilityDamage)
&& Service.Configuration.FlyTextKindsPlayerDamageTaken?.TryGetValue(kind, out var damageTakenConfig) == true)
{
return damageTakenConfig;
}
if (kind.InCategory(FlyTextCategory.AutoAttack)
&& Service.Configuration.FlyTextKindsPlayerAutoAttackTaken?.TryGetValue(kind, out var autoAttackTakenConfig) == true)
{
return autoAttackTakenConfig;
}
} }
return GetConfigForKind(kind); return GetConfigForKind(kind);