feat: add configuration for emotes
This commit is contained in:
parent
a08c086323
commit
34be1311d5
@ -18,6 +18,7 @@ public class Configuration : IPluginConfiguration {
|
||||
public bool LockViewer;
|
||||
public bool ClickThroughViewer;
|
||||
public bool HideTitlebar;
|
||||
public bool ShowEmotes = true;
|
||||
public float ViewerOpacity = 100.0f;
|
||||
public int DefaultGlyph = 3;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class MessageWithTerritory {
|
||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
||||
public class EmoteData {
|
||||
public required uint Id { get; set; }
|
||||
public required byte[] Customise { get; set; }
|
||||
public required List<byte> Customise { get; set; }
|
||||
public required EquipmentData[] Equipment { get; set; }
|
||||
public required WeaponData[] Weapon { get; set; }
|
||||
public required uint Glasses { get; set; }
|
||||
@ -91,7 +91,9 @@ public class EmoteData {
|
||||
public class EquipmentData {
|
||||
public required ushort Id { get; set; }
|
||||
public required byte Variant { get; set; }
|
||||
[JsonProperty("stain_0")]
|
||||
public required byte Stain0 { get; set; }
|
||||
[JsonProperty("stain_1")]
|
||||
public required byte Stain1 { get; set; }
|
||||
public required ulong Value { get; set; }
|
||||
}
|
||||
@ -101,7 +103,9 @@ public class EquipmentData {
|
||||
public class WeaponData {
|
||||
public required WeaponModelId ModelId { get; set; }
|
||||
public required byte State { get; set; }
|
||||
[JsonProperty("flags_1")]
|
||||
public required ushort Flags1 { get; set; }
|
||||
[JsonProperty("flags_2")]
|
||||
public required byte Flags2 { get; set; }
|
||||
}
|
||||
|
||||
@ -111,7 +115,9 @@ public class WeaponModelId {
|
||||
public required ushort Id { get; set; }
|
||||
public required ushort Kind { get; set; }
|
||||
public required ushort Variant { get; set; }
|
||||
[JsonProperty("stain_0")]
|
||||
public required byte Stain0 { get; set; }
|
||||
[JsonProperty("stain_1")]
|
||||
public required byte Stain1 { get; set; }
|
||||
public required ulong Value { get; set; }
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ internal class Settings : ITab {
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Disable in cutscenes", ref this.Plugin.Config.DisableInCutscene);
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Disable in /gpose", ref this.Plugin.Config.DisableInGpose);
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Remove glow effect from signs", ref this.Plugin.Config.RemoveGlow);
|
||||
anyChanged |= ImGui.Checkbox("Show player emotes", ref this.Plugin.Config.ShowEmotes);
|
||||
|
||||
var tt = this.Plugin.DataManager.GetExcelSheet<TerritoryType>();
|
||||
if (tt == null) {
|
||||
|
@ -3,6 +3,7 @@ using System.Text;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Interface.Textures;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
@ -28,6 +29,7 @@ internal class Write : ITab {
|
||||
private (int, int) _word2 = (-1, -1);
|
||||
private int _glyph;
|
||||
private int _emoteIdx = -1;
|
||||
private string _emoteSearch = string.Empty;
|
||||
|
||||
private const string Placeholder = "****";
|
||||
private Pack? Pack => Pack.All.Get(this._pack);
|
||||
@ -69,6 +71,7 @@ internal class Write : ITab {
|
||||
|
||||
this.Emotes = this.Plugin.DataManager.GetExcelSheet<Emote>()!
|
||||
.Skip(1)
|
||||
.Where(emote => emote.TextCommand.Row != 0)
|
||||
.ToList();
|
||||
|
||||
this._glyph = this.Plugin.Config.DefaultGlyph;
|
||||
@ -312,30 +315,50 @@ internal class Write : ITab {
|
||||
var emoteLabel = this._emoteIdx == -1
|
||||
? "None"
|
||||
: this.Emotes[this._emoteIdx].Name.ToDalamudString().TextValue;
|
||||
if (ImGui.BeginCombo("Emote", emoteLabel)) {
|
||||
if (ImGui.BeginCombo("Emote", emoteLabel, ImGuiComboFlags.HeightLarge)) {
|
||||
using var endCombo = new OnDispose(ImGui.EndCombo);
|
||||
|
||||
if (ImGui.Selectable("None##no-emote", this._emoteIdx == -1)) {
|
||||
this._emoteIdx = -1;
|
||||
if (ImGui.IsWindowAppearing()) {
|
||||
ImGui.SetKeyboardFocusHere();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
ImGui.InputTextWithHint("###emote-search", "Search...", ref this._emoteSearch, 100, ImGuiInputTextFlags.AutoSelectAll);
|
||||
|
||||
for (var i = 0; i < this.Emotes.Count; i++) {
|
||||
var emote = this.Emotes[i];
|
||||
var name = emote.Name.ToDalamudString().TextValue;
|
||||
|
||||
var unlocked = IsEmoteUnlocked(emote);
|
||||
if (!unlocked) {
|
||||
ImGui.BeginDisabled();
|
||||
using var endChild = new OnDispose(ImGui.EndChild);
|
||||
if (ImGui.BeginChild("##emote-search-child", new Vector2(0, 150) * ImGuiHelpers.GlobalScale)) {
|
||||
if (ImGui.Selectable("None##no-emote", this._emoteIdx == -1)) {
|
||||
this._emoteIdx = -1;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui.Selectable($"{name}##emote-{emote.RowId}", this._emoteIdx == i)) {
|
||||
this._emoteIdx = i;
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
if (!unlocked) {
|
||||
ImGui.EndDisabled();
|
||||
for (var i = 0; i < this.Emotes.Count; i++) {
|
||||
var emote = this.Emotes[i];
|
||||
if (!string.IsNullOrEmpty(this._emoteSearch)) {
|
||||
if (!emote.Name.ToDalamudString().TextValue.Contains(this._emoteSearch, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
if (!emote.TextCommand.Value!.Command.ToDalamudString().TextValue.Contains(this._emoteSearch, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var name = emote.Name.ToDalamudString().TextValue;
|
||||
|
||||
var unlocked = IsEmoteUnlocked(emote);
|
||||
if (!unlocked) {
|
||||
ImGui.BeginDisabled();
|
||||
}
|
||||
|
||||
if (ImGui.Selectable($"{name}##emote-{emote.RowId}", this._emoteIdx == i)) {
|
||||
this._emoteIdx = i;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (!unlocked) {
|
||||
ImGui.EndDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,12 +439,11 @@ internal class Write : ITab {
|
||||
}
|
||||
|
||||
private unsafe EmoteData GetEmoteData(Emote emote, IPlayerCharacter player) {
|
||||
var objMan = ClientObjectManager.Instance();
|
||||
var chara = (BattleChara*) objMan->GetObjectByIndex(player.ObjectIndex);
|
||||
var chara = (Character*) GameObjectManager.Instance()->Objects.GetObjectByGameObjectId(player.GameObjectId);
|
||||
|
||||
return new EmoteData {
|
||||
Id = emote.RowId,
|
||||
Customise = player.Customize,
|
||||
Customise = player.Customize.ToList(),
|
||||
Equipment = chara->DrawData.EquipmentModelIds
|
||||
.ToArray()
|
||||
.Select(equip => new EquipmentData {
|
||||
@ -464,6 +486,8 @@ internal class Write : ITab {
|
||||
this._word1 = (-1, -1);
|
||||
this._word2 = (-1, -1);
|
||||
this._glyph = this.Plugin.Config.DefaultGlyph;
|
||||
this._emoteIdx = -1;
|
||||
this._emoteSearch = string.Empty;
|
||||
}
|
||||
|
||||
private void ClearIfNecessary() {
|
||||
|
@ -19,6 +19,14 @@ internal class ActorManager : IDisposable {
|
||||
public void Dispose() {
|
||||
this.Plugin.Ui.Viewer.View -= this.OnView;
|
||||
this.Plugin.Framework.Update -= this.OnFramework;
|
||||
|
||||
if (this._idx != null) {
|
||||
unsafe {
|
||||
var objMan = ClientObjectManager.Instance();
|
||||
new DisableAction().Run(this, objMan);
|
||||
new DeleteAction().Run(this, objMan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void OnFramework(IFramework framework) {
|
||||
@ -52,7 +60,7 @@ internal class ActorManager : IDisposable {
|
||||
Plugin.Log.Debug($"OnView message is {msg}");
|
||||
this.Despawn();
|
||||
|
||||
if (message?.Emote != null) {
|
||||
if (this.Plugin.Config.ShowEmotes && message?.Emote != null) {
|
||||
this.Spawn(message);
|
||||
}
|
||||
}
|
||||
@ -122,6 +130,7 @@ internal class ActorManager : IDisposable {
|
||||
|
||||
manager._idx = idx;
|
||||
var emote = message.Emote;
|
||||
var emoteRow = manager.GetValidEmote(emote.Id);
|
||||
|
||||
var chara = (BattleChara*) objMan->GetObjectByIndex((ushort) idx);
|
||||
|
||||
@ -131,7 +140,7 @@ internal class ActorManager : IDisposable {
|
||||
chara->Rotation = message.Yaw;
|
||||
var drawData = &chara->DrawData;
|
||||
|
||||
var maxLen = Math.Min(sizeof(CustomizeData), emote.Customise.Length);
|
||||
var maxLen = Math.Min(sizeof(CustomizeData), emote.Customise.Count);
|
||||
var rawCustomise = (byte*) &drawData->CustomizeData;
|
||||
for (var i = 0; i < maxLen; i++) {
|
||||
rawCustomise[i] = emote.Customise[i];
|
||||
@ -144,26 +153,23 @@ internal class ActorManager : IDisposable {
|
||||
Variant = equip.Variant,
|
||||
Stain0 = equip.Stain0,
|
||||
Stain1 = equip.Stain1,
|
||||
Value = equip.Value,
|
||||
};
|
||||
}
|
||||
|
||||
for (var i = 0; i < Math.Min(drawData->WeaponData.Length, emote.Weapon.Length); i++) {
|
||||
var weapon = emote.Weapon[i];
|
||||
drawData->Weapon((DrawDataContainer.WeaponSlot) i) = new DrawObjectData {
|
||||
ModelId = new FFXIVClientStructs.FFXIV.Client.Game.Character.WeaponModelId {
|
||||
if (emoteRow is { DrawsWeapon: true }) {
|
||||
for (var i = 0; i < Math.Min(drawData->WeaponData.Length, emote.Weapon.Length); i++) {
|
||||
var weapon = emote.Weapon[i];
|
||||
drawData->Weapon((DrawDataContainer.WeaponSlot) i).ModelId = new FFXIVClientStructs.FFXIV.Client.Game.Character.WeaponModelId {
|
||||
Id = weapon.ModelId.Id,
|
||||
Type = weapon.ModelId.Kind,
|
||||
Variant = weapon.ModelId.Variant,
|
||||
Stain0 = weapon.ModelId.Stain0,
|
||||
Stain1 = weapon.ModelId.Stain1,
|
||||
Value = weapon.ModelId.Value,
|
||||
},
|
||||
DrawObject = chara->DrawObject,
|
||||
Flags1 = weapon.Flags1,
|
||||
Flags2 = weapon.Flags2,
|
||||
State = weapon.State,
|
||||
};
|
||||
};
|
||||
drawData->Weapon((DrawDataContainer.WeaponSlot) i).Flags1 = weapon.Flags1;
|
||||
drawData->Weapon((DrawDataContainer.WeaponSlot) i).Flags2 = weapon.Flags2;
|
||||
drawData->Weapon((DrawDataContainer.WeaponSlot) i).State = weapon.State;
|
||||
}
|
||||
}
|
||||
|
||||
drawData->IsHatHidden = emote.HatHidden;
|
||||
@ -174,8 +180,8 @@ internal class ActorManager : IDisposable {
|
||||
|
||||
chara->Alpha = 0.25f;
|
||||
chara->SetMode(CharacterModes.AnimLock, 0);
|
||||
if (manager.Plugin.DataManager.GetExcelSheet<Emote>()?.GetRow(emote.Id) is { } row) {
|
||||
chara->Timeline.BaseOverride = (ushort) row.ActionTimeline[0].Row;
|
||||
if (emoteRow != null) {
|
||||
chara->Timeline.BaseOverride = (ushort) emoteRow.ActionTimeline[0].Row;
|
||||
}
|
||||
|
||||
manager._tasks.Enqueue(new EnableAction());
|
||||
@ -183,6 +189,15 @@ internal class ActorManager : IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
private Emote? GetValidEmote(uint rowId) {
|
||||
var emote = this.Plugin.DataManager.GetExcelSheet<Emote>()?.GetRow(rowId);
|
||||
if (emote == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return emote.TextCommand.Row == 0 ? null : emote;
|
||||
}
|
||||
|
||||
private unsafe class EnableAction : BaseActorAction {
|
||||
public override bool Run(ActorManager manager, ClientObjectManager* objMan) {
|
||||
if (!this.TryGetBattleChara(manager, objMan, out var chara)) {
|
||||
|
Loading…
Reference in New Issue
Block a user