This commit is contained in:
52
.github/workflows/release.yml
vendored
Normal file
52
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Build and Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*.*.*.*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DALAMUD_HOME: /tmp/dalamud
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: 9.0.x
|
||||||
|
|
||||||
|
- name: Download Dalamud Latest
|
||||||
|
run: |
|
||||||
|
wget https://goatcorp.github.io/dalamud-distrib/latest.zip -O ${{ env.DALAMUD_HOME }}.zip
|
||||||
|
unzip ${{ env.DALAMUD_HOME }}.zip -d ${{ env.DALAMUD_HOME }}
|
||||||
|
|
||||||
|
- name: Restore Project
|
||||||
|
run: dotnet restore
|
||||||
|
|
||||||
|
- name: Build Project
|
||||||
|
run: dotnet build --configuration Release HouseStealerPlugin/HouseStealerPlugin.csproj -p:AssemblyVersion=${{ github.ref_name }}
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
id: create_release
|
||||||
|
with:
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
release_name: ${{ github.ref_name }}
|
||||||
|
tag_name: ${{ github.ref_name }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Upload Release Asset with curl
|
||||||
|
run: |
|
||||||
|
curl \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${{ gitea.token }}" \
|
||||||
|
-H "Content-Type: application/zip" \
|
||||||
|
--data-binary @bin/Release/HouseStealerPlugin/latest.zip \
|
||||||
|
"${{ steps.create_release.outputs.upload_url }}?name=latest.zip"
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.vs/
|
||||||
|
obj/
|
||||||
|
bin/
|
||||||
|
*.user
|
||||||
|
.idea/
|
||||||
31
HouseStealerPlugin.sln
Normal file
31
HouseStealerPlugin.sln
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.13.35507.96
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HouseStealerPlugin", "HouseStealerPlugin\HouseStealerPlugin.csproj", "{479ADEA9-780A-4A8E-98A1-82C0399176E4}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Debug|x64.ActiveCfg = Release|x64
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Debug|x64.Build.0 = Release|x64
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{479ADEA9-780A-4A8E-98A1-82C0399176E4}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {0D7BC4A9-5CCC-47C8-9525-9597FCB81275}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
39
HouseStealerPlugin/Configuration.cs
Normal file
39
HouseStealerPlugin/Configuration.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud.Configuration;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class Configuration : IPluginConfiguration
|
||||||
|
{
|
||||||
|
public int Version { get; set; } = 0;
|
||||||
|
|
||||||
|
public bool DrawScreen = false;
|
||||||
|
public float DrawDistance = 0;
|
||||||
|
public List<int> HiddenScreenItemHistory = new List<int>();
|
||||||
|
public List<int> GroupingList = new List<int>();
|
||||||
|
|
||||||
|
public bool Basement = true;
|
||||||
|
public bool GroundFloor = true;
|
||||||
|
public bool UpperFloor = true;
|
||||||
|
|
||||||
|
public int LoadInterval = 400;
|
||||||
|
public bool ApplyLayout = true;
|
||||||
|
|
||||||
|
public string SaveLocation = null;
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
DalamudApi.PluginInterface.SavePluginConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetRecord()
|
||||||
|
{
|
||||||
|
HiddenScreenItemHistory.Clear();
|
||||||
|
GroupingList.Clear();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
40
HouseStealerPlugin/DalamudApi.cs
Normal file
40
HouseStealerPlugin/DalamudApi.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin;
|
||||||
|
|
||||||
|
public class DalamudApi
|
||||||
|
{
|
||||||
|
public static void Initialize(IDalamudPluginInterface pluginInterface) => pluginInterface.Create<DalamudApi>();
|
||||||
|
|
||||||
|
// [PluginService] public static IAetheryteList AetheryteList { get; private set; } = null;
|
||||||
|
// [PluginService] public static IBuddyList BuddyList { get; private set; } = null;
|
||||||
|
[PluginService] public static IChatGui ChatGui { get; private set; } = null;
|
||||||
|
[PluginService] public static IClientState ClientState { get; private set; } = null;
|
||||||
|
[PluginService] public static ICommandManager CommandManager { get; private set; } = null;
|
||||||
|
// [PluginService] public static ICondition Condition { get; private set; } = null;
|
||||||
|
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null;
|
||||||
|
[PluginService] public static IDataManager DataManager { get; private set; } = null;
|
||||||
|
[PluginService] public static ITextureProvider TextureProvider { get; private set; }
|
||||||
|
// [PluginService] public static IDtrBar DtrBar { get; private set; } = null;
|
||||||
|
// [PluginService] public static IFateTable FateTable { get; private set; } = null;
|
||||||
|
// [PluginService] public static IFlyTextGui FlyTextGui { get; private set; } = null;
|
||||||
|
[PluginService] public static IFramework Framework { get; private set; } = null;
|
||||||
|
[PluginService] public static IGameGui GameGui { get; private set; } = null;
|
||||||
|
// [PluginService] public static IGameNetwork GameNetwork { get; private set; } = null;
|
||||||
|
// [PluginService] public static IGamepadState GamePadState { get; private set; } = null;
|
||||||
|
// [PluginService] public static IJobGauges JobGauges { get; private set; } = null;
|
||||||
|
// [PluginService] public static IKeyState KeyState { get; private set; } = null;
|
||||||
|
// [PluginService] public static ILibcFunction LibcFunction { get; private set; } = null;
|
||||||
|
//[PluginService] public static IObjectTable ObjectTable { get; private set; } = null;
|
||||||
|
// [PluginService] public static IPartyFinderGui PartyFinderGui { get; private set; } = null;
|
||||||
|
// [PluginService] public static IPartyList PartyList { get; private set; } = null;
|
||||||
|
[PluginService] public static ISigScanner SigScanner { get; private set; } = null;
|
||||||
|
// [PluginService] public static ITargetManager TargetManager { get; private set; } = null;
|
||||||
|
// [PluginService] public static IToastGui ToastGui { get; private set; } = null;
|
||||||
|
[PluginService] public static IGameInteropProvider Hooks { get; private set; } = null;
|
||||||
|
[PluginService] public static IPluginLog PluginLog { get; private set; } = null;
|
||||||
|
// [PluginService] public static ITitleScreenMenu TitleScreenMenu { get; private set; } = null;
|
||||||
|
}
|
||||||
440
HouseStealerPlugin/Gui/ConfigurationWindow.cs
Normal file
440
HouseStealerPlugin/Gui/ConfigurationWindow.cs
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
|
using Dalamud.Interface.Textures;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using HouseStealerPlugin.Objects;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using static HouseStealerPlugin.HouseStealerPlugin;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin.Gui
|
||||||
|
{
|
||||||
|
public class ConfigurationWindow : Window<HouseStealerPlugin>
|
||||||
|
{
|
||||||
|
|
||||||
|
public Configuration Config => Plugin.Config;
|
||||||
|
|
||||||
|
private string CustomTag = string.Empty;
|
||||||
|
private readonly Dictionary<uint, uint> iconToFurniture = new() { };
|
||||||
|
|
||||||
|
private readonly Vector4 PURPLE = new(0.26275f, 0.21569f, 0.56863f, 1f);
|
||||||
|
private readonly Vector4 PURPLE_ALPHA = new(0.26275f, 0.21569f, 0.56863f, 0.5f);
|
||||||
|
|
||||||
|
private FileDialogManager FileDialogManager { get; }
|
||||||
|
|
||||||
|
public ConfigurationWindow(HouseStealerPlugin plugin) : base(plugin)
|
||||||
|
{
|
||||||
|
this.FileDialogManager = new FileDialogManager
|
||||||
|
{
|
||||||
|
AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DrawAllUi()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ImGui.Begin(Plugin.Name, ref WindowVisible, ImGuiWindowFlags.NoScrollWithMouse))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ImGui.BeginChild("##SettingsRegion"))
|
||||||
|
{
|
||||||
|
DrawGeneralSettings();
|
||||||
|
if (ImGui.BeginChild("##ItemListRegion"))
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Header, PURPLE_ALPHA);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, PURPLE);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.HeaderActive, PURPLE);
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader("Interior Furniture", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui.PushID("interior");
|
||||||
|
DrawItemList(Plugin.InteriorItemList);
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader("Interior Fixtures", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui.PushID("interiorFixture");
|
||||||
|
DrawFixtureList(Plugin.Layout.interiorFixture);
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor(3);
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.FileDialogManager.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DrawUi()
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.TitleBgActive, PURPLE);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, PURPLE_ALPHA);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, PURPLE_ALPHA);
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(530, 450), ImGuiCond.FirstUseEver);
|
||||||
|
|
||||||
|
DrawAllUi();
|
||||||
|
|
||||||
|
ImGui.PopStyleColor(3);
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Helper Functions
|
||||||
|
public void DrawIcon(ushort icon, Vector2 size)
|
||||||
|
{
|
||||||
|
if (icon < 65000)
|
||||||
|
{
|
||||||
|
var iconTexture = DalamudApi.TextureProvider.GetFromGameIcon(new GameIconLookup(icon));
|
||||||
|
ImGui.Image(iconTexture.GetWrapOrEmpty().Handle, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Basic UI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void SaveLayoutToFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Plugin.GetGameLayout();
|
||||||
|
HouseStealerPlugin.LayoutManager.ExportLayout();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LogError($"Save Error: {e.Message}", e.StackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsafe private void DrawGeneralSettings()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.Text("Layout");
|
||||||
|
|
||||||
|
if (!Config.SaveLocation.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
ImGui.Text($"Current file location: {Config.SaveLocation}");
|
||||||
|
|
||||||
|
if (ImGui.Button("Save"))
|
||||||
|
{
|
||||||
|
SaveLayoutToFile();
|
||||||
|
}
|
||||||
|
if (ImGui.IsItemHovered()) ImGui.SetTooltip("Save layout to current file location");
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Save As"))
|
||||||
|
{
|
||||||
|
|
||||||
|
string saveName = "save";
|
||||||
|
if (!Config.SaveLocation.IsNullOrEmpty()) saveName = Path.GetFileNameWithoutExtension(Config.SaveLocation);
|
||||||
|
|
||||||
|
FileDialogManager.SaveFileDialog("Select a Save Location", ".json", saveName, "json", (bool ok, string res) =>
|
||||||
|
{
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.SaveLocation = res;
|
||||||
|
Config.Save();
|
||||||
|
SaveLayoutToFile();
|
||||||
|
|
||||||
|
}, Path.GetDirectoryName(Config.SaveLocation));
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ImGui.IsItemHovered()) ImGui.SetTooltip("Save layout to file");
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(0, 15));
|
||||||
|
|
||||||
|
bool hasFloors = false;
|
||||||
|
try {
|
||||||
|
hasFloors = Memory.Instance.GetCurrentTerritory() == Memory.HousingArea.Indoors && !Memory.Instance.GetIndoorHouseSize().Equals("Apartment");
|
||||||
|
} catch (NullReferenceException){
|
||||||
|
// Thanks zbee
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFloors)
|
||||||
|
{
|
||||||
|
|
||||||
|
ImGui.Text("Selected Floors");
|
||||||
|
|
||||||
|
if (ImGui.Checkbox("Basement", ref Config.Basement))
|
||||||
|
{
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
ImGui.SameLine(); ImGui.Dummy(new Vector2(10, 0)); ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Checkbox("Ground Floor", ref Config.GroundFloor))
|
||||||
|
{
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
ImGui.SameLine(); ImGui.Dummy(new Vector2(10, 0)); ImGui.SameLine();
|
||||||
|
|
||||||
|
if (Memory.Instance.HasUpperFloor() && ImGui.Checkbox("Upper Floor", ref Config.UpperFloor))
|
||||||
|
{
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(0, 15));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(0, 15));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawRow(int i, HousingItem housingItem, bool showSetPosition = true, int childIndex = -1)
|
||||||
|
{
|
||||||
|
if (!housingItem.CorrectLocation) ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
ImGui.Text($"{housingItem.X:N4}, {housingItem.Y:N4}, {housingItem.Z:N4}");
|
||||||
|
if (!housingItem.CorrectLocation) ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.NextColumn();
|
||||||
|
|
||||||
|
if (!housingItem.CorrectRotation) ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
ImGui.Text($"{Utils.radToDeg(housingItem.Rotate):N3}"); ImGui.NextColumn();
|
||||||
|
if (!housingItem.CorrectRotation) ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
var stain = DalamudApi.DataManager.GetExcelSheet<Stain>().GetRowOrDefault(housingItem.Stain);
|
||||||
|
var colorName = stain?.Name;
|
||||||
|
|
||||||
|
if (housingItem.Stain != 0)
|
||||||
|
{
|
||||||
|
Utils.StainButton("dye_" + i, stain.Value, new Vector2(20));
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (!housingItem.DyeMatch) ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
|
||||||
|
ImGui.Text($"{colorName}");
|
||||||
|
|
||||||
|
if (!housingItem.DyeMatch) ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (housingItem.MaterialItemKey != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (DalamudApi.DataManager.GetExcelSheet<Item>().TryGetRow(housingItem.MaterialItemKey, out var item))
|
||||||
|
{
|
||||||
|
if (!housingItem.DyeMatch) ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
|
||||||
|
DrawIcon(item.Icon, new Vector2(20, 20));
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(item.Name.ToString());
|
||||||
|
|
||||||
|
if (!housingItem.DyeMatch) ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ImGui.NextColumn();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawFixtureList(List<Fixture> fixtureList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Clear"))
|
||||||
|
{
|
||||||
|
fixtureList.Clear();
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Columns(3, "FixtureList", true);
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
ImGui.Text("Level"); ImGui.NextColumn();
|
||||||
|
ImGui.Text("Fixture"); ImGui.NextColumn();
|
||||||
|
ImGui.Text("Item"); ImGui.NextColumn();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
foreach (var fixture in fixtureList)
|
||||||
|
{
|
||||||
|
ImGui.Text(fixture.level); ImGui.NextColumn();
|
||||||
|
ImGui.Text(fixture.type); ImGui.NextColumn();
|
||||||
|
|
||||||
|
if (DalamudApi.DataManager.GetExcelSheet<Item>().TryGetRow(fixture.itemId, out var item))
|
||||||
|
{
|
||||||
|
DrawIcon(item.Icon, new Vector2(20, 20));
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
ImGui.Text(fixture.name); ImGui.NextColumn();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Columns(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LogError(e.Message, e.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawItemList(List<HousingItem> itemList, bool isUnused = false)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui.Button("Sort"))
|
||||||
|
{
|
||||||
|
itemList.Sort((x, y) =>
|
||||||
|
{
|
||||||
|
if (x.Name.CompareTo(y.Name) != 0)
|
||||||
|
return x.Name.CompareTo(y.Name);
|
||||||
|
if (x.X.CompareTo(y.X) != 0)
|
||||||
|
return x.X.CompareTo(y.X);
|
||||||
|
if (x.Y.CompareTo(y.Y) != 0)
|
||||||
|
return x.Y.CompareTo(y.Y);
|
||||||
|
if (x.Z.CompareTo(y.Z) != 0)
|
||||||
|
return x.Z.CompareTo(y.Z);
|
||||||
|
if (x.Rotate.CompareTo(y.Rotate) != 0)
|
||||||
|
return x.Rotate.CompareTo(y.Rotate);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Clear"))
|
||||||
|
{
|
||||||
|
itemList.Clear();
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUnused)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text("Note: Missing items, incorrect dyes, and items on unselected floors are grayed out");
|
||||||
|
}
|
||||||
|
|
||||||
|
// name, position, r, color, set
|
||||||
|
int columns = 4;
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.Columns(columns, "ItemList", true);
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Text("Item"); ImGui.NextColumn();
|
||||||
|
ImGui.Text("Position (X,Y,Z)"); ImGui.NextColumn();
|
||||||
|
ImGui.Text("Rotation"); ImGui.NextColumn();
|
||||||
|
ImGui.Text("Dye/Material"); ImGui.NextColumn();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
for (int i = 0; i < itemList.Count(); i++)
|
||||||
|
{
|
||||||
|
var housingItem = itemList[i];
|
||||||
|
var displayName = housingItem.Name;
|
||||||
|
|
||||||
|
if (DalamudApi.DataManager.GetExcelSheet<Item>().TryGetRow(housingItem.ItemKey, out var item))
|
||||||
|
{
|
||||||
|
DrawIcon(item.Icon, new Vector2(20, 20));
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (housingItem.ItemStruct == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text(displayName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.NextColumn();
|
||||||
|
// Make sure we don't try and draw a row for a housing item that doesn't exist. If it does get passed it corrupts all ImGui interfaces managed by dalamud.
|
||||||
|
DrawRow(i, housingItem, !isUnused);
|
||||||
|
if (housingItem.ItemStruct == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Columns(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Draw Screen
|
||||||
|
protected override void DrawScreen()
|
||||||
|
{
|
||||||
|
if (Config.DrawScreen)
|
||||||
|
{
|
||||||
|
DrawItemOnScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void DrawItemOnScreen()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Memory.Instance == null) return;
|
||||||
|
|
||||||
|
var itemList = Plugin.InteriorItemList;
|
||||||
|
|
||||||
|
for (int i = 0; i < itemList.Count(); i++)
|
||||||
|
{
|
||||||
|
var playerPos = DalamudApi.ClientState.LocalPlayer.Position;
|
||||||
|
var housingItem = itemList[i];
|
||||||
|
|
||||||
|
if (housingItem.ItemStruct == IntPtr.Zero) continue;
|
||||||
|
|
||||||
|
var itemStruct = (HousingItemStruct*)housingItem.ItemStruct;
|
||||||
|
|
||||||
|
var itemPos = new Vector3(itemStruct->Position.X, itemStruct->Position.Y, itemStruct->Position.Z);
|
||||||
|
if (Config.HiddenScreenItemHistory.IndexOf(i) >= 0) continue;
|
||||||
|
if (Config.DrawDistance > 0 && (playerPos - itemPos).Length() > Config.DrawDistance)
|
||||||
|
continue;
|
||||||
|
var displayName = housingItem.Name;
|
||||||
|
if (DalamudApi.GameGui.WorldToScreen(itemPos, out var screenCoords))
|
||||||
|
{
|
||||||
|
ImGui.PushID("HousingItemWindow" + i);
|
||||||
|
ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y));
|
||||||
|
ImGui.SetNextWindowBgAlpha(0.8f);
|
||||||
|
if (ImGui.Begin("HousingItem" + i,
|
||||||
|
ImGuiWindowFlags.NoDecoration |
|
||||||
|
ImGuiWindowFlags.AlwaysAutoResize |
|
||||||
|
ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoMove |
|
||||||
|
ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNav))
|
||||||
|
{
|
||||||
|
|
||||||
|
ImGui.Text(displayName);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
44
HouseStealerPlugin/Gui/Window.cs
Normal file
44
HouseStealerPlugin/Gui/Window.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Dalamud.Plugin;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin.Gui
|
||||||
|
{
|
||||||
|
public abstract class Window<T> where T : IDalamudPlugin
|
||||||
|
{
|
||||||
|
protected bool WindowVisible;
|
||||||
|
protected bool WindowCanUpload;
|
||||||
|
protected bool WindowCanImport;
|
||||||
|
public virtual bool Visible
|
||||||
|
{
|
||||||
|
get => WindowVisible;
|
||||||
|
set => WindowVisible = value;
|
||||||
|
}
|
||||||
|
public virtual bool CanUpload
|
||||||
|
{
|
||||||
|
get => WindowCanUpload;
|
||||||
|
set => WindowCanUpload = value;
|
||||||
|
}
|
||||||
|
public virtual bool CanImport
|
||||||
|
{
|
||||||
|
get => WindowCanImport;
|
||||||
|
set => WindowCanImport = value;
|
||||||
|
}
|
||||||
|
protected T Plugin { get; }
|
||||||
|
|
||||||
|
protected Window(T plugin)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
}
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
if (Visible)
|
||||||
|
{
|
||||||
|
DrawUi();
|
||||||
|
|
||||||
|
}
|
||||||
|
DrawScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void DrawUi();
|
||||||
|
protected abstract void DrawScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
327
HouseStealerPlugin/HouseStealerPlugin.cs
Normal file
327
HouseStealerPlugin/HouseStealerPlugin.cs
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using HouseStealerPlugin.Objects;
|
||||||
|
using HouseStealerPlugin.Util;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using static HouseStealerPlugin.Memory;
|
||||||
|
using HousingFurniture = Lumina.Excel.Sheets.HousingFurniture;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
|
||||||
|
public class HouseStealerPlugin : IDalamudPlugin
|
||||||
|
{
|
||||||
|
public string Name => $"House Stealer";
|
||||||
|
|
||||||
|
private string[] commandNames = ["housesteal"];
|
||||||
|
public PluginUi Gui { get; private set; }
|
||||||
|
public Configuration Config { get; private set; }
|
||||||
|
|
||||||
|
public static List<HousingItem> ItemsToPlace = new List<HousingItem>();
|
||||||
|
|
||||||
|
private delegate bool UpdateLayoutDelegate(IntPtr a1);
|
||||||
|
private HookWrapper<UpdateLayoutDelegate> IsSaveLayoutHook;
|
||||||
|
|
||||||
|
|
||||||
|
// Function for selecting an item, usually used when clicking on one in game.
|
||||||
|
public delegate void SelectItemDelegate(IntPtr housingStruct, IntPtr item);
|
||||||
|
private static HookWrapper<SelectItemDelegate> SelectItemHook;
|
||||||
|
|
||||||
|
public static SaveLayoutManager LayoutManager;
|
||||||
|
|
||||||
|
public static bool logHousingDetour = false;
|
||||||
|
|
||||||
|
internal static Location PlotLocation = new Location();
|
||||||
|
|
||||||
|
public Layout Layout = new Layout();
|
||||||
|
public List<HousingItem> InteriorItemList = new List<HousingItem>();
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
HookManager.Dispose();
|
||||||
|
|
||||||
|
DalamudApi.ClientState.TerritoryChanged -= TerritoryChanged;
|
||||||
|
foreach (string commandName in commandNames){
|
||||||
|
DalamudApi.CommandManager.RemoveHandler($"/{commandName}");
|
||||||
|
}
|
||||||
|
Gui?.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public HouseStealerPlugin(IDalamudPluginInterface pi)
|
||||||
|
{
|
||||||
|
DalamudApi.Initialize(pi);
|
||||||
|
|
||||||
|
Config = DalamudApi.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
|
Config.Save();
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
|
||||||
|
foreach (string commandName in commandNames){
|
||||||
|
DalamudApi.CommandManager.AddHandler($"/{commandName}", new CommandInfo(CommandHandler)
|
||||||
|
{
|
||||||
|
HelpMessage = "load config window."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Gui = new PluginUi(this);
|
||||||
|
DalamudApi.ClientState.TerritoryChanged += TerritoryChanged;
|
||||||
|
|
||||||
|
|
||||||
|
HousingData.Init(this);
|
||||||
|
Memory.Init();
|
||||||
|
LayoutManager = new SaveLayoutManager(this, Config);
|
||||||
|
|
||||||
|
DalamudApi.PluginLog.Info($"{Name} initialized");
|
||||||
|
}
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
IsSaveLayoutHook = HookManager.Hook<UpdateLayoutDelegate>("40 53 48 83 ec 20 48 8b d9 48 8b 0d ?? ?? ?? ?? e8 ?? ?? ?? ?? 33 d2 48 8b c8 e8 ?? ?? ?? ?? 84 c0 75 ?? 38 83 ?? 01 00 00", IsSaveLayoutDetour);
|
||||||
|
|
||||||
|
SelectItemHook = HookManager.Hook<SelectItemDelegate>("48 85 D2 0F 84 49 09 00 00 53 41 56 48 83 EC 48 48 89 6C 24 60 48 8B DA 48 89 74 24 70 4C 8B F1", SelectItemDetour);
|
||||||
|
|
||||||
|
UpdateYardObjHook = HookManager.Hook<UpdateYardDelegate>("48 89 74 24 18 57 48 83 ec 20 b8 dc 02 00 00 0f b7 f2 ??", UpdateYardObj);
|
||||||
|
|
||||||
|
GetGameObjectHook = HookManager.Hook<GetObjectDelegate>("48 89 5c 24 08 48 89 74 24 10 57 48 83 ec 20 0f b7 f2 33 db 0f 1f 40 00 0f 1f 84 00 00 00 00 00", GetGameObject);
|
||||||
|
|
||||||
|
GetObjectFromIndexHook = HookManager.Hook<GetActiveObjectDelegate>("81 fa 90 01 00 00 75 08 48 8b 81 88 0c 00 00 c3 0f b7 81 90 0c 00 00 3b d0 72 03 33 c0 c3", GetObjectFromIndex);
|
||||||
|
|
||||||
|
GetYardIndexHook = HookManager.Hook<GetIndexDelegate>("48 89 5c 24 10 57 48 83 ec 20 0f b6 d9", GetYardIndex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal delegate ushort GetIndexDelegate(byte type, byte objStruct);
|
||||||
|
internal static HookWrapper<GetIndexDelegate> GetYardIndexHook;
|
||||||
|
internal static ushort GetYardIndex(byte plotNumber, byte inventoryIndex)
|
||||||
|
{
|
||||||
|
var result = GetYardIndexHook.Original(plotNumber, inventoryIndex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate IntPtr GetActiveObjectDelegate(IntPtr ObjList, uint index);
|
||||||
|
|
||||||
|
internal static IntPtr GetObjectFromIndex(IntPtr ObjList, uint index)
|
||||||
|
{
|
||||||
|
var result = GetObjectFromIndexHook.Original(ObjList, index);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate IntPtr GetObjectDelegate(IntPtr ObjList, ushort index);
|
||||||
|
internal static HookWrapper<GetObjectDelegate> GetGameObjectHook;
|
||||||
|
internal static HookWrapper<GetActiveObjectDelegate> GetObjectFromIndexHook;
|
||||||
|
|
||||||
|
internal static IntPtr GetGameObject(IntPtr ObjList, ushort index)
|
||||||
|
{
|
||||||
|
return GetGameObjectHook.Original(ObjList, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void UpdateYardDelegate(IntPtr housingStruct, ushort index);
|
||||||
|
private static HookWrapper<UpdateYardDelegate> UpdateYardObjHook;
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateYardObj(IntPtr objectList, ushort index)
|
||||||
|
{
|
||||||
|
UpdateYardObjHook.Original(objectList, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static public void SelectItemDetour(IntPtr housing, IntPtr item)
|
||||||
|
{
|
||||||
|
SelectItemHook.Original(housing, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsafe static public void SelectItem(IntPtr item)
|
||||||
|
{
|
||||||
|
SelectItemDetour((IntPtr)Memory.Instance.HousingStructure, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public bool MatchItem(HousingItem item, uint itemKey)
|
||||||
|
{
|
||||||
|
if (item.ItemStruct != IntPtr.Zero) return false; // this item is already matched. We can skip
|
||||||
|
|
||||||
|
return item.ItemKey == itemKey && IsSelectedFloor(item.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe bool MatchExactItem(HousingItem item, uint itemKey, HousingGameObject obj)
|
||||||
|
{
|
||||||
|
if (!MatchItem(item, itemKey)) return false;
|
||||||
|
|
||||||
|
if (item.Stain != obj.color) return false;
|
||||||
|
|
||||||
|
var matNumber = obj.Item->MaterialManager->MaterialSlot1;
|
||||||
|
|
||||||
|
if (item.MaterialItemKey == 0 && matNumber == 0) return true;
|
||||||
|
else if (item.MaterialItemKey != 0 && matNumber == 0) return false;
|
||||||
|
|
||||||
|
var matItemKey = HousingData.Instance.GetMaterialItemKey(item.ItemKey, matNumber);
|
||||||
|
if (matItemKey == 0) return true;
|
||||||
|
|
||||||
|
return matItemKey == item.MaterialItemKey;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public unsafe void GetPlotLocation()
|
||||||
|
{
|
||||||
|
var mgr = Memory.Instance.HousingModule->outdoorTerritory;
|
||||||
|
var territoryId = Memory.Instance.GetTerritoryTypeId();
|
||||||
|
|
||||||
|
if (!DalamudApi.DataManager.GetExcelSheet<TerritoryType>().TryGetRow(territoryId, out var row))
|
||||||
|
{
|
||||||
|
LogError($"Cannot identify territory: {territoryId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var placeName = row.Name.ToString();
|
||||||
|
|
||||||
|
PlotLocation = Plots.Map[placeName][mgr->Plot + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsSelectedFloor(float y)
|
||||||
|
{
|
||||||
|
if (Memory.Instance.GetCurrentTerritory() != Memory.HousingArea.Indoors || Memory.Instance.GetIndoorHouseSize().Equals("Apartment")) return true;
|
||||||
|
|
||||||
|
if (y < -0.001) return Config.Basement;
|
||||||
|
if (y >= -0.001 && y < 6.999) return Config.GroundFloor;
|
||||||
|
|
||||||
|
if (y >= 6.999)
|
||||||
|
{
|
||||||
|
if (Memory.Instance.HasUpperFloor()) return Config.UpperFloor;
|
||||||
|
else return Config.GroundFloor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public unsafe void LoadInterior()
|
||||||
|
{
|
||||||
|
SaveLayoutManager.LoadInteriorFixtures();
|
||||||
|
|
||||||
|
List<HousingGameObject> dObjects;
|
||||||
|
Memory.Instance.TryGetNameSortedHousingGameObjectList(out dObjects);
|
||||||
|
|
||||||
|
InteriorItemList.Clear();
|
||||||
|
|
||||||
|
foreach (var gameObject in dObjects)
|
||||||
|
{
|
||||||
|
uint furnitureKey = gameObject.housingRowId;
|
||||||
|
|
||||||
|
if (!DalamudApi.DataManager.GetExcelSheet<HousingFurniture>().TryGetRow(furnitureKey, out var furniture)) continue;
|
||||||
|
|
||||||
|
if (!furniture.Item.IsValid) continue;
|
||||||
|
|
||||||
|
Item item = furniture.Item.Value;
|
||||||
|
|
||||||
|
if (item.RowId == 0) continue;
|
||||||
|
|
||||||
|
if (!IsSelectedFloor(gameObject.Y)) continue;
|
||||||
|
|
||||||
|
var housingItem = new HousingItem(item, gameObject);
|
||||||
|
housingItem.ItemStruct = (IntPtr)gameObject.Item;
|
||||||
|
|
||||||
|
if (gameObject.Item != null && gameObject.Item->MaterialManager != null)
|
||||||
|
{
|
||||||
|
ushort material = gameObject.Item->MaterialManager->MaterialSlot1;
|
||||||
|
housingItem.MaterialItemKey = HousingData.Instance.GetMaterialItemKey(item.RowId, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
InteriorItemList.Add(housingItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void GetGameLayout()
|
||||||
|
{
|
||||||
|
|
||||||
|
Memory Mem = Memory.Instance;
|
||||||
|
var currentTerritory = Mem.GetCurrentTerritory();
|
||||||
|
|
||||||
|
|
||||||
|
if(currentTerritory != HousingArea.Indoors)
|
||||||
|
{
|
||||||
|
throw new Exception("Can only load interior layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Mem.GetIndoorHouseSize() == null)
|
||||||
|
{
|
||||||
|
LogError("Cannot load layout in this territory");
|
||||||
|
throw new Exception("Cannot load layout in this territory");
|
||||||
|
}
|
||||||
|
var itemList = InteriorItemList;
|
||||||
|
itemList.Clear();
|
||||||
|
|
||||||
|
|
||||||
|
LoadInterior();
|
||||||
|
|
||||||
|
|
||||||
|
DalamudApi.PluginLog.Debug(String.Format("Loaded {0} furniture items", itemList.Count));
|
||||||
|
|
||||||
|
Config.HiddenScreenItemHistory = new List<int>();
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsSaveLayoutDetour(IntPtr housingStruct)
|
||||||
|
{
|
||||||
|
var result = IsSaveLayoutHook.Original(housingStruct);
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void TerritoryChanged(ushort e)
|
||||||
|
{
|
||||||
|
Config.DrawScreen = false;
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void CommandHandler(string command, string arguments)
|
||||||
|
{
|
||||||
|
var args = arguments.Trim().Replace("\"", string.Empty);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(args) || args.Equals("config", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Gui.ConfigWindow.Visible = !Gui.ConfigWindow.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LogError(e.Message, e.StackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Log(string message, string detail_message = "")
|
||||||
|
{
|
||||||
|
var msg = $"{message}";
|
||||||
|
DalamudApi.PluginLog.Info(detail_message == "" ? msg : detail_message);
|
||||||
|
DalamudApi.ChatGui.Print(msg);
|
||||||
|
}
|
||||||
|
public static void LogError(string message, string detail_message = "")
|
||||||
|
{
|
||||||
|
var msg = $"{message}";
|
||||||
|
DalamudApi.PluginLog.Error(msg);
|
||||||
|
|
||||||
|
if (detail_message.Length > 0) DalamudApi.PluginLog.Error(detail_message);
|
||||||
|
|
||||||
|
DalamudApi.ChatGui.PrintError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
66
HouseStealerPlugin/HouseStealerPlugin.csproj
Normal file
66
HouseStealerPlugin/HouseStealerPlugin.csproj
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<PluginVersion>1.0.0</PluginVersion>
|
||||||
|
<TargetFramework>net9.0-windows</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<AssemblyTitle>HouseStealerPlugin</AssemblyTitle>
|
||||||
|
<Product>HouseStealerPlugin</Product>
|
||||||
|
<Version>$(PluginVersion)</Version>
|
||||||
|
<FileVersion>$(PluginVersion)</FileVersion>
|
||||||
|
<AssemblyVersion>$(PluginVersion)</AssemblyVersion>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DalamudPackager" Version="13.0.0" />
|
||||||
|
<PackageReference Include="Lumina.Excel" Version="7.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Dalamud">
|
||||||
|
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FFXIVClientStructs">
|
||||||
|
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Lumina">
|
||||||
|
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Lumina.Excel">
|
||||||
|
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
11
HouseStealerPlugin/HouseStealerPlugin.json
Normal file
11
HouseStealerPlugin/HouseStealerPlugin.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"Author": "Lozy",
|
||||||
|
"Name": "HouseStealer Plugin",
|
||||||
|
"InternalName": "HouseStealerPlugin",
|
||||||
|
"Description": "Pirating houses was never this easy before.",
|
||||||
|
"Tags": [
|
||||||
|
"housing",
|
||||||
|
"furniture"
|
||||||
|
],
|
||||||
|
"Punchline": "irating houses was never this easy before"
|
||||||
|
}
|
||||||
133
HouseStealerPlugin/HousingData.cs
Normal file
133
HouseStealerPlugin/HousingData.cs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public class HousingData
|
||||||
|
{
|
||||||
|
private readonly Dictionary<uint, HousingFurniture> _furnitureDict;
|
||||||
|
private readonly Dictionary<uint, Item> _itemDict;
|
||||||
|
private readonly Dictionary<uint, Stain> _stainDict;
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, uint> _unitedDict;
|
||||||
|
|
||||||
|
private readonly Dictionary<ushort, uint> _wallpaper;
|
||||||
|
private readonly Dictionary<ushort, uint> _smallFishprint;
|
||||||
|
private readonly Dictionary<ushort, uint> _mediumFishprint;
|
||||||
|
private readonly Dictionary<ushort, uint> _largeFishprint;
|
||||||
|
private readonly Dictionary<ushort, uint> _extraLargeFishprint;
|
||||||
|
private readonly Dictionary<ushort, uint> _painting;
|
||||||
|
|
||||||
|
|
||||||
|
private static HouseStealerPlugin Plugin;
|
||||||
|
|
||||||
|
private HousingData()
|
||||||
|
{
|
||||||
|
var sheet = DalamudApi.DataManager.GetExcelSheet<HousingLandSet>();
|
||||||
|
uint[] terriKeys = { 339, 340, 341, 641 };
|
||||||
|
|
||||||
|
var unitedExteriorSheet = DalamudApi.DataManager.GetExcelSheet<HousingUnitedExterior>();
|
||||||
|
|
||||||
|
_unitedDict = new Dictionary<uint, uint>();
|
||||||
|
foreach (var row in unitedExteriorSheet)
|
||||||
|
foreach (var type in unitedExteriorSheet.Columns)
|
||||||
|
_unitedDict[type.Offset] = row.RowId;
|
||||||
|
|
||||||
|
|
||||||
|
_itemDict = DalamudApi.DataManager.GetExcelSheet<Item>()
|
||||||
|
.Where(item => item.AdditionalData.RowId != 0 && (item.ItemSearchCategory.RowId == 65 || item.ItemSearchCategory.RowId == 66))
|
||||||
|
.ToDictionary(row => row.AdditionalData.RowId, row => row);
|
||||||
|
|
||||||
|
_stainDict = DalamudApi.DataManager.GetExcelSheet<Stain>().ToDictionary(row => row.RowId, row => row);
|
||||||
|
_furnitureDict = DalamudApi.DataManager.GetExcelSheet<HousingFurniture>().ToDictionary(row => row.RowId, row => row);
|
||||||
|
|
||||||
|
DalamudApi.PluginLog.Info($"Loaded {_furnitureDict.Keys.Count} furniture");
|
||||||
|
DalamudApi.PluginLog.Info($"Loaded {_unitedDict.Keys.Count} united parts");
|
||||||
|
DalamudApi.PluginLog.Info($"Loaded {_stainDict.Keys.Count} dyes");
|
||||||
|
DalamudApi.PluginLog.Info($"Loaded {_itemDict.Keys.Count} items with AdditionalData");
|
||||||
|
|
||||||
|
_wallpaper = new Dictionary<ushort, uint>();
|
||||||
|
_smallFishprint = new Dictionary<ushort, uint>();
|
||||||
|
_mediumFishprint = new Dictionary<ushort, uint>();
|
||||||
|
_largeFishprint = new Dictionary<ushort, uint>();
|
||||||
|
_extraLargeFishprint = new Dictionary<ushort, uint>();
|
||||||
|
_painting = new Dictionary<ushort, uint>();
|
||||||
|
|
||||||
|
var materialSheet = DalamudApi.DataManager.GetExcelSheet<VaseFlower>();
|
||||||
|
|
||||||
|
foreach (var row in materialSheet)
|
||||||
|
{
|
||||||
|
var id = row.RowId;
|
||||||
|
|
||||||
|
if (id < 1000) continue;
|
||||||
|
else if (id > 1000 && id < 2000) _painting.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
else if (id > 2000 && id < 3000) _wallpaper.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
else if (id > 3000 && id < 4000) _smallFishprint.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
else if (id > 4000 && id < 5000) _mediumFishprint.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
else if (id > 5000 && id < 6000) _largeFishprint.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
else if (id > 6000 && id < 7000) _extraLargeFishprint.TryAdd(row.Unknown0, row.Item.RowId);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HousingData Instance { get; private set; }
|
||||||
|
|
||||||
|
public static void Init(HouseStealerPlugin plugin)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
Instance = new HousingData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TryGetFurniture(uint id, out HousingFurniture furniture)
|
||||||
|
{
|
||||||
|
return _furnitureDict.TryGetValue(id, out furniture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsUnitedExteriorPart(uint id, out Item item)
|
||||||
|
{
|
||||||
|
item = new Item();
|
||||||
|
|
||||||
|
if (!_unitedDict.TryGetValue(id, out var unitedId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_itemDict.TryGetValue(unitedId, out item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetItem(uint id, out Item item)
|
||||||
|
{
|
||||||
|
return _itemDict.TryGetValue(id, out item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetStain(uint id, out Stain stain)
|
||||||
|
{
|
||||||
|
return _stainDict.TryGetValue(id, out stain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public uint GetMaterialItemKey(uint itemId, ushort material)
|
||||||
|
{
|
||||||
|
if (material == 0) return 0;
|
||||||
|
|
||||||
|
// Angler Canvas
|
||||||
|
if (itemId == 28931) return _smallFishprint.GetValueOrDefault(material);
|
||||||
|
else if (itemId == 28932) return _mediumFishprint.GetValueOrDefault(material);
|
||||||
|
else if (itemId == 28933) return _largeFishprint.GetValueOrDefault(material);
|
||||||
|
else if (itemId == 28934) return _extraLargeFishprint.GetValueOrDefault(material);
|
||||||
|
|
||||||
|
if (itemId >= 16935 && itemId <= 16937)
|
||||||
|
{
|
||||||
|
// Picture Frame
|
||||||
|
return _painting.GetValueOrDefault(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _wallpaper.GetValueOrDefault(material);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
230
HouseStealerPlugin/Memory.cs
Normal file
230
HouseStealerPlugin/Memory.cs
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.MJI;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using Microsoft.VisualBasic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using static HouseStealerPlugin.HouseStealerPlugin;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public unsafe class Memory
|
||||||
|
{
|
||||||
|
// Pointers to modify assembly to enable place anywhere.
|
||||||
|
// public IntPtr placeAnywhere;
|
||||||
|
// public IntPtr wallAnywhere;
|
||||||
|
// public IntPtr wallmountAnywhere;
|
||||||
|
|
||||||
|
public delegate InventoryContainer* GetInventoryContainerDelegate(IntPtr inventoryManager, InventoryType inventoryType);
|
||||||
|
|
||||||
|
private Memory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// placeAnywhere = DalamudApi.SigScanner.ScanText("C6 ?? ?? ?? 00 00 00 8B FE 48 89") + 6;
|
||||||
|
// wallAnywhere = DalamudApi.SigScanner.ScanText("48 85 C0 74 ?? C6 87 ?? ?? 00 00 00") + 11;
|
||||||
|
// wallmountAnywhere = DalamudApi.SigScanner.ScanText("c6 87 83 01 00 00 00 48 83 c4 ??") + 6;
|
||||||
|
|
||||||
|
HousingModulePtr = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 8B 52");
|
||||||
|
LayoutWorldPtr = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B D1 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 0A", 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DalamudApi.PluginLog.Error(e, "Could not load housing memory!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Memory Instance { get; private set; }
|
||||||
|
|
||||||
|
private IntPtr HousingModulePtr { get; }
|
||||||
|
private IntPtr LayoutWorldPtr { get; }
|
||||||
|
|
||||||
|
public unsafe HousingModule* HousingModule => HousingModulePtr != IntPtr.Zero ? (HousingModule*)Marshal.ReadIntPtr(HousingModulePtr) : null;
|
||||||
|
public unsafe LayoutWorld* LayoutWorld => LayoutWorldPtr != IntPtr.Zero ? (LayoutWorld*)Marshal.ReadIntPtr(LayoutWorldPtr) : null;
|
||||||
|
public unsafe HousingObjectManager* CurrentManager => HousingModule->currentTerritory;
|
||||||
|
public unsafe HousingStructure* HousingStructure => LayoutWorld->HousingStruct;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
Instance = new Memory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InventoryContainer* GetContainer(InventoryType inventoryType)
|
||||||
|
{
|
||||||
|
return InventoryManager.Instance()->GetInventoryContainer(inventoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetTerritoryTypeId()
|
||||||
|
{
|
||||||
|
if (!GetActiveLayout(out var manager)) return 0;
|
||||||
|
return manager.TerritoryTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasUpperFloor()
|
||||||
|
{
|
||||||
|
var houseSize = GetIndoorHouseSize();
|
||||||
|
return houseSize.Equals("Medium") || houseSize.Equals("Large");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetIndoorHouseSize()
|
||||||
|
{
|
||||||
|
var territoryId = Memory.Instance.GetTerritoryTypeId();
|
||||||
|
|
||||||
|
if (!DalamudApi.DataManager.GetExcelSheet<TerritoryType>().TryGetRow(territoryId, out var row)) return null;
|
||||||
|
|
||||||
|
var placeName = row.Name.ToString();
|
||||||
|
var sizeName = placeName.Substring(1, 3);
|
||||||
|
|
||||||
|
switch (sizeName)
|
||||||
|
{
|
||||||
|
case "1i1":
|
||||||
|
return "Small";
|
||||||
|
|
||||||
|
case "1i2":
|
||||||
|
return "Medium";
|
||||||
|
|
||||||
|
case "1i3":
|
||||||
|
return "Large";
|
||||||
|
|
||||||
|
case "1i4":
|
||||||
|
return "Apartment";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetInteriorLightLevel()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (GetCurrentTerritory() != HousingArea.Indoors) return 0f;
|
||||||
|
if (!GetActiveLayout(out var manager)) return 0f;
|
||||||
|
if (!manager.IndoorAreaData.HasValue) return 0f;
|
||||||
|
return manager.IndoorAreaData.Value.LightLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommonFixture[] GetInteriorCommonFixtures(int floorId)
|
||||||
|
{
|
||||||
|
if (GetCurrentTerritory() != HousingArea.Indoors) return [];
|
||||||
|
if (!GetActiveLayout(out var manager)) return [];
|
||||||
|
if (!manager.IndoorAreaData.HasValue) return [];
|
||||||
|
var floor = manager.IndoorAreaData.Value.GetFloor(floorId);
|
||||||
|
|
||||||
|
var ret = new CommonFixture[IndoorFloorData.PartsMax];
|
||||||
|
for (var i = 0; i < IndoorFloorData.PartsMax; i++)
|
||||||
|
{
|
||||||
|
var key = floor.GetPart(i);
|
||||||
|
if (!HousingData.Instance.TryGetItem(unchecked((uint)key), out var item))
|
||||||
|
HousingData.Instance.IsUnitedExteriorPart(unchecked((uint)key), out item);
|
||||||
|
|
||||||
|
ret[i] = new CommonFixture(
|
||||||
|
false,
|
||||||
|
i,
|
||||||
|
key,
|
||||||
|
null,
|
||||||
|
item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public unsafe bool TryGetNameSortedHousingGameObjectList(out List<HousingGameObject> objects)
|
||||||
|
{
|
||||||
|
objects = null;
|
||||||
|
if (HousingModule == null ||
|
||||||
|
HousingModule->GetCurrentManager() == null ||
|
||||||
|
HousingModule->GetCurrentManager()->Objects == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
objects = new List<HousingGameObject>();
|
||||||
|
|
||||||
|
for (var i = 0; i < 400; i++)
|
||||||
|
{
|
||||||
|
var oPtr = HousingModule->GetCurrentManager()->Objects[i];
|
||||||
|
if (oPtr == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var o = *(HousingGameObject*)oPtr;
|
||||||
|
|
||||||
|
objects.Add(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
objects.Sort(
|
||||||
|
(obj1, obj2) =>
|
||||||
|
{
|
||||||
|
string name1 = "", name2 = "";
|
||||||
|
if (HousingData.Instance.TryGetFurniture(obj1.housingRowId, out var furniture1))
|
||||||
|
name1 = furniture1.Item.Value.Name.ToString();
|
||||||
|
|
||||||
|
if (HousingData.Instance.TryGetFurniture(obj2.housingRowId, out var furniture2))
|
||||||
|
name2 = furniture2.Item.Value.Name.ToString();
|
||||||
|
|
||||||
|
return string.Compare(name1, name2, StringComparison.Ordinal);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public unsafe bool GetActiveLayout(out LayoutManager manager)
|
||||||
|
{
|
||||||
|
manager = new LayoutManager();
|
||||||
|
if (LayoutWorld == null ||
|
||||||
|
LayoutWorld->ActiveLayout == null)
|
||||||
|
return false;
|
||||||
|
manager = *LayoutWorld->ActiveLayout;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetHousingController(out HousingController controller)
|
||||||
|
{
|
||||||
|
controller = new HousingController();
|
||||||
|
if (!GetActiveLayout(out var manager) ||
|
||||||
|
!manager.HousingController.HasValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
controller = manager.HousingController.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HousingArea
|
||||||
|
{
|
||||||
|
Indoors,
|
||||||
|
Outdoors,
|
||||||
|
Island,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe HousingArea GetCurrentTerritory()
|
||||||
|
{
|
||||||
|
if (!DalamudApi.DataManager.GetExcelSheet<TerritoryType>().TryGetRow(GetTerritoryTypeId(), out var territoryRow))
|
||||||
|
{
|
||||||
|
var territoryRowId = GetTerritoryTypeId();
|
||||||
|
if (territoryRowId != 0) { DalamudApi.PluginLog.Debug($"Invalid territory row: {territoryRowId}"); }
|
||||||
|
return HousingArea.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (territoryRow.Equals(null) || territoryRow.Name.ToString().Equals("r1i5")) // blacklist company workshop from editing since it's not actually a housing area
|
||||||
|
{
|
||||||
|
return HousingArea.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (territoryRow.Name.ToString().Equals("h1m2"))
|
||||||
|
{
|
||||||
|
return HousingArea.Island;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HousingModule == null) return HousingArea.None;
|
||||||
|
|
||||||
|
if (HousingModule->IsOutdoors()) return HousingArea.Outdoors;
|
||||||
|
else return HousingArea.Indoors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
47
HouseStealerPlugin/Objects/HousingItem.cs
Normal file
47
HouseStealerPlugin/Objects/HousingItem.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin.Objects
|
||||||
|
{
|
||||||
|
public class HousingItem
|
||||||
|
{
|
||||||
|
public uint ItemKey;
|
||||||
|
public byte Stain;
|
||||||
|
public uint MaterialItemKey = 0;
|
||||||
|
public float X;
|
||||||
|
public float Y;
|
||||||
|
public float Z;
|
||||||
|
public float Rotate;
|
||||||
|
public string Name = "";
|
||||||
|
public IntPtr ItemStruct = IntPtr.Zero;
|
||||||
|
public bool DyeMatch = true;
|
||||||
|
public bool CorrectLocation = true;
|
||||||
|
public bool CorrectRotation = true;
|
||||||
|
public bool IsTableOrWallMounted = false;
|
||||||
|
|
||||||
|
public HousingItem(Item item, byte stain, float x, float y, float z, float rotate)
|
||||||
|
{
|
||||||
|
ItemKey = item.RowId;
|
||||||
|
Name = item.Name.ExtractText();
|
||||||
|
|
||||||
|
IsTableOrWallMounted = item.ItemUICategory.Value.RowId == 78 || item.ItemUICategory.Value.RowId == 79;
|
||||||
|
|
||||||
|
Stain = stain;
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
Rotate = rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HousingItem(Item item, HousingGameObject gameObject)
|
||||||
|
: this(item, gameObject.color, gameObject.X, gameObject.Y, gameObject.Z, gameObject.rotation)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetLocation()
|
||||||
|
{
|
||||||
|
return new Vector3(X, Y, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
358
HouseStealerPlugin/Objects/Structs.cs
Normal file
358
HouseStealerPlugin/Objects/Structs.cs
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public enum SortType
|
||||||
|
{
|
||||||
|
Distance,
|
||||||
|
Name
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ExteriorPartsType
|
||||||
|
{
|
||||||
|
None = -1,
|
||||||
|
Roof = 0,
|
||||||
|
Walls,
|
||||||
|
Windows,
|
||||||
|
Door,
|
||||||
|
RoofOpt,
|
||||||
|
WallOpt,
|
||||||
|
SignOpt,
|
||||||
|
Fence
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InteriorFloor
|
||||||
|
{
|
||||||
|
None = -1,
|
||||||
|
Ground = 0,
|
||||||
|
Upstairs,
|
||||||
|
Basement,
|
||||||
|
External
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InteriorPartsType
|
||||||
|
{
|
||||||
|
None = -1,
|
||||||
|
Walls,
|
||||||
|
Windows,
|
||||||
|
Door,
|
||||||
|
Floor,
|
||||||
|
Light
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CommonFixture
|
||||||
|
{
|
||||||
|
public bool IsExterior;
|
||||||
|
public int FixtureType;
|
||||||
|
public int FixtureKey;
|
||||||
|
public Stain? Stain;
|
||||||
|
public Item? Item;
|
||||||
|
|
||||||
|
public CommonFixture(bool isExterior, int fixtureType, int fixtureKey, Stain? stain, Item item)
|
||||||
|
{
|
||||||
|
IsExterior = isExterior;
|
||||||
|
FixtureType = fixtureType;
|
||||||
|
FixtureKey = fixtureKey;
|
||||||
|
Stain = stain;
|
||||||
|
Item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HousingLayoutMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Move,
|
||||||
|
Rotate,
|
||||||
|
Store,
|
||||||
|
Place,
|
||||||
|
Remove = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ItemState
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Hover,
|
||||||
|
SoftSelect,
|
||||||
|
Active
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct HousingItemStruct
|
||||||
|
{
|
||||||
|
[FieldOffset(0x50)] public Vector3 Position;
|
||||||
|
[FieldOffset(0x60)] public Quaternion Rotation;
|
||||||
|
[FieldOffset(0xF8)] public ItemMaterialManager* MaterialManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct ItemMaterialManager
|
||||||
|
{
|
||||||
|
[FieldOffset(0xcc)] public ushort MaterialSlot1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct HousingStructure
|
||||||
|
{
|
||||||
|
[FieldOffset(0x0)] public HousingLayoutMode Mode;
|
||||||
|
[FieldOffset(0x4)] public HousingLayoutMode LastMode;
|
||||||
|
[FieldOffset(0x8)] public ItemState State;
|
||||||
|
[FieldOffset(0x10)] public HousingItemStruct* HoverItem;
|
||||||
|
[FieldOffset(0x18)] public HousingItemStruct* ActiveItem;
|
||||||
|
[FieldOffset(0xB8)] public bool Rotating;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This is just a GameObject
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 0x1D0)]
|
||||||
|
public unsafe struct HousingGameObject
|
||||||
|
{
|
||||||
|
[FieldOffset(0x030)] public fixed byte name[64];
|
||||||
|
[FieldOffset(0x084)] public uint housingRowId;
|
||||||
|
[FieldOffset(0x088)] public uint OwnerID;
|
||||||
|
[FieldOffset(0x0B0)] public float X;
|
||||||
|
[FieldOffset(0x0B4)] public float Y;
|
||||||
|
[FieldOffset(0x0B8)] public float Z;
|
||||||
|
[FieldOffset(0x108)] public HousingItemStruct* Item;
|
||||||
|
[FieldOffset(0x0C0)] public float rotation;
|
||||||
|
[FieldOffset(0x1A8)] public uint housingRowId2;
|
||||||
|
[FieldOffset(0x1B0)] public byte color;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct HousingObjectManager
|
||||||
|
{
|
||||||
|
[FieldOffset(0x0010)] public IntPtr ObjectList;
|
||||||
|
[FieldOffset(0x8980)] public fixed ulong Objects[400];
|
||||||
|
|
||||||
|
[FieldOffset(0x96A2)] public byte Ward;
|
||||||
|
[FieldOffset(0x96A8)] public byte Plot;
|
||||||
|
|
||||||
|
[FieldOffset(0x96E8)] public HousingGameObject* IndoorActiveObject2;
|
||||||
|
[FieldOffset(0x96F0)] public HousingGameObject* IndoorHoverObject;
|
||||||
|
[FieldOffset(0x96F8)] public HousingGameObject* IndoorActiveObject;
|
||||||
|
[FieldOffset(0x9AB8)] public HousingGameObject* OutdoorActiveObject2;
|
||||||
|
[FieldOffset(0x9AC0)] public HousingGameObject* OutdoorHoverObject;
|
||||||
|
[FieldOffset(0x9AC8)] public HousingGameObject* OutdoorActiveObject;
|
||||||
|
|
||||||
|
public static FFXIVClientStructs.FFXIV.Client.Game.HousingFurniture* GetItemInfo(HousingObjectManager* mgr, int index)
|
||||||
|
{
|
||||||
|
var objectListAddr = (IntPtr)mgr + 0x10;
|
||||||
|
|
||||||
|
return (FFXIVClientStructs.FFXIV.Client.Game.HousingFurniture*)(objectListAddr + (0x30 * index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct HousingModule
|
||||||
|
{
|
||||||
|
[FieldOffset(0x0)] public HousingObjectManager* currentTerritory;
|
||||||
|
[FieldOffset(0x8)] public HousingObjectManager* outdoorTerritory;
|
||||||
|
[FieldOffset(0x10)] public HousingObjectManager* indoorTerritory;
|
||||||
|
// [FieldOffset(0x9704)] public uint CurrentIndoorFloor;
|
||||||
|
|
||||||
|
public HousingObjectManager* GetCurrentManager()
|
||||||
|
{
|
||||||
|
return outdoorTerritory != null ? outdoorTerritory : indoorTerritory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsOutdoors()
|
||||||
|
{
|
||||||
|
return outdoorTerritory != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsIndoors()
|
||||||
|
{
|
||||||
|
return indoorTerritory != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct LayoutWorld
|
||||||
|
{
|
||||||
|
[FieldOffset(0x20)] public LayoutManager* ActiveLayout;
|
||||||
|
[FieldOffset(0x40)] public HousingStructure* HousingStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct LayoutManager
|
||||||
|
{
|
||||||
|
[FieldOffset(0x20)] public uint TerritoryTypeId;
|
||||||
|
[FieldOffset(0x80)] private readonly IntPtr _housingController;
|
||||||
|
[FieldOffset(0x90)] private readonly IntPtr _indoorAreaData;
|
||||||
|
|
||||||
|
public HousingController? HousingController
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_housingController == IntPtr.Zero) return null;
|
||||||
|
// return Unsafe.Read<HousingController>(_housingController.ToPointer());
|
||||||
|
// return Marshal.PtrToStructure<HousingController>(_housingController);
|
||||||
|
// return *(HousingController*) _housingController;
|
||||||
|
|
||||||
|
return global::HouseStealerPlugin.HousingController.Get(_housingController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndoorAreaData? IndoorAreaData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_indoorAreaData == IntPtr.Zero) return null;
|
||||||
|
return global::HouseStealerPlugin.IndoorAreaData.Get(_indoorAreaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe struct IndoorAreaData
|
||||||
|
{
|
||||||
|
public static IndoorAreaData Get(IntPtr address)
|
||||||
|
{
|
||||||
|
return new(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndoorAreaData(IntPtr thisPtr)
|
||||||
|
{
|
||||||
|
this._thisPtr = thisPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const int FloorMax = 4;
|
||||||
|
private readonly IntPtr _thisPtr;
|
||||||
|
|
||||||
|
public IndoorFloorData GetFloor(InteriorFloor index)
|
||||||
|
{
|
||||||
|
return IndoorFloorData.Get(new IntPtr((byte*)_thisPtr + (0x28 + (int)index * 0x14)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndoorFloorData GetFloor(int index)
|
||||||
|
{
|
||||||
|
return IndoorFloorData.Get(new IntPtr((byte*)_thisPtr + (0x28 + index * 0x14)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LightLevel => *(float*)((byte*)_thisPtr + 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe struct IndoorFloorData
|
||||||
|
{
|
||||||
|
public static IndoorFloorData Get(IntPtr address)
|
||||||
|
{
|
||||||
|
return new(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndoorFloorData(IntPtr thisPtr)
|
||||||
|
{
|
||||||
|
this._thisPtr = thisPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const int PartsMax = 5;
|
||||||
|
private readonly IntPtr _thisPtr;
|
||||||
|
|
||||||
|
public int GetPart(InteriorPartsType index)
|
||||||
|
{
|
||||||
|
return *(int*)((byte*)_thisPtr + (int)index * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns key in sheet
|
||||||
|
public int GetPart(int index)
|
||||||
|
{
|
||||||
|
|
||||||
|
return *(int*)(byte*)(_thisPtr + index * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [StructLayout(LayoutKind.Explicit, Size = 28336)]
|
||||||
|
public unsafe struct HousingController
|
||||||
|
{
|
||||||
|
public static HousingController Get(IntPtr address)
|
||||||
|
{
|
||||||
|
return new(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HousingController(IntPtr thisPtr)
|
||||||
|
{
|
||||||
|
this._thisPtr = thisPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const int HousesMax = 60;
|
||||||
|
private readonly IntPtr _thisPtr;
|
||||||
|
|
||||||
|
//[FieldOffset(0x8)]
|
||||||
|
public uint AreaType => *(uint*)(byte*)_thisPtr + 0x8;
|
||||||
|
|
||||||
|
// [FieldOffset(0x1F0)]
|
||||||
|
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)]
|
||||||
|
// The size of the parent type of HouseCustomize is 464 even though HouseCustomize is 352
|
||||||
|
public HouseCustomize Houses(int index)
|
||||||
|
{
|
||||||
|
return HouseCustomize.Get(new IntPtr((byte*)_thisPtr + (0x1F0 + index * 464)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [StructLayout(LayoutKind.Explicit, Size = 352)]
|
||||||
|
public unsafe struct HouseCustomize
|
||||||
|
{
|
||||||
|
public static HouseCustomize Get(IntPtr address)
|
||||||
|
{
|
||||||
|
return new(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HouseCustomize(IntPtr thisPtr)
|
||||||
|
{
|
||||||
|
this._thisPtr = thisPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const int PartsMax = 8;
|
||||||
|
private readonly IntPtr _thisPtr;
|
||||||
|
|
||||||
|
//[FieldOffset(0x10)]
|
||||||
|
public int Size => *(int*)(byte*)_thisPtr + 0x10;
|
||||||
|
|
||||||
|
public HousePart GetPart(int type)
|
||||||
|
{
|
||||||
|
return *(HousePart*)((byte*)_thisPtr + (0x20 + type * 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
public HousePart GetPart(ExteriorPartsType type)
|
||||||
|
{
|
||||||
|
return *(HousePart*)((byte*)_thisPtr + (0x20 + (int)type * 40));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 40)]
|
||||||
|
public unsafe struct HousePart
|
||||||
|
{
|
||||||
|
[FieldOffset(0x00)] public int Category;
|
||||||
|
[FieldOffset(0x04)] private readonly int Unknown1;
|
||||||
|
[FieldOffset(0x08)] public ushort FixtureKey;
|
||||||
|
[FieldOffset(0x0A)] public byte Color;
|
||||||
|
[FieldOffset(0x0B)] private readonly byte Padding;
|
||||||
|
[FieldOffset(0x0C)] private readonly int Unknown2;
|
||||||
|
[FieldOffset(0x10)] private readonly void* Unknown3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is just MJIManager
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct MjiManagerExtended
|
||||||
|
{
|
||||||
|
[FieldOffset(0x160)] public IslandObjectManager* ObjectManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct IslandObjectManager
|
||||||
|
{
|
||||||
|
[FieldOffset(0x78)] public IslandFurnitureManager* FurnitureManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct IslandFurnitureManager
|
||||||
|
{
|
||||||
|
[FieldOffset(0x1698)] public IntPtr ObjectList;
|
||||||
|
[FieldOffset(0x16A0)] public fixed ulong Objects[400];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
HouseStealerPlugin/PluginUi.cs
Normal file
39
HouseStealerPlugin/PluginUi.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using HouseStealerPlugin.Gui;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public class PluginUi : IDisposable
|
||||||
|
{
|
||||||
|
private readonly HouseStealerPlugin _plugin;
|
||||||
|
public ConfigurationWindow ConfigWindow { get; }
|
||||||
|
|
||||||
|
public PluginUi(HouseStealerPlugin plugin)
|
||||||
|
{
|
||||||
|
ConfigWindow = new ConfigurationWindow(plugin);
|
||||||
|
|
||||||
|
_plugin = plugin;
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.Draw += Draw;
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.OpenMainUi += OnOpenConfigUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Draw()
|
||||||
|
{
|
||||||
|
ConfigWindow.Draw();
|
||||||
|
}
|
||||||
|
private void OnOpenConfigUi()
|
||||||
|
{
|
||||||
|
ConfigWindow.Visible = true;
|
||||||
|
ConfigWindow.CanUpload = false;
|
||||||
|
ConfigWindow.CanImport = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.Draw -= Draw;
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi;
|
||||||
|
DalamudApi.PluginInterface.UiBuilder.OpenMainUi -= OnOpenConfigUi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
342
HouseStealerPlugin/SaveLayoutManager.cs
Normal file
342
HouseStealerPlugin/SaveLayoutManager.cs
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Text.Unicode;
|
||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using HouseStealerPlugin.Objects;
|
||||||
|
using static HouseStealerPlugin.HouseStealerPlugin;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
|
||||||
|
public class Transform
|
||||||
|
{
|
||||||
|
public List<float> location { get; set; } = new List<float> { 0, 0, 0 };
|
||||||
|
public List<float> rotation { get; set; } = new List<float> { 0, 0, 0, 1 };
|
||||||
|
public List<float> scale { get; set; } = new List<float> { 1, 1, 1 };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BasicItem
|
||||||
|
{
|
||||||
|
public string name { get; set; } = "";
|
||||||
|
public uint itemId { get; set; } = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Fixture : BasicItem
|
||||||
|
{
|
||||||
|
public string level { get; set; } = "";
|
||||||
|
public string type { get; set; } = "";
|
||||||
|
|
||||||
|
public Fixture() { }
|
||||||
|
|
||||||
|
public Fixture(string inType)
|
||||||
|
{
|
||||||
|
type = inType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fixture(string inType, string inName) : this(inType)
|
||||||
|
{
|
||||||
|
name = inName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fixture(string inType, string inName, string inLevel) : this(inType, inName)
|
||||||
|
{
|
||||||
|
level = inLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Furniture : BasicItem
|
||||||
|
{
|
||||||
|
public Transform transform { get; set; } = new Transform();
|
||||||
|
|
||||||
|
public Dictionary<string, object> properties { get; set; } = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
public List<Furniture> attachments { get; set; } = new List<Furniture>();
|
||||||
|
|
||||||
|
public Color GetColor()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (properties.TryGetValue("color", out object colorObj))
|
||||||
|
{
|
||||||
|
var color = (string)colorObj;
|
||||||
|
return System.Drawing.ColorTranslator.FromHtml("#" + color.Substring(0, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicItem GetMaterial()
|
||||||
|
{
|
||||||
|
if (properties.TryGetValue("material", out object materialObj))
|
||||||
|
{
|
||||||
|
if (materialObj is JsonElement materialJson)
|
||||||
|
{
|
||||||
|
return materialJson.Deserialize<BasicItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BasicItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ColorDiff(Color c1, Color c2)
|
||||||
|
{
|
||||||
|
return (int)Math.Sqrt((c1.R - c2.R) * (c1.R - c2.R)
|
||||||
|
+ (c1.G - c2.G) * (c1.G - c2.G)
|
||||||
|
+ (c1.B - c2.B) * (c1.B - c2.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetClosestStain(List<(Color, uint)> colorList)
|
||||||
|
{
|
||||||
|
var color = GetColor();
|
||||||
|
var minDist = 2000;
|
||||||
|
uint closestStain = 0;
|
||||||
|
|
||||||
|
foreach (var testTuple in colorList)
|
||||||
|
{
|
||||||
|
var currentDist = ColorDiff(testTuple.Item1, color);
|
||||||
|
if (currentDist < minDist)
|
||||||
|
{
|
||||||
|
minDist = currentDist;
|
||||||
|
closestStain = testTuple.Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closestStain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Layout
|
||||||
|
{
|
||||||
|
public Transform playerTransform { get; set; } = new Transform();
|
||||||
|
|
||||||
|
public string houseSize { get; set; } = "";
|
||||||
|
|
||||||
|
public float interiorScale { get; set; } = 1;
|
||||||
|
|
||||||
|
public List<Fixture> interiorFixture { get; set; } = new List<Fixture>();
|
||||||
|
|
||||||
|
public List<Furniture> interiorFurniture { get; set; } = new List<Furniture>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObjectToInferredTypesConverter : JsonConverter<object>
|
||||||
|
{
|
||||||
|
public override object Read(
|
||||||
|
ref Utf8JsonReader reader,
|
||||||
|
Type typeToConvert,
|
||||||
|
JsonSerializerOptions options) => reader.TokenType switch
|
||||||
|
{
|
||||||
|
JsonTokenType.True => true,
|
||||||
|
JsonTokenType.False => false,
|
||||||
|
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
|
||||||
|
JsonTokenType.Number => reader.GetDouble(),
|
||||||
|
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
|
||||||
|
JsonTokenType.String => reader.GetString()!,
|
||||||
|
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void Write(
|
||||||
|
Utf8JsonWriter writer,
|
||||||
|
object objectToWrite,
|
||||||
|
JsonSerializerOptions options) =>
|
||||||
|
JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SaveLayoutManager
|
||||||
|
{
|
||||||
|
public static Configuration Config;
|
||||||
|
public static HouseStealerPlugin Plugin;
|
||||||
|
|
||||||
|
public static List<(Color, uint)> ColorList;
|
||||||
|
|
||||||
|
public SaveLayoutManager(HouseStealerPlugin plugin, Configuration config)
|
||||||
|
{
|
||||||
|
Config = config;
|
||||||
|
Plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float layoutScale = 1;
|
||||||
|
|
||||||
|
|
||||||
|
private float scale(float i)
|
||||||
|
{
|
||||||
|
|
||||||
|
return checkZero(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float checkZero(float i)
|
||||||
|
{
|
||||||
|
if (Math.Abs(i) < 0.001) return 0;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<float> RotationToQuat(float rotation)
|
||||||
|
{
|
||||||
|
Quaternion q = Quaternion.CreateFromYawPitchRoll(0, 0, rotation);
|
||||||
|
|
||||||
|
return new List<float> { checkZero(q.X), checkZero(q.Y), checkZero(q.Z), checkZero(q.W) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void LoadInteriorFixtures()
|
||||||
|
{
|
||||||
|
var layout = Plugin.Layout;
|
||||||
|
layout.interiorFixture.Clear();
|
||||||
|
|
||||||
|
for (var i = 0; i < IndoorAreaData.FloorMax; i++)
|
||||||
|
{
|
||||||
|
var fixtures = Memory.Instance.GetInteriorCommonFixtures(i);
|
||||||
|
if (fixtures.Length == 0) continue;
|
||||||
|
|
||||||
|
for (var j = 0; j < IndoorFloorData.PartsMax; j++)
|
||||||
|
{
|
||||||
|
if (fixtures[j].FixtureKey == -1 || fixtures[j].FixtureKey == 0) continue;
|
||||||
|
if (!fixtures[j].Item.HasValue) continue;
|
||||||
|
|
||||||
|
var item = fixtures[j].Item.Value;
|
||||||
|
if (item.RowId == 0) continue;
|
||||||
|
|
||||||
|
var fixture = new Fixture();
|
||||||
|
fixture.type = Utils.GetInteriorPartDescriptor((InteriorPartsType)j);
|
||||||
|
fixture.level = Utils.GetFloorDescriptor((InteriorFloor)i);
|
||||||
|
|
||||||
|
fixture.name = item.Name.ExtractText();
|
||||||
|
fixture.itemId = item.RowId;
|
||||||
|
|
||||||
|
layout.interiorFixture.Add(fixture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.houseSize = Memory.Instance.GetIndoorHouseSize();
|
||||||
|
|
||||||
|
var territoryId = Memory.Instance.GetTerritoryTypeId();
|
||||||
|
|
||||||
|
if (DalamudApi.DataManager.GetExcelSheet<TerritoryType>().TryGetRow(territoryId, out var row))
|
||||||
|
{
|
||||||
|
var placeName = row.Name.ToString();
|
||||||
|
|
||||||
|
var district = new Fixture();
|
||||||
|
district.type = "District";
|
||||||
|
|
||||||
|
var districtName = placeName.Substring(0, 2);
|
||||||
|
|
||||||
|
switch (districtName)
|
||||||
|
{
|
||||||
|
case "s1":
|
||||||
|
district.name = "Mist";
|
||||||
|
break;
|
||||||
|
case "f1":
|
||||||
|
district.name = "Lavender Beds";
|
||||||
|
break;
|
||||||
|
case "w1":
|
||||||
|
district.name = "Goblet";
|
||||||
|
break;
|
||||||
|
case "e1":
|
||||||
|
district.name = "Shirogane";
|
||||||
|
break;
|
||||||
|
case "r1":
|
||||||
|
district.name = "Empyreum";
|
||||||
|
break;
|
||||||
|
case "h1":
|
||||||
|
district.name = "Minimalist";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
layout.interiorFixture.Add(district);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordFurniture(List<Furniture> furnitureList, List<HousingItem> itemList)
|
||||||
|
{
|
||||||
|
HousingData Data = HousingData.Instance;
|
||||||
|
furnitureList.Clear();
|
||||||
|
foreach (HousingItem gameObject in itemList)
|
||||||
|
{
|
||||||
|
|
||||||
|
var furniture = new Furniture();
|
||||||
|
|
||||||
|
furniture.name = gameObject.Name;
|
||||||
|
furniture.itemId = gameObject.ItemKey;
|
||||||
|
furniture.transform.location = new List<float> { scale(gameObject.X), scale(gameObject.Z), scale(gameObject.Y) };
|
||||||
|
furniture.transform.rotation = RotationToQuat(-gameObject.Rotate);
|
||||||
|
|
||||||
|
if (gameObject.Stain != 0 && Data.TryGetStain(gameObject.Stain, out var stainColor))
|
||||||
|
{
|
||||||
|
|
||||||
|
var color = Utils.StainToVector4(stainColor.Color);
|
||||||
|
var cr = (int)(color.X * 255);
|
||||||
|
var cg = (int)(color.Y * 255);
|
||||||
|
var cb = (int)(color.Z * 255);
|
||||||
|
var ca = (int)(color.W * 255);
|
||||||
|
|
||||||
|
furniture.properties.Add("color", $"{cr:X2}{cg:X2}{cb:X2}{ca:X2}");
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (gameObject.MaterialItemKey != 0)
|
||||||
|
{
|
||||||
|
if (DalamudApi.DataManager.GetExcelSheet<Item>().TryGetRow(gameObject.MaterialItemKey, out var item))
|
||||||
|
{
|
||||||
|
var basicItem = new BasicItem();
|
||||||
|
basicItem.name = item.Name.ToString();
|
||||||
|
basicItem.itemId = gameObject.MaterialItemKey;
|
||||||
|
furniture.properties.Add("material", basicItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
furnitureList.Add(furniture);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExportLayout()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Directory.Exists(Config.SaveLocation))
|
||||||
|
{
|
||||||
|
throw new Exception("Save file not specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout save = Plugin.Layout;
|
||||||
|
save.playerTransform = new Transform();
|
||||||
|
|
||||||
|
save.interiorScale = 1;
|
||||||
|
|
||||||
|
RecordFurniture(save.interiorFurniture, Plugin.InteriorItemList);
|
||||||
|
|
||||||
|
var encoderSettings = new TextEncoderSettings();
|
||||||
|
encoderSettings.AllowCharacters('\'');
|
||||||
|
encoderSettings.AllowRange(UnicodeRanges.BasicLatin);
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
WriteIndented = true,
|
||||||
|
Converters = { new ObjectToInferredTypesConverter() }
|
||||||
|
|
||||||
|
};
|
||||||
|
string jsonString = JsonSerializer.Serialize(save, options);
|
||||||
|
|
||||||
|
string pattern = @"\s+(-?(?:[0-9]*[.])?[0-9]+(?:E-[0-9]+)?,?)\s*(?=\s[-\d\]])";
|
||||||
|
string result = Regex.Replace(jsonString, pattern, " $1");
|
||||||
|
|
||||||
|
File.WriteAllText(Config.SaveLocation, result);
|
||||||
|
|
||||||
|
|
||||||
|
Log("Finished exporting layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
45
HouseStealerPlugin/Util/HookManager.cs
Normal file
45
HouseStealerPlugin/Util/HookManager.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public class HookManager
|
||||||
|
{
|
||||||
|
public static List<IHookWrapper> HookList = new();
|
||||||
|
|
||||||
|
|
||||||
|
public static void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var hook in HookList.Where(hook => !hook.IsDisposed))
|
||||||
|
{
|
||||||
|
if (hook.IsEnabled)
|
||||||
|
hook.Disable();
|
||||||
|
hook.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
HookList.Clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HookWrapper<T> Hook<T>(string signature, T detour, bool enable = true, int addressOffset = 0)
|
||||||
|
where T : Delegate
|
||||||
|
{
|
||||||
|
var addr = DalamudApi.SigScanner.ScanText(signature);
|
||||||
|
|
||||||
|
return HookAddress(addr, detour, enable, addressOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HookWrapper<T> HookAddress<T>(IntPtr addr, T detour, bool enable = true, int addressOffset = 0) where T : Delegate
|
||||||
|
{
|
||||||
|
DalamudApi.PluginLog.Info($"Hooking {detour.Method.Name} at {addr.ToString("X")}");
|
||||||
|
|
||||||
|
var h = DalamudApi.Hooks.HookFromAddress(addr + addressOffset, detour);
|
||||||
|
var wh = new HookWrapper<T>(h);
|
||||||
|
if (enable) wh.Enable();
|
||||||
|
HookList.Add(wh);
|
||||||
|
return wh;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
55
HouseStealerPlugin/Util/HookWrapper.cs
Normal file
55
HouseStealerPlugin/Util/HookWrapper.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
// based on https://github.com/Caraxi/SimpleTweaksPlugin/blob/main/Helper/HookWrapper.cs
|
||||||
|
public interface IHookWrapper : IDisposable
|
||||||
|
{
|
||||||
|
public bool IsEnabled { get; }
|
||||||
|
public bool IsDisposed { get; }
|
||||||
|
public void Enable();
|
||||||
|
public void Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HookWrapper<T> : IHookWrapper where T : Delegate
|
||||||
|
{
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
private readonly Hook<T> wrappedHook;
|
||||||
|
|
||||||
|
public HookWrapper(Hook<T> hook)
|
||||||
|
{
|
||||||
|
wrappedHook = hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Original => wrappedHook.Original;
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
{
|
||||||
|
if (disposed) return;
|
||||||
|
wrappedHook?.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
{
|
||||||
|
if (disposed) return;
|
||||||
|
wrappedHook?.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DalamudApi.PluginLog.Info("Disposing of {cdelegate}", typeof(T).Name);
|
||||||
|
Disable();
|
||||||
|
disposed = true;
|
||||||
|
wrappedHook?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Address => wrappedHook.Address;
|
||||||
|
|
||||||
|
public bool IsEnabled => wrappedHook.IsEnabled;
|
||||||
|
public bool IsDisposed => wrappedHook.IsDisposed;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
58
HouseStealerPlugin/Util/MoveUtil.cs
Normal file
58
HouseStealerPlugin/Util/MoveUtil.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public static class QuaternionExtensions
|
||||||
|
{
|
||||||
|
public static float ComputeXAngle(this Quaternion q)
|
||||||
|
{
|
||||||
|
float sinr_cosp = 2 * (q.W * q.X + q.Y * q.Z);
|
||||||
|
float cosr_cosp = 1 - 2 * (q.X * q.X + q.Y * q.Y);
|
||||||
|
return (float)Math.Atan2(sinr_cosp, cosr_cosp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float ComputeYAngle(this Quaternion q)
|
||||||
|
{
|
||||||
|
float sinp = 2 * (q.W * q.Y - q.Z * q.X);
|
||||||
|
if (Math.Abs(sinp) >= 1)
|
||||||
|
return (float)Math.PI / 2 * Math.Sign(sinp); // use 90 degrees if out of range
|
||||||
|
else
|
||||||
|
return (float)Math.Asin(sinp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float ComputeZAngle(this Quaternion q)
|
||||||
|
{
|
||||||
|
float siny_cosp = 2 * (q.W * q.Z + q.X * q.Y);
|
||||||
|
float cosy_cosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z);
|
||||||
|
return (float)Math.Atan2(siny_cosp, cosy_cosp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 ComputeAngles(this Quaternion q)
|
||||||
|
{
|
||||||
|
return new Vector3(ComputeXAngle(q), ComputeYAngle(q), ComputeZAngle(q));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion FromAngles(Vector3 angles)
|
||||||
|
{
|
||||||
|
|
||||||
|
float cy = (float)Math.Cos(angles.Z * 0.5f);
|
||||||
|
float sy = (float)Math.Sin(angles.Z * 0.5f);
|
||||||
|
float cp = (float)Math.Cos(angles.Y * 0.5f);
|
||||||
|
float sp = (float)Math.Sin(angles.Y * 0.5f);
|
||||||
|
float cr = (float)Math.Cos(angles.X * 0.5f);
|
||||||
|
float sr = (float)Math.Sin(angles.X * 0.5f);
|
||||||
|
|
||||||
|
Quaternion q = new Quaternion
|
||||||
|
{
|
||||||
|
W = cr * cp * cy + sr * sp * sy,
|
||||||
|
X = sr * cp * cy - cr * sp * sy,
|
||||||
|
Y = cr * sp * cy + sr * cp * sy,
|
||||||
|
Z = cr * cp * sy - sr * sp * cy
|
||||||
|
};
|
||||||
|
|
||||||
|
return q;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
349
HouseStealerPlugin/Util/Plots.cs
Normal file
349
HouseStealerPlugin/Util/Plots.cs
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin.Util
|
||||||
|
{
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
public float x;
|
||||||
|
public float y;
|
||||||
|
public float z;
|
||||||
|
public float rotation;
|
||||||
|
public string size;
|
||||||
|
public string entranceLayout;
|
||||||
|
|
||||||
|
public Location(float _x, float _y, float _z, float rot, string _size, string layout)
|
||||||
|
{
|
||||||
|
x = _x;
|
||||||
|
y = _y;
|
||||||
|
z = _z;
|
||||||
|
rotation = rot;
|
||||||
|
size = _size;
|
||||||
|
entranceLayout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 ToVector()
|
||||||
|
{
|
||||||
|
return new Vector3(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Plots
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Dictionary<string, Dictionary<int, Location>> Map = new Dictionary<string, Dictionary<int, Location>> {
|
||||||
|
{"r1h1", new Dictionary<int, Location>{
|
||||||
|
{ 01, new Location(90f, -18.5f, 177f, 3.141593f, "s", "Center")},
|
||||||
|
{ 02, new Location(144f, -38.5f, 129f, 0f, "m", "Center")},
|
||||||
|
{ 03, new Location(79f, -28.5f, 109f, 0f, "s", "Center")},
|
||||||
|
{ 04, new Location(101f, -28.5f, 78f, -1.570796f, "s", "Center")},
|
||||||
|
{ 05, new Location(179f, -48.5f, 85f, 3.141593f, "s", "Center")},
|
||||||
|
{ 06, new Location(184f, -48.5f, 44f, 0f, "s", "Center")},
|
||||||
|
{ 07, new Location(117f, -28.5f, 42f, -1.570796f, "m", "Center")},
|
||||||
|
{ 08, new Location(-36f, -18.5f, 86f, -0.9599311f, "m", "Center")},
|
||||||
|
{ 09, new Location(4f, -18.5f, 59f, 0.6108653f, "s", "Center")},
|
||||||
|
{ 10, new Location(-23f, -18.5f, 36f, 3.141593f, "s", "Center")},
|
||||||
|
{ 11, new Location(-71f, -8.5f, 135f, 0f, "s", "Center")},
|
||||||
|
{ 12, new Location(-114f, 1.5f, 78f, -0.9599311f, "l", "Center")},
|
||||||
|
{ 13, new Location(-81f, 1.5f, 42f, 0f, "s", "Center")},
|
||||||
|
{ 14, new Location(-23f, -18.5f, -36f, 0f, "s", "Center")},
|
||||||
|
{ 15, new Location(-9f, -18.5f, -80f, -0.6108653f, "s", "Center")},
|
||||||
|
{ 16, new Location(-41f, -8.5f, -94f, -2.181662f, "s", "Center")},
|
||||||
|
{ 17, new Location(-86f, 1.5f, -43f, -1.570796f, "m", "Center")},
|
||||||
|
{ 18, new Location(-116f, 11.5f, -85f, -2.181662f, "m", "Center")},
|
||||||
|
{ 19, new Location(-46f, 1.5f, -146f, -1.570796f, "s", "Center")},
|
||||||
|
{ 20, new Location(-77f, 1.5f, -147f, 0f, "s", "Center")},
|
||||||
|
{ 21, new Location(-72f, 11.5f, -190f, 0f, "m", "Center")},
|
||||||
|
{ 22, new Location(-140f, 21.5f, -136f, -1.570796f, "l", "Center")},
|
||||||
|
{ 23, new Location(114f, -18.5f, -37f, 0.9599311f, "s", "Center")},
|
||||||
|
{ 24, new Location(131f, -18.5f, -61f, 2.530727f, "s", "Center")},
|
||||||
|
{ 25, new Location(88f, -18.5f, -88f, 0f, "s", "Center")},
|
||||||
|
{ 26, new Location(185f, -38.5f, -54f, 0f, "m", "Center")},
|
||||||
|
{ 27, new Location(151f, -28.5f, -100f, 0.9599311f, "s", "Center")},
|
||||||
|
{ 28, new Location(44f, 1.5f, -135f, -1.570796f, "s", "Center")},
|
||||||
|
{ 29, new Location(52f, 1.5f, -176f, 0f, "s", "Center")},
|
||||||
|
{ 30, new Location(93f, 1.5f, -178f, 0f, "l", "Center")},
|
||||||
|
{ 31, new Location(-881f, -18.5f, -614f, -1.570796f, "s", "Center")},
|
||||||
|
{ 32, new Location(-833f, -38.5f, -560f, 1.570796f, "m", "Center")},
|
||||||
|
{ 33, new Location(-813f, -28.5f, -625f, 1.570796f, "s", "Center")},
|
||||||
|
{ 34, new Location(-782f, -28.5f, -603f, 0f, "s", "Center")},
|
||||||
|
{ 35, new Location(-789f, -48.5f, -525f, -1.570796f, "s", "Center")},
|
||||||
|
{ 36, new Location(-748f, -48.5f, -520f, 1.570796f, "s", "Center")},
|
||||||
|
{ 37, new Location(-746f, -28.5f, -587f, 0f, "m", "Center")},
|
||||||
|
{ 38, new Location(-790f, -18.5f, -740f, 0.6108653f, "m", "Center")},
|
||||||
|
{ 39, new Location(-763f, -18.5f, -700f, 2.181662f, "s", "Center")},
|
||||||
|
{ 40, new Location(-740f, -18.5f, -727f, -1.570796f, "s", "Center")},
|
||||||
|
{ 41, new Location(-839f, -8.5f, -775f, 1.570796f, "s", "Center")},
|
||||||
|
{ 42, new Location(-782f, 1.5f, -818f, 0.6108653f, "l", "Center")},
|
||||||
|
{ 43, new Location(-746f, 1.5f, -785f, 1.570796f, "s", "Center")},
|
||||||
|
{ 44, new Location(-668f, -18.5f, -727f, 1.570796f, "s", "Center")},
|
||||||
|
{ 45, new Location(-624f, -18.5f, -713f, 0.9599311f, "s", "Center")},
|
||||||
|
{ 46, new Location(-610f, -8.5f, -745f, -0.6108651f, "s", "Center")},
|
||||||
|
{ 47, new Location(-661f, 1.5f, -790f, 0f, "m", "Center")},
|
||||||
|
{ 48, new Location(-619f, 11.5f, -820f, -0.6108651f, "m", "Center")},
|
||||||
|
{ 49, new Location(-558f, 1.5f, -750f, 0f, "s", "Center")},
|
||||||
|
{ 50, new Location(-557f, 1.5f, -781f, 1.570796f, "s", "Center")},
|
||||||
|
{ 51, new Location(-514f, 11.5f, -776f, 1.570796f, "m", "Center")},
|
||||||
|
{ 52, new Location(-568f, 21.5f, -844f, 0f, "l", "Center")},
|
||||||
|
{ 53, new Location(-667f, -18.5f, -590f, 2.530728f, "s", "Center")},
|
||||||
|
{ 54, new Location(-643f, -18.5f, -573f, -2.181662f, "s", "Center")},
|
||||||
|
{ 55, new Location(-616f, -18.5f, -616f, 1.570796f, "s", "Center")},
|
||||||
|
{ 56, new Location(-650f, -38.5f, -519f, 1.570796f, "m", "Center")},
|
||||||
|
{ 57, new Location(-604f, -28.5f, -553f, 2.530728f, "s", "Center")},
|
||||||
|
{ 58, new Location(-569f, 1.5f, -660f, 0f, "s", "Center")},
|
||||||
|
{ 59, new Location(-528f, 1.5f, -652f, 1.570796f, "s", "Center")},
|
||||||
|
{ 60, new Location(-526f, 1.5f, -611f, 1.570796f, "l", "Center")}
|
||||||
|
} },
|
||||||
|
{"e1h1", new Dictionary<int, Location>{
|
||||||
|
{ 01, new Location(-34f, 2.02f, 116f, -1.308997f, "m", "Center")},
|
||||||
|
{ 02, new Location(-27f, 14.52f, 75f, -1.308997f, "s", "Center")},
|
||||||
|
{ 03, new Location(5f, 6.02f, 125f, -1.134464f, "s", "Center")},
|
||||||
|
{ 04, new Location(7f, 20.02f, 79f, -2.617994f, "s", "Center")},
|
||||||
|
{ 05, new Location(40f, 20.02f, 63f, 0.5235988f, "s", "Center")},
|
||||||
|
{ 06, new Location(45f, 10.02f, 99f, 0f, "s", "Center")},
|
||||||
|
{ 07, new Location(50f, 10.02f, 144f, 3.141593f, "l", "Center")},
|
||||||
|
{ 08, new Location(115f, 11.6f, 130f, 2.356194f, "m", "Center")},
|
||||||
|
{ 09, new Location(90f, 16.02f, 93f, -2.181662f, "s", "Center")},
|
||||||
|
{ 10, new Location(118f, 22.02f, 70f, 2.356194f, "s", "Center")},
|
||||||
|
{ 11, new Location(89f, 22.02f, 47f, 1.047198f, "s", "Center")},
|
||||||
|
{ 12, new Location(58f, 26.02f, 22f, 0.4363323f, "s", "Center")},
|
||||||
|
{ 13, new Location(68f, 31.59f, -18f, 0.4886922f, "m", "Center")},
|
||||||
|
{ 14, new Location(105f, 30.02f, 6f, 0.7853982f, "s", "Center")},
|
||||||
|
{ 15, new Location(131f, 34.02f, 32f, 2.356194f, "m", "Center")},
|
||||||
|
{ 16, new Location(136f, 40.02f, -30f, 0.7853982f, "l", "Center")},
|
||||||
|
{ 17, new Location(-105f, 2.02f, 74f, 2.094395f, "s", "Center")},
|
||||||
|
{ 18, new Location(-88f, 14.52f, 39f, 2.356194f, "s", "Center")},
|
||||||
|
{ 19, new Location(-135f, 2.02f, 50f, -0.7853982f, "m", "Center")},
|
||||||
|
{ 20, new Location(-107f, 10.02f, 12f, 0.9599311f, "s", "Center")},
|
||||||
|
{ 21, new Location(-164f, 6.02f, 22f, 2.879793f, "s", "Center")},
|
||||||
|
{ 22, new Location(-167f, 6.02f, -11f, 0f, "s", "Center")},
|
||||||
|
{ 23, new Location(-151f, 16.02f, -50f, -2.356194f, "s", "Center")},
|
||||||
|
{ 24, new Location(-123f, 17.51f, -26f, -2.356194f, "m", "Center")},
|
||||||
|
{ 25, new Location(-80f, 14.02f, -14f, 2.094395f, "s", "Center")},
|
||||||
|
{ 26, new Location(-97f, 16.02f, -56f, 0.7853982f, "s", "Center")},
|
||||||
|
{ 27, new Location(-59f, 20.02f, -55f, 0f, "s", "Center")},
|
||||||
|
{ 28, new Location(-75f, 25.02f, -117f, 0f, "m", "Center")},
|
||||||
|
{ 29, new Location(-116f, 26.62f, -93f, 1.134464f, "s", "Center")},
|
||||||
|
{ 30, new Location(-159f, 30.02f, -122f, -0.7853982f, "l", "Center")},
|
||||||
|
{ 31, new Location(-820f, 2.02f, -738f, 0.2617994f, "m", "Center")},
|
||||||
|
{ 32, new Location(-779f, 14.52f, -731f, 0.2617994f, "s", "Center")},
|
||||||
|
{ 33, new Location(-829f, 6.02f, -699f, 0.4363323f, "s", "Center")},
|
||||||
|
{ 34, new Location(-783f, 20.02f, -697f, -1.047197f, "s", "Center")},
|
||||||
|
{ 35, new Location(-767f, 20.02f, -664f, 2.094395f, "s", "Center")},
|
||||||
|
{ 36, new Location(-803f, 10.02f, -659f, 1.570796f, "s", "Center")},
|
||||||
|
{ 37, new Location(-848f, 10.02f, -654f, -1.570796f, "l", "Center")},
|
||||||
|
{ 38, new Location(-834f, 11.6f, -589f, -2.356195f, "m", "Center")},
|
||||||
|
{ 39, new Location(-797f, 16.02f, -614f, -0.6108653f, "s", "Center")},
|
||||||
|
{ 40, new Location(-774f, 22.02f, -586f, -2.356195f, "s", "Center")},
|
||||||
|
{ 41, new Location(-751f, 22.02f, -615f, 2.617994f, "s", "Center")},
|
||||||
|
{ 42, new Location(-726f, 26.02f, -646f, 2.007128f, "s", "Center")},
|
||||||
|
{ 43, new Location(-686f, 31.59f, -636f, 2.059489f, "m", "Center")},
|
||||||
|
{ 44, new Location(-710f, 30.02f, -599f, 2.356195f, "s", "Center")},
|
||||||
|
{ 45, new Location(-736f, 34.02f, -573f, -2.356195f, "m", "Center")},
|
||||||
|
{ 46, new Location(-674f, 40.02f, -568f, 2.356195f, "l", "Center")},
|
||||||
|
{ 47, new Location(-778f, 2.02f, -809f, -2.617994f, "s", "Center")},
|
||||||
|
{ 48, new Location(-743f, 14.52f, -792f, -2.356195f, "s", "Center")},
|
||||||
|
{ 49, new Location(-754f, 2.02f, -839f, 0.7853982f, "m", "Center")},
|
||||||
|
{ 50, new Location(-716f, 10.02f, -811f, 2.530728f, "s", "Center")},
|
||||||
|
{ 51, new Location(-726f, 6.02f, -868f, -1.832596f, "s", "Center")},
|
||||||
|
{ 52, new Location(-693f, 6.02f, -871f, 1.570796f, "s", "Center")},
|
||||||
|
{ 53, new Location(-654f, 16.02f, -855f, -0.7853979f, "s", "Center")},
|
||||||
|
{ 54, new Location(-678f, 17.51f, -827f, -0.7853979f, "m", "Center")},
|
||||||
|
{ 55, new Location(-690f, 14.02f, -784f, -2.617994f, "s", "Center")},
|
||||||
|
{ 56, new Location(-648f, 16.02f, -801f, 2.356195f, "s", "Center")},
|
||||||
|
{ 57, new Location(-649f, 20.02f, -763f, 1.570796f, "s", "Center")},
|
||||||
|
{ 58, new Location(-587f, 25.02f, -779f, 1.570796f, "m", "Center")},
|
||||||
|
{ 59, new Location(-611f, 26.62f, -820f, 2.70526f, "s", "Center")},
|
||||||
|
{ 60, new Location(-582f, 30.02f, -863f, 0.7853982f, "l", "Center")},
|
||||||
|
} },
|
||||||
|
{"f1h1", new Dictionary<int, Location>{
|
||||||
|
{ 01, new Location(144f, 46f, -78.375f, 1.570451f, "m", "Center")},
|
||||||
|
{ 02, new Location(78.5f, 51f, -100f, 0f, "s", "Center")},
|
||||||
|
{ 03, new Location(130f, 58.5f, -163f, 2.443461f, "l", "Far Right Side")},
|
||||||
|
{ 04, new Location(39.5f, 54.5f, -81f, -1.308997f, "s", "Center")},
|
||||||
|
{ 05, new Location(71.5f, 34.5f, -30.5f, 0f, "m", "Center")},
|
||||||
|
{ 06, new Location(143f, 23.5f, 2f, 2.007128f, "l", "Far Right Side")},
|
||||||
|
{ 07, new Location(116.5f, 9.625f, 52f, 0.08726646f, "s", "Center")},
|
||||||
|
{ 08, new Location(85f, 8.75f, 63.5f, -0.7853982f, "s", "Center")},
|
||||||
|
{ 09, new Location(125f, 8f, 95f, 1.570451f, "s", "Center")},
|
||||||
|
{ 10, new Location(74.5f, 7.75f, 93.5f, -1.221731f, "s", "Center")},
|
||||||
|
{ 11, new Location(52f, 5f, 132f, 0f, "m", "Center")},
|
||||||
|
{ 12, new Location(64f, 25f, 22.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 13, new Location(27.74659f, 34f, 13f, -1.832596f, "s", "Center")},
|
||||||
|
{ 14, new Location(32f, 19.5f, 43.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 15, new Location(12f, 9f, 81.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 16, new Location(-92f, 7.75f, 98f, -0.6981317f, "m", "Center")},
|
||||||
|
{ 17, new Location(-30f, 10f, 78.5f, 0.7853978f, "s", "Center")},
|
||||||
|
{ 18, new Location(-31f, 21f, 44.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 19, new Location(-82f, 21.5f, 45.5f, -1.221731f, "s", "Center")},
|
||||||
|
{ 20, new Location(-8.5f, 33f, 1f, 1.570451f, "s", "Center")},
|
||||||
|
{ 21, new Location(-58f, 30.5f, -3f, 0f, "m", "Center")},
|
||||||
|
{ 22, new Location(-37f, 41.5f, -36.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 23, new Location(-65.5f, 32f, -35.5f, 1.570451f, "s", "Center")},
|
||||||
|
{ 24, new Location(-45.5f, 47f, -65.5f, -1.570451f, "s", "Center")},
|
||||||
|
{ 25, new Location(-4f, 46.5f, -73f, 1.570451f, "s", "Center")},
|
||||||
|
{ 26, new Location(-29f, 56.5f, -106f, 2.96706f, "s", "Center")},
|
||||||
|
{ 27, new Location(-114f, 31.5f, -40f, -1.308997f, "m", "Center")},
|
||||||
|
{ 28, new Location(-135.75f, 27.5f, -108.5f, -2.6529f, "l", "Left Side")},
|
||||||
|
{ 29, new Location(-105f, 34.5f, -154.5f, -0.7330383f, "s", "Center")},
|
||||||
|
{ 30, new Location(-50.5f, 56f, -150f, 0f, "m", "Center")},
|
||||||
|
{ 31, new Location(-625.625f, 46f, -560f, 3.141247f, "m", "Center")},
|
||||||
|
{ 32, new Location(-604f, 51f, -625.5f, 1.570796f, "s", "Center")},
|
||||||
|
{ 33, new Location(-541f, 58.5f, -574f, -2.268928f, "l", "Far Right Side")},
|
||||||
|
{ 34, new Location(-623f, 54.5f, -664.5f, 0.2617994f, "s", "Center")},
|
||||||
|
{ 35, new Location(-673.5f, 34.5f, -632.5f, 1.570796f, "m", "Center")},
|
||||||
|
{ 36, new Location(-706f, 23.5f, -561f, -2.70526f, "l", "Far Right Side")},
|
||||||
|
{ 37, new Location(-756f, 9.625f, -587.5f, 1.658063f, "s", "Center")},
|
||||||
|
{ 38, new Location(-767.5f, 8.75f, -619f, 0.7853982f, "s", "Center")},
|
||||||
|
{ 39, new Location(-799f, 8f, -579f, 3.141247f, "s", "Center")},
|
||||||
|
{ 40, new Location(-797.5f, 7.75f, -629.5f, 0.3490657f, "s", "Center")},
|
||||||
|
{ 41, new Location(-836f, 5f, -652f, 1.570796f, "m", "Center")},
|
||||||
|
{ 42, new Location(-726.5f, 25f, -640f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 43, new Location(-717f, 34f, -676.2534f, -0.2617998f, "s", "Center")},
|
||||||
|
{ 44, new Location(-747.5f, 19.5f, -672f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 45, new Location(-785.5f, 9f, -692f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 46, new Location(-802f, 7.75f, -796f, 0.8726646f, "m", "Center")},
|
||||||
|
{ 47, new Location(-782.5f, 10f, -734f, 2.356194f, "s", "Center")},
|
||||||
|
{ 48, new Location(-748.5f, 21f, -735f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 49, new Location(-749.5f, 21.5f, -786f, 0.3490657f, "s", "Center")},
|
||||||
|
{ 50, new Location(-705f, 33f, -712.5f, 3.141247f, "s", "Center")},
|
||||||
|
{ 51, new Location(-701f, 30.5f, -762f, 1.570796f, "m", "Center")},
|
||||||
|
{ 52, new Location(-667.5f, 41.5f, -741f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 53, new Location(-668.5f, 32f, -769.5f, 3.141247f, "s", "Center")},
|
||||||
|
{ 54, new Location(-638.5f, 47f, -749.5f, 0.0003454686f, "s", "Center")},
|
||||||
|
{ 55, new Location(-631f, 46.5f, -708f, 3.141247f, "s", "Center")},
|
||||||
|
{ 56, new Location(-598f, 56.5f, -733f, -1.745329f, "s", "Center")},
|
||||||
|
{ 57, new Location(-664f, 31.5f, -818f, 0.2617989f, "m", "Center")},
|
||||||
|
{ 58, new Location(-595.5f, 27.5f, -839.75f, -1.082104f, "l", "Left Side")},
|
||||||
|
{ 59, new Location(-549.5f, 34.5f, -809f, 0.8377581f, "s", "Center")},
|
||||||
|
{ 60, new Location(-554f, 56f, -754.5f, 1.570796f, "m", "Center")},
|
||||||
|
} },
|
||||||
|
|
||||||
|
{"s1h1", new Dictionary<int, Location>{
|
||||||
|
{ 01, new Location(-72f, 40f, -108f, -1.570451f, "m", "Center")},
|
||||||
|
{ 02, new Location(-144f, 36f, -100f, -0.7853982f, "l", "Center")},
|
||||||
|
{ 03, new Location(-96f, 32f, -60f, 3.141593f, "s", "Center")},
|
||||||
|
{ 04, new Location(-92f, 18f, -12f, -1.570451f, "m", "Right")},
|
||||||
|
{ 05, new Location(-148f, 20f, 28f, -2.094395f, "l", "Center")},
|
||||||
|
{ 06, new Location(-36f, 14f, -4f, 0.7853982f, "m", "Center")},
|
||||||
|
{ 07, new Location(-40f, 24f, -56f, 0f, "m", "Center")},
|
||||||
|
{ 08, new Location(-12f, 36f, -92f, 1.570451f, "s", "Right")},
|
||||||
|
{ 09, new Location(40f, 38f, -100f, 0f, "s", "Right Side")},
|
||||||
|
{ 10, new Location(64f, 42f, -124f, 0f, "s", "Right")},
|
||||||
|
{ 11, new Location(4f, 25f, -56f, 0f, "s", "Right Side")},
|
||||||
|
{ 12, new Location(48f, 26f, -60f, 0f, "s", "Center")},
|
||||||
|
{ 13, new Location(64f, 18f, -32f, 0f, "s", "Right")},
|
||||||
|
{ 14, new Location(83.628f, 29f, -63f, -0.7853982f, "m", "Far Right")},
|
||||||
|
{ 15, new Location(148f, 46f, -104f, 0.7853982f, "l", "Center")},
|
||||||
|
{ 16, new Location(136f, 28f, -34f, 1.570451f, "s", "Left")},
|
||||||
|
{ 17, new Location(112f, 22f, -20f, 1.570451f, "s", "Left")},
|
||||||
|
{ 18, new Location(72f, 17f, 4f, 0f, "s", "Far Right Side")},
|
||||||
|
{ 19, new Location(42f, 8f, 24f, 0.3490659f, "s", "Center")},
|
||||||
|
{ 20, new Location(66f, 6f, 36f, 0.5235988f, "s", "Center")},
|
||||||
|
{ 21, new Location(88f, 5f, 52f, 0.6981317f, "s", "Center")},
|
||||||
|
{ 22, new Location(120f, 18f, 56f, 0f, "s", "Right Side")},
|
||||||
|
{ 23, new Location(112f, 18f, 28f, 0f, "s", "Right Side")},
|
||||||
|
{ 24, new Location(150f, 22f, -6f, 0f, "s", "Center")},
|
||||||
|
{ 25, new Location(162f, 32f, 24f, 0f, "s", "Right Side")},
|
||||||
|
{ 26, new Location(168f, 28f, 56f, 1.570451f, "s", "Center")},
|
||||||
|
{ 27, new Location(186f, 36f, -6f, 0f, "s", "Center")},
|
||||||
|
{ 28, new Location(196f, 40f, 24f, 0f, "s", "Right")},
|
||||||
|
{ 29, new Location(196f, 38f, 64f, 1.570451f, "m", "Far Right")},
|
||||||
|
{ 30, new Location(140f, 20f, 100f, 2.617994f, "m", "Center")},
|
||||||
|
{ 31, new Location(-596f, 40f, -776f, 0.0003454686f, "m", "Center")},
|
||||||
|
{ 32, new Location(-604f, 36f, -848f, 0.7853982f, "l", "Center")},
|
||||||
|
{ 33, new Location(-644f, 32f, -800f, -1.570796f, "s", "Center")},
|
||||||
|
{ 34, new Location(-692f, 18f, -796f, 0.0003454686f, "m", "Right")},
|
||||||
|
{ 35, new Location(-732f, 20f, -852f, -0.523599f, "l", "Center")},
|
||||||
|
{ 36, new Location(-700f, 14f, -740f, 2.356195f, "m", "Center")},
|
||||||
|
{ 37, new Location(-648f, 24f, -744f, 1.570796f, "m", "Center")},
|
||||||
|
{ 38, new Location(-612f, 36f, -716f, 3.141247f, "s", "Right")},
|
||||||
|
{ 39, new Location(-604f, 38f, -664f, 1.570796f, "s", "Right Side")},
|
||||||
|
{ 40, new Location(-580f, 42f, -640f, 1.570796f, "s", "Right")},
|
||||||
|
{ 41, new Location(-648f, 25f, -700f, 1.570796f, "s", "Right Side")},
|
||||||
|
{ 42, new Location(-644f, 26f, -656f, 1.570796f, "s", "Center")},
|
||||||
|
{ 43, new Location(-672f, 18f, -640f, 1.570796f, "s", "Right")},
|
||||||
|
{ 44, new Location(-641f, 29f, -620.372f, 0.7853982f, "m", "Far Right")},
|
||||||
|
{ 45, new Location(-600f, 46f, -556f, 2.356195f, "l", "Center")},
|
||||||
|
{ 46, new Location(-670f, 28f, -568f, 3.141247f, "s", "Left")},
|
||||||
|
{ 47, new Location(-684f, 22f, -592f, 3.141247f, "s", "Left")},
|
||||||
|
{ 48, new Location(-708f, 17f, -632f, 1.570796f, "s", "Far Right Side")},
|
||||||
|
{ 49, new Location(-728f, 8f, -662f, 1.919862f, "s", "Center")},
|
||||||
|
{ 50, new Location(-740f, 6f, -638f, 2.094395f, "s", "Center")},
|
||||||
|
{ 51, new Location(-756f, 5f, -616f, 2.268928f, "s", "Center")},
|
||||||
|
{ 52, new Location(-760f, 18f, -584f, 1.570796f, "s", "Right Side")},
|
||||||
|
{ 53, new Location(-732f, 18f, -592f, 1.570796f, "s", "Right Side")},
|
||||||
|
{ 54, new Location(-698f, 22f, -554f, 1.570796f, "s", "Center")},
|
||||||
|
{ 55, new Location(-728f, 32f, -542f, 1.570796f, "s", "Right Side")},
|
||||||
|
{ 56, new Location(-760f, 28f, -536f, 3.141247f, "s", "Center")},
|
||||||
|
{ 57, new Location(-698f, 36f, -518f, 1.570796f, "s", "Center")},
|
||||||
|
{ 58, new Location(-728f, 40f, -508f, 1.570796f, "s", "Right")},
|
||||||
|
{ 59, new Location(-768f, 38f, -508f, 3.141247f, "m", "Far Right")},
|
||||||
|
{ 60, new Location(-804f, 20f, -564f, -2.094395f, "m", "Center")},
|
||||||
|
} },
|
||||||
|
{"w1h1", new Dictionary<int, Location>{
|
||||||
|
{ 01, new Location(-38.00001f, -4f, -110f, 2.86234f, "s", "Right")},
|
||||||
|
{ 02, new Location(-64.00002f, 4f, -98.00002f, -0.6108653f, "s", "Right")},
|
||||||
|
{ 03, new Location(-85.64f, 6f, -80.02f, -0.8834857f, "s", "Right")},
|
||||||
|
{ 04, new Location(-82.203f, -4f, -121.07f, 2.548181f, "m", "Left")},
|
||||||
|
{ 05, new Location(-118.665f, 12f, -92.44f, 0.5962044f, "l", "Right Side")},
|
||||||
|
{ 06, new Location(-39.73f, 0f, -64.44f, 0.7853982f, "m", "Right")},
|
||||||
|
{ 07, new Location(-72.6f, 8f, -40.315f, 2.059489f, "s", "Right")},
|
||||||
|
{ 08, new Location(-117.81f, 10f, -23.37f, -1.343904f, "m", "Center")},
|
||||||
|
{ 09, new Location(-140.246f, 12f, -51.004f, 2.007129f, "s", "Right")},
|
||||||
|
{ 10, new Location(-147.905f, 15f, -24.543f, 0.1745329f, "s", "Right")},
|
||||||
|
{ 11, new Location(-158.78f, 15f, 18.875f, -1.833119f, "m", "Right")},
|
||||||
|
{ 12, new Location(-116f, 15f, 23.99996f, 1.308997f, "m", "Right")},
|
||||||
|
{ 13, new Location(-72f, 11.618f, 12f, -0.2391101f, "l", "Far Left Side")},
|
||||||
|
{ 14, new Location(-32.00002f, -20f, 17.99998f, 3.141593f, "s", "Left")},
|
||||||
|
{ 15, new Location(-14.018f, -16.02f, -36.035f, -0.7853982f, "s", "Right")},
|
||||||
|
{ 16, new Location(68.24998f, -16f, -39.56697f, -0.5235988f, "s", "Right")},
|
||||||
|
{ 17, new Location(67f, -20f, 0.2499695f, 3.141593f, "s", "Right")},
|
||||||
|
{ 18, new Location(73.188f, -24f, 28.851f, 2.094395f, "s", "Right")},
|
||||||
|
{ 19, new Location(44f, -24f, 53.81f, 2.094395f, "m", "Right")},
|
||||||
|
{ 20, new Location(0f, -24f, 79.99998f, 3.141593f, "s", "Right")},
|
||||||
|
{ 21, new Location(93.99998f, -26f, -70.00002f, 2.356194f, "s", "Right")},
|
||||||
|
{ 22, new Location(106f, -14f, -36.00003f, -0.3490659f, "s", "Left")},
|
||||||
|
{ 23, new Location(130.465f, -18f, -56.628f, 1.221731f, "s", "Right")},
|
||||||
|
{ 24, new Location(144.5f, -26f, -32.00003f, 0f, "s", "Right")},
|
||||||
|
{ 25, new Location(123.75f, -28f, 4f, -1.570796f, "m", "Right")},
|
||||||
|
{ 26, new Location(120f, -28f, 39.99997f, -1.570796f, "s", "Right")},
|
||||||
|
{ 27, new Location(130f, -36f, 71.99997f, 3.141593f, "s", "Right")},
|
||||||
|
{ 28, new Location(95.545f, -33.68f, 59.08f, 0.5235988f, "s", "Right")},
|
||||||
|
{ 29, new Location(184f, -44f, 23.49998f, 1.570796f, "s", "Right")},
|
||||||
|
{ 30, new Location(188f, -40f, 60f, 3.141593f, "l", "Far Right Side")},
|
||||||
|
{ 31, new Location(-594f, -4f, -742f, -1.850049f, "s", "Right")},
|
||||||
|
{ 32, new Location(-606f, 4f, -768f, 0.9599311f, "s", "Right")},
|
||||||
|
{ 33, new Location(-623.98f, 6f, -789.64f, 0.6873107f, "s", "Right")},
|
||||||
|
{ 34, new Location(-582.93f, -4f, -786.203f, -2.164208f, "m", "Left")},
|
||||||
|
{ 35, new Location(-611.56f, 12f, -822.665f, 2.167001f, "l", "Right Side")},
|
||||||
|
{ 36, new Location(-639.56f, 0f, -743.73f, 2.356195f, "m", "Right")},
|
||||||
|
{ 37, new Location(-663.685f, 8f, -776.6f, -2.6529f, "s", "Right")},
|
||||||
|
{ 38, new Location(-680.63f, 10f, -821.81f, 0.2268923f, "m", "Center")},
|
||||||
|
{ 39, new Location(-652.996f, 12f, -844.246f, -2.70526f, "s", "Right")},
|
||||||
|
{ 40, new Location(-679.457f, 15f, -851.905f, 1.745329f, "s", "Right")},
|
||||||
|
{ 41, new Location(-722.875f, 15f, -862.78f, -0.262323f, "m", "Right")},
|
||||||
|
{ 42, new Location(-727.9999f, 15f, -820f, 2.879793f, "m", "Right")},
|
||||||
|
{ 43, new Location(-716f, 11.618f, -776f, 1.331686f, "l", "Far Left Side")},
|
||||||
|
{ 44, new Location(-722f, -20f, -736f, -1.570796f, "s", "Left")},
|
||||||
|
{ 45, new Location(-667.965f, -16.02f, -718.018f, 0.7853982f, "s", "Right")},
|
||||||
|
{ 46, new Location(-664.433f, -16f, -635.75f, 1.047198f, "s", "Right")},
|
||||||
|
{ 47, new Location(-704.25f, -20f, -637f, -1.570796f, "s", "Right")},
|
||||||
|
{ 48, new Location(-732.851f, -24f, -630.812f, -2.617994f, "s", "Right")},
|
||||||
|
{ 49, new Location(-757.81f, -24f, -660f, -2.617994f, "m", "Right")},
|
||||||
|
{ 50, new Location(-784f, -24f, -704f, -1.570796f, "s", "Right")},
|
||||||
|
{ 51, new Location(-634f, -26f, -610f, -2.356195f, "s", "Right")},
|
||||||
|
{ 52, new Location(-668f, -14f, -598f, 1.22173f, "s", "Left")},
|
||||||
|
{ 53, new Location(-647.372f, -18f, -573.535f, 2.792527f, "s", "Right")},
|
||||||
|
{ 54, new Location(-672f, -26f, -559.5f, 1.570796f, "s", "Right")},
|
||||||
|
{ 55, new Location(-708f, -28f, -580.25f, 0f, "m", "Right")},
|
||||||
|
{ 56, new Location(-744f, -28f, -584f, 0f, "s", "Right")},
|
||||||
|
{ 57, new Location(-776f, -36f, -574f, -1.570796f, "s", "Right")},
|
||||||
|
{ 58, new Location(-763.08f, -33.68f, -608.455f, 2.094395f, "s", "Right")},
|
||||||
|
{ 59, new Location(-727.5f, -44f, -520f, -3.141593f, "s", "Right")},
|
||||||
|
{ 60, new Location(-764f, -40f, -516f, -1.570796f, "l", "Far Right Side")},
|
||||||
|
} }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
145
HouseStealerPlugin/Util/Utils.cs
Normal file
145
HouseStealerPlugin/Util/Utils.cs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
using Lumina.Excel.Sheets;
|
||||||
|
using HouseStealerPlugin.Objects;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
|
||||||
|
|
||||||
|
namespace HouseStealerPlugin
|
||||||
|
{
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
public static string GetExteriorPartDescriptor(ExteriorPartsType partsType)
|
||||||
|
{
|
||||||
|
return partsType switch
|
||||||
|
{
|
||||||
|
ExteriorPartsType.Roof => "Roof",
|
||||||
|
ExteriorPartsType.Walls => "Exterior Wall",
|
||||||
|
ExteriorPartsType.Windows => "Window",
|
||||||
|
ExteriorPartsType.Door => "Door",
|
||||||
|
ExteriorPartsType.RoofOpt => "Roof Decor",
|
||||||
|
ExteriorPartsType.WallOpt => "Exterior Wall Decor",
|
||||||
|
ExteriorPartsType.SignOpt => "Placard",
|
||||||
|
ExteriorPartsType.Fence => "Fence",
|
||||||
|
_ => "Unknown"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetInteriorPartDescriptor(InteriorPartsType partsType)
|
||||||
|
{
|
||||||
|
return partsType switch
|
||||||
|
{
|
||||||
|
InteriorPartsType.Walls => "Wall",
|
||||||
|
InteriorPartsType.Windows => "Window",
|
||||||
|
InteriorPartsType.Door => "Door",
|
||||||
|
InteriorPartsType.Floor => "Floor",
|
||||||
|
InteriorPartsType.Light => "Light",
|
||||||
|
_ => "Unknown"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFloorDescriptor(InteriorFloor floor)
|
||||||
|
{
|
||||||
|
return floor switch
|
||||||
|
{
|
||||||
|
InteriorFloor.Ground => "Ground Floor",
|
||||||
|
InteriorFloor.Basement => "Basement",
|
||||||
|
InteriorFloor.Upstairs => "Upper Floor",
|
||||||
|
InteriorFloor.External => "Main",
|
||||||
|
_ => "Unknown"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float DistanceFromPlayer(HousingGameObject obj, Vector3 playerPos)
|
||||||
|
{
|
||||||
|
return Distance(new Vector3(playerPos.X, playerPos.Y, playerPos.Z), new Vector3(obj.X, obj.Y, obj.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double FastDistance(Vector3 v1, Vector3 v2) // for comparison, when actual distance doesn't matter
|
||||||
|
{
|
||||||
|
var x1 = Math.Pow(v2.X - v1.X, 2);
|
||||||
|
var y1 = Math.Pow(v2.Y - v1.Y, 2);
|
||||||
|
var z1 = Math.Pow(v2.Z - v1.Z, 2);
|
||||||
|
|
||||||
|
return x1 + y1 + z1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Distance(Vector3 v1, Vector3 v2)
|
||||||
|
{
|
||||||
|
return (float)Math.Sqrt(FastDistance(v1, v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StainButton(string id, Stain color, Vector2 size)
|
||||||
|
{
|
||||||
|
var floatColor = StainToVector4(color.Color);
|
||||||
|
ImGui.ColorButton($"##{id}", floatColor, ImGuiColorEditFlags.NoTooltip, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4 StainToVector4(uint stainColor)
|
||||||
|
{
|
||||||
|
var s = 1.0f / 255.0f;
|
||||||
|
|
||||||
|
return new Vector4()
|
||||||
|
{
|
||||||
|
X = ((stainColor >> 16) & 0xFF) * s,
|
||||||
|
Y = ((stainColor >> 8) & 0xFF) * s,
|
||||||
|
Z = ((stainColor >> 0) & 0xFF) * s,
|
||||||
|
W = ((stainColor >> 24) & 0xFF) * s
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HousingItem GetNearestHousingItem(IEnumerable<HousingItem> items, Vector3 position)
|
||||||
|
{
|
||||||
|
return items
|
||||||
|
.OrderBy(item => FastDistance(position, new Vector3(item.X, item.Y, item.Z)))
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenLink(String address)
|
||||||
|
{
|
||||||
|
Dalamud.Utility.Util.OpenLink(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Base64Url
|
||||||
|
{
|
||||||
|
public static string Encode(string text)
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).TrimEnd('=').Replace('+', '-')
|
||||||
|
.Replace('/', '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Decode(string text)
|
||||||
|
{
|
||||||
|
text = text.Replace('_', '/').Replace('-', '+');
|
||||||
|
switch (text.Length % 4)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
text += "==";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
text += "=";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Encoding.UTF8.GetString(Convert.FromBase64String(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float radToDeg(float radians)
|
||||||
|
{
|
||||||
|
var degrees = Math.Round((radians/ Math.PI)* 180,3);
|
||||||
|
if (degrees == 0)
|
||||||
|
{
|
||||||
|
degrees = 0; // stop -0 from showing up.
|
||||||
|
}
|
||||||
|
if (degrees <= -180)
|
||||||
|
{
|
||||||
|
degrees = 180; // the other edge case
|
||||||
|
}
|
||||||
|
return (float)degrees;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
HouseStealerPlugin/packages.lock.json
Normal file
41
HouseStealerPlugin/packages.lock.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"net9.0-windows7.0": {
|
||||||
|
"DalamudPackager": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[13.0.0, )",
|
||||||
|
"resolved": "13.0.0",
|
||||||
|
"contentHash": "Mb3cUDSK/vDPQ8gQIeuCw03EMYrej1B4J44a1AvIJ9C759p9XeqdU9Hg4WgOmlnlPe0G7ILTD32PKSUpkQNa8w=="
|
||||||
|
},
|
||||||
|
"DotNet.ReproducibleBuilds": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.25, )",
|
||||||
|
"resolved": "1.2.25",
|
||||||
|
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||||
|
},
|
||||||
|
"Lumina.Excel": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.3.1, )",
|
||||||
|
"resolved": "7.3.1",
|
||||||
|
"contentHash": "NKjlWOi/hnBx6ZHV/VmDknIFQLuBmBoqdufDxawzoAsAwye2dibZdMYyz/gIezSRzAMbU0qP9h51uYo65eiWIQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Lumina": "6.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Lumina": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.3.0",
|
||||||
|
"contentHash": "FQlZ16KhXtPGCEq1KeRTDZ14uq6qrvW2vYnNNlCpW7Xs1iLhF8AJsbYG8S0y1NnP7BRholPY8KGToVTsvmb8jw==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.ObjectPool": "8.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.ObjectPool": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.7",
|
||||||
|
"contentHash": "2yLweyqmpuuFSRo+I3sLHMxmnAgNcI537kBJiyv49U2ZEqo00jZcG8lrnD8uCiOJp9IklYyTZULtbsXoFVzsjQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user