chore: initial commit

This commit is contained in:
Anna 2024-06-17 12:04:57 -04:00
commit 449d70237d
Signed by: anna
GPG Key ID: D0943384CD9F87D1
30 changed files with 584 additions and 0 deletions

108
Plugin.cs Normal file
View File

@ -0,0 +1,108 @@
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace TimePasses;
public class Plugin : IDalamudPlugin {
[PluginService]
private IGameInteropProvider GameInterop { get; init; }
[PluginService]
private IPluginLog Log { get; init; }
private HttpClient Client { get; } = new();
private DataFile Data { get; set; }
private Dictionary<uint, nint> ReplacementPointers { get; set; }
private SemaphoreSlim Mutex { get; } = new(1, 1);
private static class Signatures {
internal const string GetBalloonRow = "E8 ?? ?? ?? ?? 48 85 C0 74 4D 48 89 5C 24";
}
private delegate nint GetBalloonRowDelegate(uint rowId);
[Signature(Signatures.GetBalloonRow, DetourName = nameof(GetBalloonRowDetour))]
private Hook<GetBalloonRowDelegate>? GetBalloonRowHook { get; init; }
public Plugin() {
Task.Run(async () => {
#if DEBUG
var stream = typeof(Plugin).Assembly.GetManifestResourceStream("TimePasses.replacements.yaml");
using var reader = new StreamReader(stream!);
var yaml = await reader.ReadToEndAsync();
#else
using var resp = await this.Client.GetAsync("https://git.anna.lgbt/anna/TimePasses/raw/branch/main/replacements.yaml");
var yaml = await resp.Content.ReadAsStringAsync();
#endif
var de = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.Build();
await this.Mutex.WaitAsync();
try {
this.Data = de.Deserialize<DataFile>(yaml);
foreach (var replacement in this.Data.Replacements) {
var textBytes = Encoding.UTF8.GetBytes(replacement.Text);
unsafe {
var ptr = (uint*) Marshal.AllocHGlobal(8 + textBytes.Length + 1);
try {
*ptr = 8;
*(ptr + 1) = replacement.Slowly ? 1u : 0u;
var bytes = (byte*) (ptr + 2);
bytes[textBytes.Length] = 0;
Marshal.Copy(textBytes, 0, (nint) bytes, textBytes.Length);
this.ReplacementPointers![replacement.Id] = (nint) ptr;
} catch (Exception ex) {
this.Log!.Error(ex, "Error serialising balloon message");
Marshal.FreeHGlobal((nint) ptr);
}
}
}
} finally {
this.Mutex.Release();
}
});
}
public void Dispose() {
this.Client.Dispose();
this.Mutex.Dispose();
foreach (var (_, ptr) in this.ReplacementPointers) {
Marshal.FreeHGlobal(ptr);
}
this.ReplacementPointers.Clear();
}
private nint GetBalloonRowDetour(uint rowId) {
if (this.ReplacementPointers.TryGetValue(rowId, out var ptr)) {
return ptr;
}
return this.GetBalloonRowHook!.Original(rowId);
}
}
[Serializable]
internal class DataFile {
public Replacement[] Replacements { get; init; }
}
[Serializable]
internal class Replacement {
public uint Id { get; init; }
public string Text { get; init; }
public bool Slowly { get; init; }
}

54
TimePasses.csproj Normal file
View File

@ -0,0 +1,54 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>1.0.0</Version>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<LangVersion>preview</LangVersion>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Configurations>Debug;Release</Configurations>
<Platforms>x64</Platforms>
</PropertyGroup>
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>CS8618;CS1591;CS1573;IDE0003;MSB3277</NoWarn>
</PropertyGroup>
<PropertyGroup>
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev</DalamudLibPath>
</PropertyGroup>
<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'">
<DalamudLibPath>$(DALAMUD_HOME)</DalamudLibPath>
</PropertyGroup>
<PropertyGroup Condition="'$(IsCI)' == 'true'">
<DalamudLibPath>$(HOME)/dalamud</DalamudLibPath>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DalamudLibPath)\Dalamud.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ImGui.NET">
<HintPath>$(DalamudLibPath)\ImGui.NET.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="YamlDotNet" Version="15.3.0" />
</ItemGroup>
</Project>

25
TimePasses.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimePasses", "TimePasses.csproj", "{5F60F6C6-A0F4-448E-A35A-54653EF24EE9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5F60F6C6-A0F4-448E-A35A-54653EF24EE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F60F6C6-A0F4-448E-A35A-54653EF24EE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F60F6C6-A0F4-448E-A35A-54653EF24EE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F60F6C6-A0F4-448E-A35A-54653EF24EE9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3B0C57F1-5712-405F-BF67-9EA51C2B96D5}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]

View File

@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyTitleAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows7.0")]
[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -0,0 +1 @@
686ef8ed24066c6bddc4d5501ac7527757d6e0919514757a1228df6786fe7946

View File

@ -0,0 +1,13 @@
is_global = true
build_property.TargetFramework = net8.0-windows
build_property.TargetPlatformMinVersion = 7.0
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = TimePasses
build_property.ProjectDir = /home/anna/code/plugins/TimePasses/
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =

View File

@ -0,0 +1,8 @@
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]

View File

@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyTitleAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -0,0 +1 @@
f910133122f2815b8bc0ff543fa97d148b588a249a0fc831554ed5cd80fb81ff

View File

@ -0,0 +1,13 @@
is_global = true
build_property.TargetFramework = net8.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = TimePasses
build_property.ProjectDir = /home/anna/code/plugins/TimePasses/
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =

View File

@ -0,0 +1,8 @@
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

Binary file not shown.

View File

@ -0,0 +1,70 @@
{
"format": 1,
"restore": {
"/home/anna/code/plugins/TimePasses/TimePasses.csproj": {}
},
"projects": {
"/home/anna/code/plugins/TimePasses/TimePasses.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/home/anna/code/plugins/TimePasses/TimePasses.csproj",
"projectName": "TimePasses",
"projectPath": "/home/anna/code/plugins/TimePasses/TimePasses.csproj",
"packagesPath": "/home/anna/.nuget/packages/",
"outputPath": "/home/anna/code/plugins/TimePasses/obj/",
"projectStyle": "PackageReference",
"configFilePaths": [
"/home/anna/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net8.0-windows"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0-windows7.0": {
"targetAlias": "net8.0-windows",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreLockProperties": {
"restorePackagesWithLockFile": "true"
}
},
"frameworks": {
"net8.0-windows7.0": {
"targetAlias": "net8.0-windows",
"dependencies": {
"YamlDotNet": {
"target": "Package",
"version": "[15.3.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.104/PortableRuntimeIdentifierGraph.json"
}
}
}
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/anna/.nuget/packages/</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/anna/.nuget/packages/</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="/home/anna/.nuget/packages/" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />

118
obj/project.assets.json Normal file
View File

@ -0,0 +1,118 @@
{
"version": 3,
"targets": {
"net8.0-windows7.0": {
"YamlDotNet/15.3.0": {
"type": "package",
"compile": {
"lib/net8.0/YamlDotNet.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net8.0/YamlDotNet.dll": {
"related": ".xml"
}
}
}
}
},
"libraries": {
"YamlDotNet/15.3.0": {
"sha512": "F93japYa9YrJ59AZGhgdaUGHN7ITJ55FBBg/D/8C0BDgahv/rQD6MOSwHxOJJpon1kYyslVbeBrQ2wcJhox01w==",
"type": "package",
"path": "yamldotnet/15.3.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.txt",
"README.md",
"images/yamldotnet.png",
"lib/net47/YamlDotNet.dll",
"lib/net47/YamlDotNet.xml",
"lib/net6.0/YamlDotNet.dll",
"lib/net6.0/YamlDotNet.xml",
"lib/net7.0/YamlDotNet.dll",
"lib/net7.0/YamlDotNet.xml",
"lib/net8.0/YamlDotNet.dll",
"lib/net8.0/YamlDotNet.xml",
"lib/netstandard2.0/YamlDotNet.dll",
"lib/netstandard2.0/YamlDotNet.xml",
"lib/netstandard2.1/YamlDotNet.dll",
"lib/netstandard2.1/YamlDotNet.xml",
"yamldotnet.15.3.0.nupkg.sha512",
"yamldotnet.nuspec"
]
}
},
"projectFileDependencyGroups": {
"net8.0-windows7.0": [
"YamlDotNet >= 15.3.0"
]
},
"packageFolders": {
"/home/anna/.nuget/packages/": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/home/anna/code/plugins/TimePasses/TimePasses.csproj",
"projectName": "TimePasses",
"projectPath": "/home/anna/code/plugins/TimePasses/TimePasses.csproj",
"packagesPath": "/home/anna/.nuget/packages/",
"outputPath": "/home/anna/code/plugins/TimePasses/obj/",
"projectStyle": "PackageReference",
"configFilePaths": [
"/home/anna/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net8.0-windows"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0-windows7.0": {
"targetAlias": "net8.0-windows",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreLockProperties": {
"restorePackagesWithLockFile": "true"
}
},
"frameworks": {
"net8.0-windows7.0": {
"targetAlias": "net8.0-windows",
"dependencies": {
"YamlDotNet": {
"target": "Package",
"version": "[15.3.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.104/PortableRuntimeIdentifierGraph.json"
}
}
}
}

10
obj/project.nuget.cache Normal file
View File

@ -0,0 +1,10 @@
{
"version": 2,
"dgSpecHash": "0AOTCq29iUc+8XajVr0eACFUAHNQ7kW08ZK+AhezGJjOOcOoe+eumzpxSe8fwvPY+7jk8U1+9Vt7W+fsCGFVWQ==",
"success": true,
"projectFilePath": "/home/anna/code/plugins/TimePasses/TimePasses.csproj",
"expectedPackageFiles": [
"/home/anna/.nuget/packages/yamldotnet/15.3.0/yamldotnet.15.3.0.nupkg.sha512"
],
"logs": []
}

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]

View File

@ -0,0 +1,16 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyMetadata("Sentry.ProjectDirectory", "/home/anna/code/plugins/TimePasses/")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyTitleAttribute("TimePasses")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows7.0")]
[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -0,0 +1 @@
686ef8ed24066c6bddc4d5501ac7527757d6e0919514757a1228df6786fe7946

View File

@ -0,0 +1,13 @@
is_global = true
build_property.TargetFramework = net8.0-windows
build_property.TargetPlatformMinVersion = 7.0
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = TimePasses
build_property.ProjectDir = /home/anna/code/plugins/TimePasses/
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =

View File

@ -0,0 +1,8 @@
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

Binary file not shown.

13
packages.lock.json Normal file
View File

@ -0,0 +1,13 @@
{
"version": 1,
"dependencies": {
"net8.0-windows7.0": {
"YamlDotNet": {
"type": "Direct",
"requested": "[15.3.0, )",
"resolved": "15.3.0",
"contentHash": "F93japYa9YrJ59AZGhgdaUGHN7ITJ55FBBg/D/8C0BDgahv/rQD6MOSwHxOJJpon1kYyslVbeBrQ2wcJhox01w=="
}
}
}
}

5
replacements.yaml Normal file
View File

@ -0,0 +1,5 @@
replacements:
- id: 22
text: |-
It's been quiet
lately.