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
8 changes: 8 additions & 0 deletions Stagehand.Definitions/Objects/IObjectVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ public interface IObjectVisitor<TParam, TResult>
/// <param name="param">The parameter passed to the visitor.</param>
/// <returns>The result of visiting the weapon definition.</returns>
static abstract TResult VisitWeaponDefinition(WeaponDefinition definition, ref TParam param);

/// <summary>
/// Visits a <see cref="SoundObjectDefinition"/>.
/// </summary>
/// <param name="definition">The sound object definition to visit.</param>
/// <param name="param">The parameter passed to the visitor.</param>
/// <returns>The result of visiting the sound object definition.</returns>
static abstract TResult VisitSoundObjectDefinition(SoundObjectDefinition definition, ref TParam param);
}
1 change: 1 addition & 0 deletions Stagehand.Definitions/Objects/ObjectDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace Stagehand.Definitions.Objects;
[JsonDerivedType(typeof(LightDefinition), typeDiscriminator: "Light")]
[JsonDerivedType(typeof(VfxObjectDefinition), typeDiscriminator: "VfxObject")]
[JsonDerivedType(typeof(WeaponDefinition), typeDiscriminator: "Weapon")]
[JsonDerivedType(typeof(SoundObjectDefinition), typeDiscriminator: "Sound")]
public abstract class ObjectDefinition
{
/// <summary>
Expand Down
70 changes: 70 additions & 0 deletions Stagehand.Definitions/Objects/SoundObjectDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Stagehand.Definitions.Objects;

/// <summary>
/// The definition of a sound object in a Stage definition.
/// </summary>
public class SoundObjectDefinition : ObjectDefinition
{
/// <summary>
/// The game path of the .scd resource to play.
/// </summary>
public string SoundGamePath { get; set; } = "";

/// <summary>
/// The index of the Sound in the sound resource to play.
/// </summary>
public int SoundIndex { get; set; } = 0;

/// <summary>
/// How loud to play the sound, with 1.0 being the original volume of the sound.
/// </summary>
public float Volume { get; set; } = 1.0f;

/// <summary>
/// How long the sound should fade in for, or 0 to not fade in.
/// </summary>
public float FadeInDurationSeconds { get; set; } = 0.0f;

/// <summary>
/// The speed to play the sound at, with 1.0 being the original speed of the sound.
/// </summary>
public float Speed { get; set; } = 1.0f;

/// <summary>
/// Whether to play the sound as though it is coming from the location of this sound object.
/// </summary>
public bool IsPositional { get; set; } = true;

/// <inheritdoc />
public override ObjectDefinition Clone()
{
var result = new SoundObjectDefinition();
CopyTo(result);
return result;
}

/// <inheritdoc />
public override void CopyTo(ObjectDefinition other)
{
base.CopyTo(other);

if (other is SoundObjectDefinition otherSound)
{
otherSound.SoundGamePath = SoundGamePath;
otherSound.Volume = Volume;
otherSound.FadeInDurationSeconds = FadeInDurationSeconds;
otherSound.Speed = Speed;
otherSound.SoundIndex = SoundIndex;
}
}

/// <inheritdoc />
public override TResult Visit<TVisitor, TParam, TResult>(ref TParam param)
{
return TVisitor.VisitSoundObjectDefinition(this, ref param);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ protected override void OnDrawProperties()
ImGui.TableNextColumn();
bool isModelResource = entry.Key.EndsWith(".mdl", StringComparison.OrdinalIgnoreCase);
bool isVfxResource = entry.Key.EndsWith(".avfx", StringComparison.OrdinalIgnoreCase);
if (isModelResource || isVfxResource)
bool isScdResource = entry.Key.EndsWith(".scd", StringComparison.OrdinalIgnoreCase);
if (isModelResource || isVfxResource || isScdResource)
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus, new Vector2(ImGui.GetFrameHeight())))
{
Expand All @@ -222,6 +223,10 @@ protected override void OnDrawProperties()
{
newDefinition = new VfxObjectDefinition() { VfxGamePath = entry.Key };
}
else if (isScdResource)
{
newDefinition = new SoundObjectDefinition() { SoundGamePath = entry.Key };
}

if (newDefinition != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ internal class BgObjectDefinitionEditor : ObjectDefinitionEditor<BgObjectDefinit

public override DefinitionTypeInfo TypeInfo => StaticTypeInfo;

private readonly IDataManager _dataManager;
private readonly IEditorHitTestService _hitTestService;
private readonly IAssetLibraryWindow _assetLibraryWindow;
private readonly EditorHitTestModel _hitTestModel;

public string ModelGamePath
Expand All @@ -49,9 +47,7 @@ public Vector4 DyeColor

public BgObjectDefinitionEditor(IServiceProvider serviceProvider, BgObjectDefinition definition, string key, StageDefinitionEditor stage) : base(serviceProvider, definition, key, stage)
{
_dataManager = serviceProvider.GetRequiredService<IDataManager>();
_hitTestService = serviceProvider.GetRequiredService<IEditorHitTestService>();
_assetLibraryWindow = serviceProvider.GetRequiredService<IAssetLibraryWindow>();
_hitTestModel = new EditorHitTestModel(this, ModelGamePath, serviceProvider.GetRequiredService<IModelBvhCacheService>(), serviceProvider.GetRequiredService<IDataManager>())
{
Position = Position,
Expand Down Expand Up @@ -103,7 +99,7 @@ protected override void SetDisplayNameInternal(string displayName)
base.SetDisplayNameInternal(displayName);
if (IsSelected)
{
_assetLibraryWindow.SetSelectionCallback(DisplayName, "Model Path", AssetType.MdlResource, () => IsInStage && IsSelected, asset => ModelGamePath = asset.GamePath);
AssetLibraryWindow.SetSelectionCallback(DisplayName, "Model Path", AssetType.MdlResource, () => IsInStage && IsSelected, asset => ModelGamePath = asset.GamePath);
}
}

Expand All @@ -124,48 +120,19 @@ public override void Selected()
{
base.Selected();

_assetLibraryWindow.SetSelectionCallback(DisplayName, "Model Path", AssetType.MdlResource, () => IsInStage && IsSelected, asset => ModelGamePath = asset.GamePath);
AssetLibraryWindow.SetSelectionCallback(DisplayName, "Model Path", AssetType.MdlResource, () => IsInStage && IsSelected, asset => ModelGamePath = asset.GamePath);
}

protected override void OnDrawProperties()
{
base.OnDrawProperties();

string modelGamePath = ModelGamePath;
if (ImGui.InputText("Model Path", ref modelGamePath, 1024, ImGuiInputTextFlags.EnterReturnsTrue))
if (DrawResourceGamePath("Model Path", ref modelGamePath))
{
ModelGamePath = modelGamePath;
}

bool exists = _dataManager.GameData.FileExists(ModelGamePath);
var icon = exists ? FontAwesomeIcon.CheckCircle : FontAwesomeIcon.ExclamationCircle;
float propertiesColumnWidth = (ImGui.GetContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) * 0.333f;
ImGui.SameLine(ImGui.GetContentRegionMax().X - propertiesColumnWidth - 16.0f * ImGuiHelpers.GlobalScale);
using (ImRaii.PushColor(ImGuiCol.Text, exists ? ImGuiColors.HealerGreen : ImGuiColors.DPSRed))
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.TextUnformatted(icon.ToIconString());
}
if (ImGui.IsItemHovered())
{
using (ImRaii.Tooltip())
{
ImGui.TextUnformatted(exists ? "Game path exists" : "Game path does not exist");
}
}
ImGui.SameLine(ImGui.GetContentRegionMax().X - ImGui.GetFrameHeight());
if (ImGuiComponents.IconButton(IAssetLibraryWindow.Icon, new Vector2(ImGui.GetFrameHeight(), ImGui.GetFrameHeight())))
{
_assetLibraryWindow.Show();
}
if (ImGui.IsItemHovered())
{
using (ImRaii.Tooltip())
{
ImGui.TextUnformatted("Open the Asset Library");
}
}

float opacity = Opacity;
if (ImGui.SliderFloat("Opacity", ref opacity, vMin: 0.0f, vMax: 1.0f))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.DependencyInjection;
using Stagehand.Definitions.Objects;
using Stagehand.Editor.Services;
using Stagehand.Live;
using Stagehand.Services;
using Stagehand.Windows;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -51,6 +56,8 @@ internal abstract class ObjectDefinitionEditor<TDefinition> : DefinitionEditorBa
protected ISelectionManager SelectionManager { get; }
protected IOverlayService OverlayService { get; }
protected ILiveObjectService LiveObjectService { get; }
protected IAssetLibraryWindow AssetLibraryWindow { get; }
protected IDataManager DataManager { get; }

protected TDefinition Definition { get; }
public string Key { get; }
Expand Down Expand Up @@ -125,6 +132,8 @@ protected ObjectDefinitionEditor(IServiceProvider serviceProvider, TDefinition d
SelectionManager = serviceProvider.GetRequiredService<ISelectionManager>();
OverlayService = serviceProvider.GetRequiredService<IOverlayService>();
LiveObjectService = serviceProvider.GetRequiredService<ILiveObjectService>();
AssetLibraryWindow = serviceProvider.GetRequiredService<IAssetLibraryWindow>();
DataManager = serviceProvider.GetRequiredService<IDataManager>();

Definition = definition;
Key = key;
Expand Down Expand Up @@ -212,6 +221,48 @@ protected override void OnDrawProperties()
ImGuiHelpers.ScaledDummy(4.0f);
}

protected bool DrawResourceGamePath(string propertyName, ref string gamePath)
{
var result = false;
if (ImGui.InputText(propertyName, ref gamePath, 1024, ImGuiInputTextFlags.EnterReturnsTrue))
{
result = true;
}

bool existsModded = !string.IsNullOrEmpty(ModpackId) && GetPreviewModpack() is ILiveModpack liveModpack && liveModpack.ModdedResourceExists(gamePath);
string modpackName = (!string.IsNullOrEmpty(ModpackId) && Stage.EmbeddedModpacks.TryGetValue(ModpackId, out var modpack)) ? modpack.DisplayName : string.Empty;
bool existsVanilla = DataManager.GameData.FileExists(gamePath);
var icon = existsModded ? FontAwesomeIcon.PlusCircle : existsVanilla ? FontAwesomeIcon.CheckCircle : FontAwesomeIcon.ExclamationCircle;
float propertiesColumnWidth = (ImGui.GetContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) * 0.333f;
ImGui.SameLine(ImGui.GetContentRegionMax().X - propertiesColumnWidth - 16.0f * ImGuiHelpers.GlobalScale);
using (ImRaii.PushColor(ImGuiCol.Text, existsModded ? ImGuiColors.HealerGreen : existsVanilla ? ImGuiColors.DalamudWhite : ImGuiColors.DPSRed))
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.TextUnformatted(icon.ToIconString());
}
if (ImGui.IsItemHovered())
{
using (ImRaii.Tooltip())
{
ImGui.TextUnformatted(existsModded ? $"Game path is modded in {modpackName}" : existsVanilla ? "Game path exists" : "Game path does not exist");
}
}
ImGui.SameLine(ImGui.GetContentRegionMax().X - ImGui.GetFrameHeight());
if (ImGuiComponents.IconButton(IAssetLibraryWindow.Icon, new Vector2(ImGui.GetFrameHeight(), ImGui.GetFrameHeight())))
{
AssetLibraryWindow.Show();
}
if (ImGui.IsItemHovered())
{
using (ImRaii.Tooltip())
{
ImGui.TextUnformatted("Open the Asset Library");
}
}

return result;
}

protected virtual IEnumerable<OutlinerContextMenuItem> GenerateContextMenuItems()
{
yield return new OutlinerContextMenuItem("Duplicate", "Creates a copy of this object.", _ =>
Expand Down
Loading
Loading