diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 245d433..c85eee2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,17 +37,17 @@ jobs: with: additionalArguments: '/updateprojectfiles /overrideconfig "mode=Mainline"' - - name: Build - run: dotnet build . -p:Version=$GitVersion_SemVer + - name: Build (Release) + run: dotnet build . --configuration Release -p:Version=$GitVersion_SemVer - name: Run Unit Tests run: dotnet test - name: Package Nuget - run: dotnet pack -p:Version=$GitVersion_SemVer --output ./nuget + run: dotnet pack VCF.Core --configuration Release -p:Version=$GitVersion_SemVer --output ./nuget - name: Upload a Build Artifact - if: ${{ !env.ACT }} + if: ${{ !env.ACT && github.event_name == 'push' }} uses: actions/upload-artifact@v3.1.0 with: path: ./nuget @@ -62,7 +62,7 @@ jobs: with: body: Automatic pre-release of ${{ env.GitVersion_SemVer }} for ${{ env.GitVersion_ShortSha }} name: v${{ env.GitVersion_SemVer }} - files: ./VampireCommandFrameworkPlugin/bin/Debug/net6.0/*.dll + files: ./VCF.Core/bin/Debug/net6.0/VampireCommandFramework.dll fail_on_unmatched_files: true prerelease: true tag_name: v${{ env.GitVersion_SemVer }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c3e72d..57252bc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,11 +36,11 @@ jobs: run: gh release download ${{ env.RELEASE_TAG }} -D ./dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # - name: Install tcli - # run: dotnet tool install --global tcli - # - name: Run tcli - # run: tcli publish --token ${{ secrets.THUNDERSTORE_KEY }} --package-version ${RELEASE_TAG:1} - # - name: Upload a Build Artifact - # uses: actions/upload-artifact@v3.1.0 - # with: - # path: ./build \ No newline at end of file + - name: Install tcli + run: dotnet tool install --global tcli + - name: Run tcli + run: tcli publish --token ${{ secrets.THUNDERSTORE_KEY }} --package-version ${RELEASE_TAG:1} + - name: Upload a Build Artifact + uses: actions/upload-artifact@v3.1.0 + with: + path: ./build \ No newline at end of file diff --git a/VCF.Core/Basics/HelpCommand.cs b/VCF.Core/Basics/HelpCommand.cs index 6ec3713..bfa793b 100644 --- a/VCF.Core/Basics/HelpCommand.cs +++ b/VCF.Core/Basics/HelpCommand.cs @@ -11,7 +11,7 @@ namespace VampireCommandFramework.Basics; -public static class HelpCommands +internal static class HelpCommands { private static readonly Regex _trailingLongDashRegex = new Regex(@"-\d+$"); diff --git a/VampireCommandFrameworkPlugin/Breadstone/ChatHook.cs b/VCF.Core/Breadstone/ChatHook.cs similarity index 86% rename from VampireCommandFrameworkPlugin/Breadstone/ChatHook.cs rename to VCF.Core/Breadstone/ChatHook.cs index ab2a3ca..cd6b23a 100644 --- a/VampireCommandFrameworkPlugin/Breadstone/ChatHook.cs +++ b/VCF.Core/Breadstone/ChatHook.cs @@ -8,6 +8,7 @@ namespace VampireCommandFramework.Breadstone; [HarmonyPriority(200)] +[HarmonyBefore("gg.deca.Bloodstone")] [HarmonyPatch(typeof(ChatMessageSystem), nameof(ChatMessageSystem.OnUpdate))] public static class ChatMessageSystem_Patch { @@ -49,14 +50,7 @@ public static bool Prefix(ChatMessageSystem __instance) else if (result != CommandResult.Unmatched) { //__instance.EntityManager.AddComponent(entity); - - var whisperChatEvent = new ChatMessageEvent() - { - MessageText = chatEventData.MessageText, - MessageType = ChatMessageType.Whisper, - ReceiverEntity = chatEventData.ReceiverEntity - }; - __instance.EntityManager.SetComponentData(entity, whisperChatEvent); + VWorld.Server.EntityManager.DestroyEntity(entity); return true; } diff --git a/VampireCommandFrameworkPlugin/Breadstone/VCFChatEvent.cs b/VCF.Core/Breadstone/VCFChatEvent.cs similarity index 100% rename from VampireCommandFrameworkPlugin/Breadstone/VCFChatEvent.cs rename to VCF.Core/Breadstone/VCFChatEvent.cs diff --git a/VampireCommandFrameworkPlugin/Breadstone/VWorld.cs b/VCF.Core/Breadstone/VWorld.cs similarity index 100% rename from VampireCommandFrameworkPlugin/Breadstone/VWorld.cs rename to VCF.Core/Breadstone/VWorld.cs diff --git a/VCF.Core/Common/Log.cs b/VCF.Core/Common/Log.cs index ec116e8..6340ef5 100644 --- a/VCF.Core/Common/Log.cs +++ b/VCF.Core/Common/Log.cs @@ -3,9 +3,9 @@ namespace VampireCommandFramework.Common; -public static class Log +internal static class Log { - public static ManualLogSource Instance { get; set; } + internal static ManualLogSource Instance { get; set; } public static void Warning(string s) => LogOrConsole(s, s => Instance.LogWarning(s)); public static void Error(string s) => LogOrConsole(s, s => Instance.LogError(s)); diff --git a/VCF.Core/Common/Utility.cs b/VCF.Core/Common/Utility.cs index 0a19bdc..15fd2cc 100644 --- a/VCF.Core/Common/Utility.cs +++ b/VCF.Core/Common/Utility.cs @@ -1,4 +1,7 @@ -using System.Text; +using RootMotion.FinalIK; +using System; +using System.Collections.Generic; +using System.Text; namespace VampireCommandFramework.Common; diff --git a/VampireCommandFrameworkPlugin/Breadstone/ChatCommandContext.cs b/VCF.Core/Framework/ChatCommandContext.cs similarity index 100% rename from VampireCommandFrameworkPlugin/Breadstone/ChatCommandContext.cs rename to VCF.Core/Framework/ChatCommandContext.cs diff --git a/VampireCommandFrameworkPlugin/Plugin.cs b/VCF.Core/Plugin.cs similarity index 76% rename from VampireCommandFrameworkPlugin/Plugin.cs rename to VCF.Core/Plugin.cs index fa8b41e..237e2a0 100644 --- a/VampireCommandFrameworkPlugin/Plugin.cs +++ b/VCF.Core/Plugin.cs @@ -33,17 +33,10 @@ public override void Load() CommandRegistry.RegisterCommandType(typeof(Basics.HelpCommands)); CommandRegistry.RegisterCommandType(typeof(Basics.BepInExConfigCommands)); - CommandRegistry.RegisterCommandType(typeof(Breadstone.Reload)); IL2CPPChainloader.Instance.Plugins.TryGetValue(PluginInfo.PLUGIN_GUID, out var info); Log.LogMessage($"VCF Loaded: {info?.Metadata.Version}"); - - - // Attempting to speed up Gloomrot compatibility development, server reload - // functionality was taken from Wetstone by molenzwiebel. Should be compatible with Wetstone as well. - // Please don't rely on this persisting or use for production. - Breadstone.Reload.Initialize("BepInEx/VCF-Reloadable-Debugging"); } public override bool Unload() diff --git a/VCF.Core/VCF.Core.csproj b/VCF.Core/VCF.Core.csproj index b4f1889..904bde9 100644 --- a/VCF.Core/VCF.Core.csproj +++ b/VCF.Core/VCF.Core.csproj @@ -1,22 +1,32 @@  - - net6.0 - enable - enable - false - - - - - + + net6.0 + VampireCommandFramework + My first plugin + 0.0.999 + true + latest + ../nuget.nuspec + version=$(Version) + gg.deca.VampireCommandFramework + VampireCommandFramework + VampireCommandFramework + deca + + + + + + + + + + + + - + - - - - - diff --git a/VCF.SimpleSamplePlugin/Plugin.cs b/VCF.SimpleSamplePlugin/Plugin.cs index a204550..c50b904 100644 --- a/VCF.SimpleSamplePlugin/Plugin.cs +++ b/VCF.SimpleSamplePlugin/Plugin.cs @@ -4,9 +4,9 @@ namespace VCF.SimpleSamplePlugin; -[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] +[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] [BepInDependency("gg.deca.VampireCommandFramework")] -[VampireCommandFramework.Breadstone.Reloadable] +[Bloodstone.API.Reloadable] internal class Plugin : BasePlugin { public override void Load() diff --git a/VCF.SimpleSamplePlugin/VCF.SimpleSamplePlugin.csproj b/VCF.SimpleSamplePlugin/VCF.SimpleSamplePlugin.csproj index 4b6c7bc..fa40b28 100644 --- a/VCF.SimpleSamplePlugin/VCF.SimpleSamplePlugin.csproj +++ b/VCF.SimpleSamplePlugin/VCF.SimpleSamplePlugin.csproj @@ -12,11 +12,11 @@ - - + + + - diff --git a/VCF.Tests/HelpTests.cs b/VCF.Tests/HelpTests.cs index d1a05ec..4831ef7 100644 --- a/VCF.Tests/HelpTests.cs +++ b/VCF.Tests/HelpTests.cs @@ -37,7 +37,7 @@ public void HelpCommand_Help_ListsAll() Assert.That(CommandRegistry.Handle(AnyCtx, ".help"), Is.EqualTo(CommandResult.Success)); AnyCtx.AssertReply($""" [vcf] Listing all commands - Commands from VCF.Core: + Commands from VampireCommandFramework: .help-legacy [search=] .help [search=] """); @@ -46,9 +46,9 @@ [vcf] Listing all commands [Test] public void HelpCommand_Help_ListsAssemblyMatch() { - Assert.That(CommandRegistry.Handle(AnyCtx, ".help VCF.Core"), Is.EqualTo(CommandResult.Success)); + Assert.That(CommandRegistry.Handle(AnyCtx, ".help VampireCommandFramework"), Is.EqualTo(CommandResult.Success)); AnyCtx.AssertReply($""" - [vcf] Commands from VCF.Core: + [vcf] Commands from VampireCommandFramework: .help-legacy [search=] .help [search=] """); diff --git a/VCF.Tests/VCF.Tests.csproj b/VCF.Tests/VCF.Tests.csproj index a065769..33619c1 100644 --- a/VCF.Tests/VCF.Tests.csproj +++ b/VCF.Tests/VCF.Tests.csproj @@ -21,7 +21,6 @@ - diff --git a/VCF.sln b/VCF.sln index c66535f..4d3b7cd 100644 --- a/VCF.sln +++ b/VCF.sln @@ -3,14 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32519.111 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VampireCommandFramework", "VampireCommandFrameworkPlugin\VampireCommandFramework.csproj", "{54C82B43-DB9B-4E83-8E43-79FFE691CE85}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VCF.Core", "VCF.Core\VCF.Core.csproj", "{54C82B43-DB9B-4E83-8E43-79FFE691CE85}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VCF.SimpleSamplePlugin", "VCF.SimpleSamplePlugin\VCF.SimpleSamplePlugin.csproj", "{85CE497F-326B-4E35-97FA-01439C4F8CA6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VCF.Tests", "VCF.Tests\VCF.Tests.csproj", "{05FC95C7-6679-48C8-8633-FB27CC94A43F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VCF.Core", "VCF.Core\VCF.Core.csproj", "{34DBB564-4F68-428D-8597-1511606C672D}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,10 +27,6 @@ Global {05FC95C7-6679-48C8-8633-FB27CC94A43F}.Debug|Any CPU.Build.0 = Debug|Any CPU {05FC95C7-6679-48C8-8633-FB27CC94A43F}.Release|Any CPU.ActiveCfg = Release|Any CPU {05FC95C7-6679-48C8-8633-FB27CC94A43F}.Release|Any CPU.Build.0 = Release|Any CPU - {34DBB564-4F68-428D-8597-1511606C672D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34DBB564-4F68-428D-8597-1511606C672D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34DBB564-4F68-428D-8597-1511606C672D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {34DBB564-4F68-428D-8597-1511606C672D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/VampireCommandFrameworkPlugin/Breadstone/IRunOnInitialized.cs b/VampireCommandFrameworkPlugin/Breadstone/IRunOnInitialized.cs deleted file mode 100644 index 6bd4ffc..0000000 --- a/VampireCommandFrameworkPlugin/Breadstone/IRunOnInitialized.cs +++ /dev/null @@ -1,30 +0,0 @@ - - -namespace VampireCommandFramework.Breadstone; - -/// -/// Helper interface for plugins that wish to run something once the -/// game has been initialized, instead of during plugin loading time. -/// This is useful because when BepInEx normally loads us, the ECS -/// worlds have yet to be initialized. This is not a problem for hooking, -/// but for other cases some callback to know when the game has initialized -/// is nice to have. -/// -/// This interface will run your code both when it is loaded normally (i.e. -/// as a normal BepInEx plugin) and when it is reloaded through the Wetstone -/// reloading facilities (see also the Reloadable attribute). You do not need -/// to attach an event handler anywhere, we'll magically call your plugin. -/// -/// This works on both client and server. The exact time at which the callback -/// will be called is undefined, but it is guaranteed to happen after the -/// ECS system has been initialized. -/// -public interface IRunOnInitialized -{ - /// - /// Callback to be called when the game's ECS system has finished initializing. - /// See the type documentation for IRunOnInitialized for more details on the - /// exact semantics of this function. - /// - public void OnGameInitialized(); -} diff --git a/VampireCommandFrameworkPlugin/Breadstone/OnInitialize.cs b/VampireCommandFrameworkPlugin/Breadstone/OnInitialize.cs deleted file mode 100644 index 382bd29..0000000 --- a/VampireCommandFrameworkPlugin/Breadstone/OnInitialize.cs +++ /dev/null @@ -1,48 +0,0 @@ -using BepInEx.Unity.IL2CPP; -using HarmonyLib; -using VampireCommandFramework.Common; - -namespace VampireCommandFramework.Breadstone; - -/// -/// Hook responsible for handling calls to IRunOnInitialized. -/// -internal static class OnInitialize -{ - internal static bool HasInitialized { get; private set; } = false; - - internal static void InvokePlugins() - { - Log.Info("Game has bootstrapped. Worlds and systems now exist."); - - if (HasInitialized) return; - HasInitialized = true; - - foreach (var (name, info) in IL2CPPChainloader.Instance.Plugins) - { - if (info.Instance is IRunOnInitialized runOnInitialized) - { - runOnInitialized.OnGameInitialized(); - } - } - - foreach (var plugin in Reload._loadedPlugins) - { - if (plugin is IRunOnInitialized runOnInitialized) - { - runOnInitialized.OnGameInitialized(); - } - } - } -} - -[HarmonyPatch("ProjectM.GameBootstrap", "Start")] -public static class SeverDetours -{ - // use of string here is intentional, avoids issues if the class somehow does not exist - [HarmonyPostfix] - public static void Postfix() - { - OnInitialize.InvokePlugins(); - } -} \ No newline at end of file diff --git a/VampireCommandFrameworkPlugin/Breadstone/Reload.cs b/VampireCommandFrameworkPlugin/Breadstone/Reload.cs deleted file mode 100644 index f5f720d..0000000 --- a/VampireCommandFrameworkPlugin/Breadstone/Reload.cs +++ /dev/null @@ -1,127 +0,0 @@ -using BepInEx.Unity.IL2CPP; -using BepInEx; -using Mono.Cecil; -using System; -using System.Collections.Generic; -using System.Linq; -using VampireCommandFramework.Common; -using System.IO; -using System.Reflection; - -namespace VampireCommandFramework.Breadstone; - -/// -/// This functionality is a server side adoption from Wetstone with VCF commands -/// -internal static class Reload -{ -#nullable disable - private static string _reloadPluginsFolder; -#nullable enable - - internal static List _loadedPlugins = new(); - - internal static void Initialize(string reloadPluginsFolder) - { - _reloadPluginsFolder = reloadPluginsFolder; - LoadPlugins(); - } - - [Command("reload","re", adminOnly:true)] - public static void HandleReloadCommand(ICommandContext ctx) - { - UnloadPlugins(); - var loaded = LoadPlugins(); - - if (loaded.Count > 0) - { - ctx.Reply($"Reloaded {string.Join(", ", loaded)}. See console for details."); - } - else - { - ctx.Reply($"Did not reload any plugins because no reloadable plugins were found. Check the console for more details."); - } - } - - private static void UnloadPlugins() - { - for (int i = _loadedPlugins.Count - 1; i >= 0; i--) - { - var plugin = _loadedPlugins[i]; - - if (!plugin.Unload()) - { - Log.Warning($"Plugin {plugin.GetType().FullName} does not support unloading, skipping..."); - } - else - { - _loadedPlugins.RemoveAt(i); - } - } - } - - private static List LoadPlugins() - { - if (!Directory.Exists(_reloadPluginsFolder)) return new(); - - return Directory.GetFiles(_reloadPluginsFolder, "*.dll").SelectMany(LoadPlugin).ToList(); - } - - private static List LoadPlugin(string path) - { - var defaultResolver = new DefaultAssemblyResolver(); - defaultResolver.AddSearchDirectory(_reloadPluginsFolder); - defaultResolver.AddSearchDirectory(Paths.ManagedPath); - defaultResolver.AddSearchDirectory(Paths.BepInExAssemblyDirectory); - - // Il2CppInteropManager.IL2CPPInteropAssemblyPath is internal so this will have to do - defaultResolver.AddSearchDirectory(Path.Combine(Paths.BepInExRootPath, "interop")); - - using var dll = AssemblyDefinition.ReadAssembly(path, new() { AssemblyResolver = defaultResolver }); - dll.Name.Name = $"{dll.Name.Name}-{DateTime.Now.Ticks}"; - - using var ms = new MemoryStream(); - dll.Write(ms); - - var loaded = new List(); - - var assembly = Assembly.Load(ms.ToArray()); - foreach (var pluginType in assembly.GetTypes().Where(x => typeof(BasePlugin).IsAssignableFrom(x))) - { - // skip plugins not marked as reloadable - if (!pluginType.GetCustomAttributes().Any()) - { - Log.Warning($"Plugin {pluginType.FullName} is not marked as reloadable, skipping..."); - continue; - } - - // skip plugins already loaded - if (_loadedPlugins.Any(x => x.GetType() == pluginType)) continue; - - try - { - // we skip chainloader here and don't check dependencies. Fast n dirty. - var plugin = (BasePlugin)Activator.CreateInstance(pluginType); - var metadata = MetadataHelper.GetMetadata(plugin); - _loadedPlugins.Add(plugin); - plugin.Load(); - loaded.Add(metadata.Name); - - // ensure initialize hook runs even if we reload far after initialization is already done - if (OnInitialize.HasInitialized && plugin is IRunOnInitialized runOnInitialized) - { - runOnInitialized.OnGameInitialized(); - } - - Log.Info($"Loaded plugin {pluginType.FullName}"); - } - catch (Exception ex) - { - Log.Error($"Plugin {pluginType.FullName} threw an exception during initialization:"); - Log.Error(ex.ToString()); - } - } - - return loaded; - } -} \ No newline at end of file diff --git a/VampireCommandFrameworkPlugin/Breadstone/ReloadableAttribute.cs b/VampireCommandFrameworkPlugin/Breadstone/ReloadableAttribute.cs deleted file mode 100644 index 862443a..0000000 --- a/VampireCommandFrameworkPlugin/Breadstone/ReloadableAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace VampireCommandFramework.Breadstone; - -/// -/// Plugins that implement this interface will be reloaded when the -/// .reload VCF is executed. This is intended for development only -/// -/// -/// This is intended for mods that don't use Wetstone. This was included -/// during Gloomrot compatibility work to speed up development. -/// -/// Expect this might change without a major version bump as it's experimental -/// -[System.AttributeUsage(System.AttributeTargets.Class)] -public class ReloadableAttribute : System.Attribute -{ - -} diff --git a/VampireCommandFrameworkPlugin/Breadstone/Shim.cs b/VampireCommandFrameworkPlugin/Breadstone/Shim.cs deleted file mode 100644 index f1f4bd1..0000000 --- a/VampireCommandFrameworkPlugin/Breadstone/Shim.cs +++ /dev/null @@ -1,6 +0,0 @@ - -namespace System.Runtime.CompilerServices; - -internal sealed class IsUnmanagedAttribute : System.Attribute { } - -internal class IsExternalInit { } \ No newline at end of file diff --git a/VampireCommandFrameworkPlugin/VampireCommandFramework.csproj b/VampireCommandFrameworkPlugin/VampireCommandFramework.csproj deleted file mode 100644 index a232e10..0000000 --- a/VampireCommandFrameworkPlugin/VampireCommandFramework.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - net6.0 - VampireCommandFramework - My first plugin - 0.0.999 - true - latest - ../nuget.nuspec - version=$(Version) - gg.deca.VampireCommandFramework - VampireCommandFramework - VampireCommandFramework - deca - - - - - - - - - - - - - - - - - - - - - diff --git a/nuget.nuspec b/nuget.nuspec index 10b9457..8a70b59 100644 --- a/nuget.nuspec +++ b/nuget.nuspec @@ -17,7 +17,7 @@ - +