├── .gitignore
├── Dalamud.FullscreenCutscenes
├── icon.png
├── packages.lock.json
├── Dalamud.FullscreenCutscenes.json
├── Configuration.cs
├── Dalamud.FullscreenCutscenes.csproj
└── Plugin.cs
├── Dalamud.FullscreenCutscenes.sln
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/
2 | .idea/
3 | obj/
4 | bin/
5 | *.user
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goaaats/Dalamud.FullscreenCutscenes/HEAD/Dalamud.FullscreenCutscenes/icon.png
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/packages.lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "dependencies": {
4 | "net8.0-windows7.0": {
5 | "DalamudPackager": {
6 | "type": "Direct",
7 | "requested": "[2.1.13, )",
8 | "resolved": "2.1.13",
9 | "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/Dalamud.FullscreenCutscenes.json:
--------------------------------------------------------------------------------
1 | {
2 | "Author": "goat",
3 | "Name": "Ultrawide Cutscenes",
4 | "Punchline": "Remove letterboxing from cutscenes on ultrawide monitors.",
5 | "Description": "This plugin removes the \"letterboxing\" bars when watching cutscenes on ultrawide monitors.\nBeware! You may see things that you are not supposed to be seeing, such as upcoming NPCs popping in or T-posing.\n\nThanks to aers for finding this.",
6 | "InternalName": "Dalamud.FullscreenCutscenes",
7 | "RepoUrl": "https://github.com/goaaats/Dalamud.FullscreenCutscenes",
8 | "ApplicableVersion": "any",
9 | "Tags": [
10 | "ultrawide",
11 | "cutscene",
12 | "fullscreen"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/Configuration.cs:
--------------------------------------------------------------------------------
1 | using Dalamud.Configuration;
2 | using Dalamud.Plugin;
3 | using System;
4 |
5 | namespace Dalamud.FullscreenCutscenes
6 | {
7 | [Serializable]
8 | public class Configuration : IPluginConfiguration
9 | {
10 | public int Version { get; set; } = 0;
11 |
12 | public bool IsEnabled { get; set; } = true;
13 |
14 | // the below exist just to make saving less cumbersome
15 |
16 | [NonSerialized]
17 | private IDalamudPluginInterface? pluginInterface;
18 |
19 | public void Initialize(IDalamudPluginInterface pluginInterface)
20 | {
21 | this.pluginInterface = pluginInterface;
22 | }
23 |
24 | public void Save()
25 | {
26 | this.pluginInterface!.SavePluginConfig(this);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29709.97
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.FullscreenCutscenes", "Dalamud.FullscreenCutscenes\Dalamud.FullscreenCutscenes.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Release|x64 = Release|x64
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64
15 | {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64
16 | {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64
17 | {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64
18 | {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.ActiveCfg = Debug|x64
19 | {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.Build.0 = Debug|x64
20 | {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.ActiveCfg = Release|x64
21 | {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.Build.0 = Release|x64
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | GlobalSection(ExtensibilityGlobals) = postSolution
27 | SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF}
28 | EndGlobalSection
29 | EndGlobal
30 |
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/Dalamud.FullscreenCutscenes.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 1.0.0.3
7 | A sample plugin.
8 |
9 | https://github.com/goatcorp/SamplePlugin
10 | true
11 |
12 |
13 |
14 | net8.0-windows
15 | x64
16 | enable
17 | latest
18 | true
19 | false
20 | false
21 |
22 |
23 |
24 | $(appdata)\XIVLauncher\addon\Hooks\dev\
25 |
26 |
27 |
28 |
29 |
30 | $(DalamudLibPath)FFXIVClientStructs.dll
31 | false
32 |
33 |
34 | $(DalamudLibPath)Newtonsoft.Json.dll
35 | false
36 |
37 |
38 | $(DalamudLibPath)Dalamud.dll
39 | false
40 |
41 |
42 | $(DalamudLibPath)ImGui.NET.dll
43 | false
44 |
45 |
46 | $(DalamudLibPath)ImGuiScene.dll
47 | false
48 |
49 |
50 | $(DalamudLibPath)Lumina.dll
51 | false
52 |
53 |
54 | $(DalamudLibPath)Lumina.Excel.dll
55 | false
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SamplePlugin
2 |
3 | Simple example plugin for Dalamud.
4 |
5 | This is not designed to be the simplest possible example, but it is also not designed to cover everything you might want to do. For more detailed questions, come ask in [the Discord](https://discord.gg/3NMcUV5).
6 |
7 | ## Main Points
8 |
9 | * Simple functional plugin
10 | * Slash command
11 | * Main UI
12 | * Settings UI
13 | * Image loading
14 | * Plugin json
15 | * Simple, slightly-improved plugin configuration handling
16 | * Project organization
17 | * Copies all necessary plugin files to the output directory
18 | * Does not copy dependencies that are provided by dalamud
19 | * Output directory can be zipped directly and have exactly what is required
20 | * Hides data files from visual studio to reduce clutter
21 | * Also allows having data files in different paths than VS would usually allow if done in the IDE directly
22 |
23 |
24 | The intention is less that any of this is used directly in other projects, and more to show how similar things can be done.
25 |
26 | ## To Use
27 | ### Building
28 |
29 | 1. Open up `SamplePlugin.sln` in your C# editor of choice (likely [Visual Studio 2022](https://visualstudio.microsoft.com) or [JetBrains Rider](https://www.jetbrains.com/rider/)).
30 | 2. Build the solution. By default, this will build a `Debug` build, but you can switch to `Release` in your IDE.
31 | 3. The resulting plugin can be found at `SamplePlugin/obj/x64/Debug/SamplePlugin.dll` (or `Release` if appropriate.)
32 |
33 | ### Activating in-game
34 |
35 | 1. Launch the game and use `/xlsettings` in chat or `xlsettings` in the Dalamud Console to open up the Dalamud settings.
36 | * In here, go to `Experimental`, and add the full path to the `SamplePlugin.dll` to the list of Dev Plugin Locations.
37 | 2. Next, use `/xlplugins` (chat) or `xlplugins` (console) to open up the Plugin Installer.
38 | * In here, go to `Dev Tools > Installed Dev Plugins`, and the `SamplePlugin` should be visible. Enable it.
39 | 3. You should now be able to use `/pmycommand` (chat) or `pmycommand` (console)!
40 |
41 | Note that you only need to add it to the Dev Plugin Locations once (Step 1); it is preserved afterwards. You can disable, enable, or load your plugin on startup through the Plugin Installer.
42 |
43 | ### Reconfiguring for your own uses
44 |
45 | Basically, just replace all references to `SamplePlugin` in all of the files and filenames with your desired name. You'll figure it out 😁
46 |
47 | Dalamud will load the JSON file (by default, `Data/SamplePlugin.json`) next to your DLL and use it for metadata, including the description for your plugin in the Plugin Installer. Make sure to update this with information relevant to _your_ plugin!
--------------------------------------------------------------------------------
/Dalamud.FullscreenCutscenes/Plugin.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using Dalamud.Game.Command;
3 | using Dalamud.Plugin;
4 | using Dalamud.Game;
5 | using Dalamud.Game.ClientState.Conditions;
6 | using Dalamud.Hooking;
7 | using Dalamud.Plugin.Services;
8 |
9 | namespace Dalamud.FullscreenCutscenes
10 | {
11 | public sealed class Plugin : IDalamudPlugin
12 | {
13 | public string Name => "Ultrawide Cutscenes";
14 |
15 | private const string commandName = "/pcutscenes";
16 |
17 | private delegate nint UpdateLetterboxingDelegate(nint thisPtr);
18 |
19 | private Hook? updateLetterboxingHook;
20 |
21 | private IDalamudPluginInterface PluginInterface { get; init; }
22 | private ICommandManager CommandManager { get; init; }
23 | private Configuration Configuration { get; init; }
24 | private ICondition Condition { get; init; }
25 | public Plugin(
26 | IDalamudPluginInterface pluginInterface,
27 | ICommandManager commandManager,
28 | ISigScanner targetScanner,
29 | IGameInteropProvider gameInteropProvider,
30 | ICondition condition)
31 | {
32 | this.PluginInterface = pluginInterface;
33 | this.CommandManager = commandManager;
34 | this.Condition = condition;
35 |
36 | this.Configuration = this.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
37 | this.Configuration.Initialize(this.PluginInterface);
38 |
39 | // you might normally want to embed resources and load them from the manifest stream
40 | //this.PluginUi = new PluginUI(this.Configuration, goatImage);
41 |
42 | this.CommandManager.AddHandler(commandName, new CommandInfo(OnCommand)
43 | {
44 | HelpMessage = "A useful message to display in /xlhelp"
45 | });
46 |
47 | if (targetScanner.TryScanText("E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 8B ?? ?? ?? ??", out var ptr))
48 | {
49 | this.updateLetterboxingHook = gameInteropProvider.HookFromAddress(ptr, UpdateLetterboxingDetour);
50 | this.updateLetterboxingHook.Enable();
51 | }
52 |
53 | //this.PluginInterface.UiBuilder.Draw += DrawUI;
54 | //this.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
55 | }
56 |
57 | private unsafe nint UpdateLetterboxingDetour(nint thisptr)
58 | {
59 | bool isWatchingCutscene = Condition[ConditionFlag.OccupiedInCutSceneEvent] ||
60 | Condition[ConditionFlag.WatchingCutscene78];
61 | if (this.Configuration.IsEnabled && isWatchingCutscene)
62 | {
63 | SomeConfig* config = (SomeConfig*) thisptr;
64 | config->ShouldLetterBox &= ~(1 << 5);
65 | }
66 |
67 | return this.updateLetterboxingHook!.Original(thisptr);
68 | }
69 |
70 | public void Dispose()
71 | {
72 | this.updateLetterboxingHook?.Disable();
73 | this.CommandManager.RemoveHandler(commandName);
74 | }
75 |
76 | private void OnCommand(string command, string args)
77 | {
78 | if (!string.IsNullOrWhiteSpace(args) && bool.TryParse(args, out var val))
79 | {
80 | this.Configuration.IsEnabled = val;
81 | }
82 | else
83 | {
84 | this.Configuration.IsEnabled = !this.Configuration.IsEnabled;
85 | }
86 |
87 | this.Configuration.Save();
88 | }
89 |
90 | [StructLayout(LayoutKind.Explicit)]
91 | public partial struct SomeConfig
92 | {
93 | [FieldOffset(0x40)] public int ShouldLetterBox;
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------