From df43b90f7edea54d33997748c6a103f28bd2f6c4 Mon Sep 17 00:00:00 2001 From: soul4soul <5142635+soul4soul@users.noreply.github.com> Date: Sun, 23 May 2021 12:17:48 -0400 Subject: [PATCH] Update the app to use a plug-in style system where each monster format is its own assembly (#17) * Extract and add converter specific logic to the converter classes This is a first of several commits to pluggable converter architecture. Converter logic was remove from the MonsterFileProcessor class. Each converter must be able to identify what it supports and implement the appropriate logic. * Update logic in MonsterFileProcessor to only use information provided from the converterclasses instead of hardcoded logic * Work on organizing and sperating each converter into its own assembly Move each converter into its own assembly. Move generic Monster classes into its own assembly. Fixed UI code to use parsed converter types instead of being hardcoded (WIP, mostly fixed compilation errors) Working on pluginhelper class which finds available converters on the local system * dynamically load hardcoded list of converters * Update project to .NET5 * Remove test code from pluginhelper class * Change plugin helper instance to async to ensure it's loaded all dlls before use * Fix command line usage with use of new pluginhelper class * update nuget packages * update github actions for .net 5 workload * update readme --- .github/workflows/wpfdotnet-core.yml | 62 +------ OTMonsterConverter.sln | 25 --- .../Converter/IMonsterConverter.cs | 16 -- OTMonsterConverter/OTMonsterConverter.csproj | 22 --- README.md | 4 +- .../IMonsterConverter.cs | 32 ++++ .../MonsterConverter.cs | 31 ++++ .../MonsterConverterInterface.csproj | 11 ++ .../MonsterTypes/DetailedLookType.cs | 2 +- .../MonsterTypes/EnumTypes.cs | 2 +- .../MonsterTypes/Loot.cs | 2 +- .../MonsterTypes/Monster.cs | 2 +- .../MonsterTypes/Spell.cs | 2 +- .../MonsterTypes/SpellCategory.cs | 2 +- .../MonsterTypes/Summon.cs | 2 +- .../MonsterTypes/Voice.cs | 2 +- .../MonsterConverterPyOt.csproj | 25 +++ .../MonsterConverterPyOt}/PyOtConverter.cs | 23 ++- .../MonsterConverterTfsRevScriptSys.csproj | 25 +++ .../TfsRevScriptSysConverter.cs | 31 +++- .../MonsterConverterTfsXml.csproj | 25 +++ .../TfsXmlConverter.cs | 24 ++- .../MonsterConverterTibiaWiki}/Extensions.cs | 2 +- .../MonsterConverterTibiaWiki.csproj | 26 +++ .../TibiaWikiConverter.cs | 55 +++++- app/OTMonsterConverter.sln | 55 ++++++ .../OTMonsterConverter}/AboutWindow.xaml | 0 .../OTMonsterConverter}/AboutWindow.xaml.cs | 0 .../OTMonsterConverter}/AssemblyInfo.cs | 0 .../OTMonsterConverter}/ConsoleWindow.cs | 28 ++- .../OTMonsterConverter}/Images/info.png | Bin .../OTMonsterConverter}/MainWindow.xaml | 14 +- .../OTMonsterConverter}/MainWindow.xaml.cs | 44 +++-- .../MonsterFileProcessor.cs | 98 +--------- .../OTMonsterConverter.csproj | 37 ++++ app/OTMonsterConverter/PluginHelper.cs | 109 +++++++++++ .../OTMonsterConverter}/Program.cs | 172 +++++++++--------- .../OTMonsterConverter}/app.ico | Bin 38 files changed, 641 insertions(+), 371 deletions(-) delete mode 100644 OTMonsterConverter.sln delete mode 100644 OTMonsterConverter/Converter/IMonsterConverter.cs delete mode 100644 OTMonsterConverter/OTMonsterConverter.csproj create mode 100644 app/MonsterConverterInterface/IMonsterConverter.cs create mode 100644 app/MonsterConverterInterface/MonsterConverter.cs create mode 100644 app/MonsterConverterInterface/MonsterConverterInterface.csproj rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/DetailedLookType.cs (95%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/EnumTypes.cs (98%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/Loot.cs (87%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/Monster.cs (98%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/Spell.cs (96%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/SpellCategory.cs (75%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/Summon.cs (86%) rename {OTMonsterConverter => app/MonsterConverterInterface}/MonsterTypes/Voice.cs (80%) create mode 100644 app/MonsterConverterPyOt/MonsterConverterPyOt.csproj rename {OTMonsterConverter/Converter => app/MonsterConverterPyOt}/PyOtConverter.cs (89%) create mode 100644 app/MonsterConverterTfsRevScriptSys/MonsterConverterTfsRevScriptSys.csproj rename {OTMonsterConverter/Converter => app/MonsterConverterTfsRevScriptSys}/TfsRevScriptSysConverter.cs (97%) create mode 100644 app/MonsterConverterTfsXml/MonsterConverterTfsXml.csproj rename {OTMonsterConverter/Converter => app/MonsterConverterTfsXml}/TfsXmlConverter.cs (98%) rename {OTMonsterConverter => app/MonsterConverterTibiaWiki}/Extensions.cs (94%) create mode 100644 app/MonsterConverterTibiaWiki/MonsterConverterTibiaWiki.csproj rename {OTMonsterConverter/Converter => app/MonsterConverterTibiaWiki}/TibiaWikiConverter.cs (91%) create mode 100644 app/OTMonsterConverter.sln rename {OTMonsterConverter => app/OTMonsterConverter}/AboutWindow.xaml (100%) rename {OTMonsterConverter => app/OTMonsterConverter}/AboutWindow.xaml.cs (100%) rename {OTMonsterConverter => app/OTMonsterConverter}/AssemblyInfo.cs (100%) rename {OTMonsterConverter => app/OTMonsterConverter}/ConsoleWindow.cs (70%) rename {OTMonsterConverter => app/OTMonsterConverter}/Images/info.png (100%) rename {OTMonsterConverter => app/OTMonsterConverter}/MainWindow.xaml (85%) rename {OTMonsterConverter => app/OTMonsterConverter}/MainWindow.xaml.cs (81%) rename {OTMonsterConverter => app/OTMonsterConverter}/MonsterFileProcessor.cs (57%) create mode 100644 app/OTMonsterConverter/OTMonsterConverter.csproj create mode 100644 app/OTMonsterConverter/PluginHelper.cs rename {OTMonsterConverter => app/OTMonsterConverter}/Program.cs (88%) rename {OTMonsterConverter => app/OTMonsterConverter}/app.ico (100%) diff --git a/.github/workflows/wpfdotnet-core.yml b/.github/workflows/wpfdotnet-core.yml index ab5fd881..b50227c8 100644 --- a/.github/workflows/wpfdotnet-core.yml +++ b/.github/workflows/wpfdotnet-core.yml @@ -1,42 +1,4 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow will build, test and package a WPF desktop application -# built on .NET Core. -# To learn how to migrate your existing WPF application to .NET Core, -# refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework -# -# To configure this workflow: -# -# 1. Configure environment variables -# GitHub sets default environment variables for every workflow run. -# Replace the variables relative to your project in the "env" section below. -# -# 2. Signing -# Generate a signing certificate in the Windows Application -# Packaging Project or add an existing signing certificate to the project. -# Next, use PowerShell to encode the .pfx file using Base64 encoding -# by running the following Powershell script to generate the output string: -# -# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte -# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' -# -# Open the output file, SigningCertificate_Encoded.txt, and copy the -# string inside. Then, add the string to the repo as a GitHub secret -# and name it "Base64_Encoded_Pfx." -# For more information on how to configure your signing certificate for -# this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing -# -# Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key". -# See "Build the Windows Application Packaging project" below to see how the secret is used. -# -# For more information on GitHub Actions, refer to https://github.com/features/actions -# For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications, -# refer to https://github.com/microsoft/github-actions-for-desktop-apps - -name: WPF .NET Core +name: Build on Windows on: push: @@ -52,30 +14,24 @@ jobs: matrix: configuration: [Debug, Release] - runs-on: windows-latest # For a list of available runner types, refer to - # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on + runs-on: windows-latest env: - Solution_Name: OTMonsterConverter.sln # Replace with your solution name, i.e. MyWpfApp.sln. + SolutionPath: app\OTMonsterConverter.sln steps: - name: Checkout uses: actions/checkout@v2 - with: - fetch-depth: 0 - # Install the .NET Core workload - - name: Install .NET Core + - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.101 + dotnet-version: 5.0.x - # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild - - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@2008f912f56e61277eefaac6d1888b750582aa16 + - name: Restore dependencies + run: dotnet restore $env:SolutionPath - # Restore the WPF application to populate the obj folder with RuntimeIdentifiers - - name: Restore the WPF application - run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration + - name: Build + run: dotnet build $env:SolutionPath --no-restore --configuration=$env:Configuration env: Configuration: ${{ matrix.configuration }} diff --git a/OTMonsterConverter.sln b/OTMonsterConverter.sln deleted file mode 100644 index 625e098e..00000000 --- a/OTMonsterConverter.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30002.166 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OTMonsterConverter", "OTMonsterConverter\OTMonsterConverter.csproj", "{BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {60E82F53-8F7A-42AC-8894-89C5CD6953AE} - EndGlobalSection -EndGlobal diff --git a/OTMonsterConverter/Converter/IMonsterConverter.cs b/OTMonsterConverter/Converter/IMonsterConverter.cs deleted file mode 100644 index a9af2df0..00000000 --- a/OTMonsterConverter/Converter/IMonsterConverter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using OTMonsterConverter.MonsterTypes; -using System; -using System.Collections.Generic; -using System.Text; - -namespace OTMonsterConverter.Converter -{ - public interface IMonsterConverter - { - string FileExtRegEx { get; } - - bool ReadMonster(string filename, out Monster monster); - - bool WriteMonster(string directory, ref Monster monster); - } -} diff --git a/OTMonsterConverter/OTMonsterConverter.csproj b/OTMonsterConverter/OTMonsterConverter.csproj deleted file mode 100644 index 15aaff33..00000000 --- a/OTMonsterConverter/OTMonsterConverter.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - Exe - netcoreapp3.1 - true - true - app.ico - Soul4Soul - 2.0.0.0 - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 416aca7e..05e5df79 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Tibia OT Monster Converter is a tool for converting monster files between the va ## Technology -- .NET Core 3.1 +- .NET 5 - WPF - Visual Studio 2019 @@ -49,6 +49,6 @@ Options: Improvements and bug fixes are welcome, via pull requests For questions, suggestions and bug reports, submit an issue. -Another to contribute to this project is by contributing to [TibiaWiki](https://tibia.fandom.com) to improve creature information. +Another way to contribute to this project is by contributing to [TibiaWiki](https://tibia.fandom.com) to improve creature information. ![image](https://vignette.wikia.nocookie.net/tibia/images/d/d9/Tibiawiki_Small.gif/revision/latest?cb=20150129101832&path-prefix=en) diff --git a/app/MonsterConverterInterface/IMonsterConverter.cs b/app/MonsterConverterInterface/IMonsterConverter.cs new file mode 100644 index 00000000..149699cc --- /dev/null +++ b/app/MonsterConverterInterface/IMonsterConverter.cs @@ -0,0 +1,32 @@ +using MonsterConverterInterface.MonsterTypes; +using System; + +namespace MonsterConverterInterface +{ + public enum FileSource + { + LocalFiles, + Web + } + + // name, isreadsupported, and iswritesupported can all be metadataattributes should that be valuable localfile source too + // none of those fields deal with function they all are for information only + public interface IMonsterConverter + { + string ConverterName { get; } + + string FileExt { get; } + + FileSource FileSource { get; } + + bool IsReadSupported { get; } + + bool IsWriteSupported { get; } + + string[] GetFilesForConversion(string directory); + + bool ReadMonster(string filename, out Monster monster); + + bool WriteMonster(string directory, ref Monster monster); + } +} diff --git a/app/MonsterConverterInterface/MonsterConverter.cs b/app/MonsterConverterInterface/MonsterConverter.cs new file mode 100644 index 00000000..239f0a5b --- /dev/null +++ b/app/MonsterConverterInterface/MonsterConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using MonsterConverterInterface.MonsterTypes; + +namespace MonsterConverterInterface +{ + public abstract class MonsterConverter : IMonsterConverter + { + public abstract string ConverterName { get; } + + public abstract string FileExt { get; } + + public virtual FileSource FileSource { get => FileSource.LocalFiles; } + + public abstract bool IsReadSupported { get; } + + public abstract bool IsWriteSupported { get; } + + public virtual string[] GetFilesForConversion(string directory) + { + string searchPattern = "*." + FileExt; + return Directory.GetFiles(directory, searchPattern, SearchOption.AllDirectories); + } + + public abstract bool ReadMonster(string filename, out Monster monster); + + public abstract bool WriteMonster(string directory, ref Monster monster); + } +} diff --git a/app/MonsterConverterInterface/MonsterConverterInterface.csproj b/app/MonsterConverterInterface/MonsterConverterInterface.csproj new file mode 100644 index 00000000..a6be76ae --- /dev/null +++ b/app/MonsterConverterInterface/MonsterConverterInterface.csproj @@ -0,0 +1,11 @@ + + + + net5.0 + + + + + + + diff --git a/OTMonsterConverter/MonsterTypes/DetailedLookType.cs b/app/MonsterConverterInterface/MonsterTypes/DetailedLookType.cs similarity index 95% rename from OTMonsterConverter/MonsterTypes/DetailedLookType.cs rename to app/MonsterConverterInterface/MonsterTypes/DetailedLookType.cs index 7f81bc92..0e1888f1 100644 --- a/OTMonsterConverter/MonsterTypes/DetailedLookType.cs +++ b/app/MonsterConverterInterface/MonsterTypes/DetailedLookType.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { //todo should we add outfit ID to this class? public class DetailedLookType diff --git a/OTMonsterConverter/MonsterTypes/EnumTypes.cs b/app/MonsterConverterInterface/MonsterTypes/EnumTypes.cs similarity index 98% rename from OTMonsterConverter/MonsterTypes/EnumTypes.cs rename to app/MonsterConverterInterface/MonsterTypes/EnumTypes.cs index 7eee5212..1a52b4aa 100644 --- a/OTMonsterConverter/MonsterTypes/EnumTypes.cs +++ b/app/MonsterConverterInterface/MonsterTypes/EnumTypes.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public enum Condition { diff --git a/OTMonsterConverter/MonsterTypes/Loot.cs b/app/MonsterConverterInterface/MonsterTypes/Loot.cs similarity index 87% rename from OTMonsterConverter/MonsterTypes/Loot.cs rename to app/MonsterConverterInterface/MonsterTypes/Loot.cs index 2518a2e8..fd7018bd 100644 --- a/OTMonsterConverter/MonsterTypes/Loot.cs +++ b/app/MonsterConverterInterface/MonsterTypes/Loot.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public class Loot { diff --git a/OTMonsterConverter/MonsterTypes/Monster.cs b/app/MonsterConverterInterface/MonsterTypes/Monster.cs similarity index 98% rename from OTMonsterConverter/MonsterTypes/Monster.cs rename to app/MonsterConverterInterface/MonsterTypes/Monster.cs index 37ecaf55..8de3d043 100644 --- a/OTMonsterConverter/MonsterTypes/Monster.cs +++ b/app/MonsterConverterInterface/MonsterTypes/Monster.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public class Monster { diff --git a/OTMonsterConverter/MonsterTypes/Spell.cs b/app/MonsterConverterInterface/MonsterTypes/Spell.cs similarity index 96% rename from OTMonsterConverter/MonsterTypes/Spell.cs rename to app/MonsterConverterInterface/MonsterTypes/Spell.cs index 720ec0d3..6bd1bf0d 100644 --- a/OTMonsterConverter/MonsterTypes/Spell.cs +++ b/app/MonsterConverterInterface/MonsterTypes/Spell.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public class Spell { diff --git a/OTMonsterConverter/MonsterTypes/SpellCategory.cs b/app/MonsterConverterInterface/MonsterTypes/SpellCategory.cs similarity index 75% rename from OTMonsterConverter/MonsterTypes/SpellCategory.cs rename to app/MonsterConverterInterface/MonsterTypes/SpellCategory.cs index 69ba8dab..045733c1 100644 --- a/OTMonsterConverter/MonsterTypes/SpellCategory.cs +++ b/app/MonsterConverterInterface/MonsterTypes/SpellCategory.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public enum SpellCategory { diff --git a/OTMonsterConverter/MonsterTypes/Summon.cs b/app/MonsterConverterInterface/MonsterTypes/Summon.cs similarity index 86% rename from OTMonsterConverter/MonsterTypes/Summon.cs rename to app/MonsterConverterInterface/MonsterTypes/Summon.cs index eeb57ed8..73b6d052 100644 --- a/OTMonsterConverter/MonsterTypes/Summon.cs +++ b/app/MonsterConverterInterface/MonsterTypes/Summon.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public class Summon { diff --git a/OTMonsterConverter/MonsterTypes/Voice.cs b/app/MonsterConverterInterface/MonsterTypes/Voice.cs similarity index 80% rename from OTMonsterConverter/MonsterTypes/Voice.cs rename to app/MonsterConverterInterface/MonsterTypes/Voice.cs index 24dd9d27..2dda207c 100644 --- a/OTMonsterConverter/MonsterTypes/Voice.cs +++ b/app/MonsterConverterInterface/MonsterTypes/Voice.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace OTMonsterConverter.MonsterTypes +namespace MonsterConverterInterface.MonsterTypes { public class Voice { diff --git a/app/MonsterConverterPyOt/MonsterConverterPyOt.csproj b/app/MonsterConverterPyOt/MonsterConverterPyOt.csproj new file mode 100644 index 00000000..fecfe2d8 --- /dev/null +++ b/app/MonsterConverterPyOt/MonsterConverterPyOt.csproj @@ -0,0 +1,25 @@ + + + + net5.0 + + + + ..\..\bin\$(Configuration) + false + + + + ..\..\bin\$(Configuration) + false + + + + + + + + + + + diff --git a/OTMonsterConverter/Converter/PyOtConverter.cs b/app/MonsterConverterPyOt/PyOtConverter.cs similarity index 89% rename from OTMonsterConverter/Converter/PyOtConverter.cs rename to app/MonsterConverterPyOt/PyOtConverter.cs index 8ee00f10..bd961a82 100644 --- a/OTMonsterConverter/Converter/PyOtConverter.cs +++ b/app/MonsterConverterPyOt/PyOtConverter.cs @@ -1,25 +1,34 @@ -using OTMonsterConverter.MonsterTypes; +using MonsterConverterInterface; +using MonsterConverterInterface.MonsterTypes; using System; using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Globalization; using System.IO; using System.Text; -namespace OTMonsterConverter.Converter +namespace MonsterConverterPyOt.Converter { // https://bitbucket.org/vapus/pyot/src/0aa7c38f46814f502f375b84ac905e7f5ebef1a3/game/monster.py?at=default - public class PyOtConverter : IMonsterConverter + [Export(typeof(IMonsterConverter))] + public class PyOtConverter : MonsterConverter { - public string FileExtRegEx { get => "*.py"; } + public override string ConverterName { get => "pyOT"; } + + public override string FileExt { get => "py"; } + + public override bool IsReadSupported { get => false; } + + public override bool IsWriteSupported { get => true; } // Functions - public bool ReadMonster(string filename, out Monster monster) + public override bool ReadMonster(string filename, out Monster monster) { monster = new Monster(); return false; // Not Implemented } - public bool WriteMonster(string directory, ref Monster monster) + public override bool WriteMonster(string directory, ref Monster monster) { string lowerName = monster.Name.ToLower(); // TODO Remove special chars spaces etc.. want a-z_ for characters... Can we just use a fixed variable name such as "monster"? @@ -42,7 +51,7 @@ public bool WriteMonster(string directory, ref Monster monster) GenericToPyOTVoice(lowerName, ref monster), GenericToPyOTLoot(lowerName, ref monster) }; - string fileName = Path.Combine(directory, monster.FileName + ".py"); + string fileName = Path.Combine(directory, monster.FileName + "." + FileExt); File.WriteAllLines(fileName, lines); return true; diff --git a/app/MonsterConverterTfsRevScriptSys/MonsterConverterTfsRevScriptSys.csproj b/app/MonsterConverterTfsRevScriptSys/MonsterConverterTfsRevScriptSys.csproj new file mode 100644 index 00000000..fecfe2d8 --- /dev/null +++ b/app/MonsterConverterTfsRevScriptSys/MonsterConverterTfsRevScriptSys.csproj @@ -0,0 +1,25 @@ + + + + net5.0 + + + + ..\..\bin\$(Configuration) + false + + + + ..\..\bin\$(Configuration) + false + + + + + + + + + + + diff --git a/OTMonsterConverter/Converter/TfsRevScriptSysConverter.cs b/app/MonsterConverterTfsRevScriptSys/TfsRevScriptSysConverter.cs similarity index 97% rename from OTMonsterConverter/Converter/TfsRevScriptSysConverter.cs rename to app/MonsterConverterTfsRevScriptSys/TfsRevScriptSysConverter.cs index 7276002c..a1d0507c 100644 --- a/OTMonsterConverter/Converter/TfsRevScriptSysConverter.cs +++ b/app/MonsterConverterTfsRevScriptSys/TfsRevScriptSysConverter.cs @@ -1,14 +1,18 @@ -using OTMonsterConverter.MonsterTypes; +using MonsterConverterInterface; +using MonsterConverterInterface.MonsterTypes; using System; using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Globalization; using System.IO; -using System.Text; -namespace OTMonsterConverter.Converter +namespace MonsterConverterTfsRevScriptSys { - public class TfsRevScriptSysConverter : IMonsterConverter + [Export(typeof(IMonsterConverter))] + public class TfsRevScriptSysConverter : MonsterConverter { + public override string ConverterName { get => "TFS RevScriptSys"; } + const uint MAX_LOOTCHANCE = 100000; IDictionary ConditioToTFsConstants = new Dictionary @@ -198,11 +202,15 @@ public class TfsRevScriptSysConverter : IMonsterConverter {Animation.SimpleArrow, "CONST_ANI_SIMPLEARROW"}, }; - public string FileExtRegEx { get => "*.lua"; } + public override string FileExt { get => "lua"; } + + public override bool IsReadSupported { get => false; } - public bool WriteMonster(string directory, ref Monster monster) + public override bool IsWriteSupported { get => true; } + + public override bool WriteMonster(string directory, ref Monster monster) { - string fileName = Path.Combine(directory, monster.FileName + ".lua"); + string fileName = Path.Combine(directory, monster.FileName + "." + FileExt); using (var fstream = File.OpenWrite(fileName)) using (var dest = new StreamWriter(fstream)) @@ -301,7 +309,8 @@ public bool WriteMonster(string directory, ref Monster monster) for (int i = 0; i < monster.Summons.Count; i++) { summon = $" {{name = \"{monster.Summons[i].Name}\", chance = {monster.Summons[i].Chance * 100}, interval = {monster.Summons[i].Rate}"; - if (monster.Summons[i].Max > 0) { + if (monster.Summons[i].Max > 0) + { summon += $", max = {monster.Summons[i].Max}"; } @@ -314,7 +323,9 @@ public bool WriteMonster(string directory, ref Monster monster) if (i == monster.Summons.Count - 1) { summon = summon.TrimEnd(','); - } else { + } + else + { summon += ","; } dest.WriteLine(summon); @@ -471,7 +482,7 @@ public bool WriteMonster(string directory, ref Monster monster) return true; } - public bool ReadMonster(string filename, out Monster monster) + public override bool ReadMonster(string filename, out Monster monster) { throw new NotImplementedException(); } diff --git a/app/MonsterConverterTfsXml/MonsterConverterTfsXml.csproj b/app/MonsterConverterTfsXml/MonsterConverterTfsXml.csproj new file mode 100644 index 00000000..c0ad1ac5 --- /dev/null +++ b/app/MonsterConverterTfsXml/MonsterConverterTfsXml.csproj @@ -0,0 +1,25 @@ + + + + net5.0 + + + + ..\..\bin\$(Configuration) + false + + + + ..\..\bin\$(Configuration) + false + + + + + + + + + + + diff --git a/OTMonsterConverter/Converter/TfsXmlConverter.cs b/app/MonsterConverterTfsXml/TfsXmlConverter.cs similarity index 98% rename from OTMonsterConverter/Converter/TfsXmlConverter.cs rename to app/MonsterConverterTfsXml/TfsXmlConverter.cs index 68081d8f..41d4bac7 100644 --- a/OTMonsterConverter/Converter/TfsXmlConverter.cs +++ b/app/MonsterConverterTfsXml/TfsXmlConverter.cs @@ -1,18 +1,22 @@ -using OTMonsterConverter.MonsterTypes; +using MonsterConverterInterface; +using MonsterConverterInterface.MonsterTypes; using System; using System.Collections.Generic; +using System.ComponentModel.Composition; using System.IO; using System.Text; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; -namespace OTMonsterConverter.Converter +namespace MonsterConverterTfsXml { //https://github.com/otland/forgottenserver/blob/master/src/monsters.cpp - - class TfsXmlConverter : IMonsterConverter + [Export(typeof(IMonsterConverter))] + public class TfsXmlConverter : MonsterConverter { + public override string ConverterName { get => "TFS XML"; } + const uint MAX_LOOTCHANCE = 100000; const uint ATTACK_INTERVAL_DEFAULT = 2000; @@ -171,10 +175,14 @@ class TfsXmlConverter : IMonsterConverter //{"undefined", CombatDamage.Undefined} }; - public string FileExtRegEx { get => "*.xml"; } + public override string FileExt { get => "xml"; } + + public override bool IsReadSupported { get => true; } + + public override bool IsWriteSupported { get => false; } // Functions - public bool ReadMonster(string filename, out Monster monster) + public override bool ReadMonster(string filename, out Monster monster) { XmlSerializer serializer = new XmlSerializer(typeof(TFSXmlMonster)); @@ -194,9 +202,9 @@ public bool ReadMonster(string filename, out Monster monster) return true; } - public bool WriteMonster(string directory, ref Monster monster) + public override bool WriteMonster(string directory, ref Monster monster) { - string fileName = Path.Combine(directory, monster.Name.ToLower()); + string fileName = Path.Combine(directory, monster.FileName + "." + FileExt); XDocument xDoc = XDocument.Load(fileName); xDoc.Root.Add(new XElement("monster", diff --git a/OTMonsterConverter/Extensions.cs b/app/MonsterConverterTibiaWiki/Extensions.cs similarity index 94% rename from OTMonsterConverter/Extensions.cs rename to app/MonsterConverterTibiaWiki/Extensions.cs index 56ccf8c9..0b32eefd 100644 --- a/OTMonsterConverter/Extensions.cs +++ b/app/MonsterConverterTibiaWiki/Extensions.cs @@ -3,7 +3,7 @@ using System.Text; using System.Text.RegularExpressions; -namespace OTMonsterConverter +namespace MonsterConverterTibiaWiki { public static class Extensions { diff --git a/app/MonsterConverterTibiaWiki/MonsterConverterTibiaWiki.csproj b/app/MonsterConverterTibiaWiki/MonsterConverterTibiaWiki.csproj new file mode 100644 index 00000000..76efd121 --- /dev/null +++ b/app/MonsterConverterTibiaWiki/MonsterConverterTibiaWiki.csproj @@ -0,0 +1,26 @@ + + + + net5.0 + + + + ..\..\bin\$(Configuration) + false + + + + ..\..\bin\$(Configuration) + false + + + + + + + + + + + + diff --git a/OTMonsterConverter/Converter/TibiaWikiConverter.cs b/app/MonsterConverterTibiaWiki/TibiaWikiConverter.cs similarity index 91% rename from OTMonsterConverter/Converter/TibiaWikiConverter.cs rename to app/MonsterConverterTibiaWiki/TibiaWikiConverter.cs index e1584eac..74878b89 100644 --- a/OTMonsterConverter/Converter/TibiaWikiConverter.cs +++ b/app/MonsterConverterTibiaWiki/TibiaWikiConverter.cs @@ -1,19 +1,31 @@ -using OTMonsterConverter.MonsterTypes; +using MonsterConverterInterface; +using MonsterConverterInterface.MonsterTypes; using ScrapySharp.Extensions; using ScrapySharp.Network; using System; using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -namespace OTMonsterConverter.Converter + +namespace MonsterConverterTibiaWiki { - public class TibiaWikiConverter : IMonsterConverter + [Export(typeof(IMonsterConverter))] + public class TibiaWikiConverter : MonsterConverter { - public string FileExtRegEx => throw new NotImplementedException(); + public override string ConverterName { get => "TibiaWiki"; } + + public override FileSource FileSource { get => FileSource.Web; } + + public override string FileExt { get => "html"; } + + public override bool IsReadSupported { get => true; } + + public override bool IsWriteSupported { get => true; } public class RegexPatternKeys { @@ -250,7 +262,38 @@ private static string RemoveNonNumericChars(string input) return input; } - public bool ReadMonster(string filename, out Monster monster) + public override string[] GetFilesForConversion(string directory) + { + // directory parameter is ignored for this format... + + string monsterlisturl = $"https://tibia.fandom.com/wiki/List_of_Creatures_(Ordered)"; + IList names = new List(); + + ScrapingBrowser browser = new ScrapingBrowser(); + browser.Encoding = Encoding.UTF8; + WebPage monsterspage = browser.NavigateToPage(new Uri(monsterlisturl)); + var orderedLists = monsterspage.Html.CssSelect("ol"); + + // Links are HTML encoded + // %27 is HTML encode for ' character + // %27%C3% is HTML encode for ñ character + var nameregex = new Regex("/wiki/(?[[a-zA-Z.()_%27%C3%B1-]+)"); + foreach (var ol in orderedLists) + { + foreach (var child in ol.ChildNodes) + { + if (nameregex.IsMatch(child.InnerHtml)) + { + var namematches = nameregex.Matches(child.InnerHtml); + names.Add(namematches.FindNamedGroupValue("name").Replace("%27", "'").Replace("%C3%B1", "ñ")); + } + } + } + + return names.ToArray(); + } + + public override bool ReadMonster(string filename, out Monster monster) { string monsterurl = $"https://tibia.fandom.com/wiki/{filename}?action=edit"; string looturl = $"https://tibia.fandom.com/wiki/Loot_Statistics:{filename}?action=edit"; @@ -337,7 +380,7 @@ public bool ReadMonster(string filename, out Monster monster) return true; } - public bool WriteMonster(string directory, ref Monster monster) + public override bool WriteMonster(string directory, ref Monster monster) { string[] lines = { diff --git a/app/OTMonsterConverter.sln b/app/OTMonsterConverter.sln new file mode 100644 index 00000000..308c6b1a --- /dev/null +++ b/app/OTMonsterConverter.sln @@ -0,0 +1,55 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30002.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OTMonsterConverter", "OTMonsterConverter\OTMonsterConverter.csproj", "{BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonsterConverterInterface", "MonsterConverterInterface\MonsterConverterInterface.csproj", "{DCE6644C-1244-4870-8C14-A9FB84278053}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonsterConverterPyOt", "MonsterConverterPyOt\MonsterConverterPyOt.csproj", "{C9E453D0-44C9-4C5B-993B-0674B0D59BFC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonsterConverterTfsRevScriptSys", "MonsterConverterTfsRevScriptSys\MonsterConverterTfsRevScriptSys.csproj", "{06DEE9D3-54E6-4A93-AEB3-8BF550C139B5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonsterConverterTfsXml", "MonsterConverterTfsXml\MonsterConverterTfsXml.csproj", "{C2FF670C-BBF9-41AA-9613-30FDC5986191}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonsterConverterTibiaWiki", "MonsterConverterTibiaWiki\MonsterConverterTibiaWiki.csproj", "{804873AF-3756-427F-A3C8-4565063AB039}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBD1B272-ACB9-4658-B13B-AE7FB35ECF1A}.Release|Any CPU.Build.0 = Release|Any CPU + {DCE6644C-1244-4870-8C14-A9FB84278053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCE6644C-1244-4870-8C14-A9FB84278053}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCE6644C-1244-4870-8C14-A9FB84278053}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCE6644C-1244-4870-8C14-A9FB84278053}.Release|Any CPU.Build.0 = Release|Any CPU + {C9E453D0-44C9-4C5B-993B-0674B0D59BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9E453D0-44C9-4C5B-993B-0674B0D59BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9E453D0-44C9-4C5B-993B-0674B0D59BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9E453D0-44C9-4C5B-993B-0674B0D59BFC}.Release|Any CPU.Build.0 = Release|Any CPU + {06DEE9D3-54E6-4A93-AEB3-8BF550C139B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {06DEE9D3-54E6-4A93-AEB3-8BF550C139B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06DEE9D3-54E6-4A93-AEB3-8BF550C139B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {06DEE9D3-54E6-4A93-AEB3-8BF550C139B5}.Release|Any CPU.Build.0 = Release|Any CPU + {C2FF670C-BBF9-41AA-9613-30FDC5986191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2FF670C-BBF9-41AA-9613-30FDC5986191}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2FF670C-BBF9-41AA-9613-30FDC5986191}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2FF670C-BBF9-41AA-9613-30FDC5986191}.Release|Any CPU.Build.0 = Release|Any CPU + {804873AF-3756-427F-A3C8-4565063AB039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {804873AF-3756-427F-A3C8-4565063AB039}.Debug|Any CPU.Build.0 = Debug|Any CPU + {804873AF-3756-427F-A3C8-4565063AB039}.Release|Any CPU.ActiveCfg = Release|Any CPU + {804873AF-3756-427F-A3C8-4565063AB039}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {60E82F53-8F7A-42AC-8894-89C5CD6953AE} + EndGlobalSection +EndGlobal diff --git a/OTMonsterConverter/AboutWindow.xaml b/app/OTMonsterConverter/AboutWindow.xaml similarity index 100% rename from OTMonsterConverter/AboutWindow.xaml rename to app/OTMonsterConverter/AboutWindow.xaml diff --git a/OTMonsterConverter/AboutWindow.xaml.cs b/app/OTMonsterConverter/AboutWindow.xaml.cs similarity index 100% rename from OTMonsterConverter/AboutWindow.xaml.cs rename to app/OTMonsterConverter/AboutWindow.xaml.cs diff --git a/OTMonsterConverter/AssemblyInfo.cs b/app/OTMonsterConverter/AssemblyInfo.cs similarity index 100% rename from OTMonsterConverter/AssemblyInfo.cs rename to app/OTMonsterConverter/AssemblyInfo.cs diff --git a/OTMonsterConverter/ConsoleWindow.cs b/app/OTMonsterConverter/ConsoleWindow.cs similarity index 70% rename from OTMonsterConverter/ConsoleWindow.cs rename to app/OTMonsterConverter/ConsoleWindow.cs index d14fafb1..a966bdd2 100644 --- a/OTMonsterConverter/ConsoleWindow.cs +++ b/app/OTMonsterConverter/ConsoleWindow.cs @@ -1,6 +1,8 @@ -using System; +using MonsterConverterInterface; +using System; using System.Collections.Generic; using System.Text; +using System.Linq; namespace OTMonsterConverter { @@ -9,18 +11,20 @@ class ConsoleWindow private MonsterFileProcessor fileProcessor; private string inputDirectory; private string outputDirectory; - private MonsterFormat inputFormat; - private MonsterFormat outputFormat; + private IMonsterConverter input; + private IMonsterConverter output; private bool mirrorFolderStructure; - public ConsoleWindow(string inputDirectory, string outputDirectory, MonsterFormat inputFormat, MonsterFormat outputFormat, bool mirrorFolderStructure) + public ConsoleWindow(string inputDirectory, string outputDirectory, string inputFormatName, string outputFormatName, bool mirrorFolderStructure) { this.inputDirectory = inputDirectory; this.outputDirectory = outputDirectory; - this.inputFormat = inputFormat; - this.outputFormat = outputFormat; this.mirrorFolderStructure = mirrorFolderStructure; + PluginHelper plugins = PluginHelper.Instance.Task.Result; + input = plugins.Converters.FirstOrDefault(mc => mc.ConverterName == inputFormatName); + output = plugins.Converters.FirstOrDefault(mc => mc.ConverterName == outputFormatName); + fileProcessor = new MonsterFileProcessor(); } @@ -36,6 +40,16 @@ public bool ValidateValues() Console.WriteLine("DevExpress Directory not specified"); return false; } + else if ((input == null) || (!input.IsReadSupported)) + { + Console.WriteLine("Input format was not specified or invalid"); + return false; + } + else if ((output == null) || (!output.IsWriteSupported)) + { + Console.WriteLine("Output format was not specified or invalid"); + return false; + } else { return true; @@ -45,7 +59,7 @@ public bool ValidateValues() public bool ScanFiles() { Console.WriteLine("Scanning..."); - ScanError result = fileProcessor.ConvertMonsterFiles(inputDirectory, inputFormat, outputDirectory, outputFormat, mirrorFolderStructure); + ScanError result = fileProcessor.ConvertMonsterFiles(inputDirectory, input, outputDirectory, output, mirrorFolderStructure); switch (result) { case ScanError.Success: diff --git a/OTMonsterConverter/Images/info.png b/app/OTMonsterConverter/Images/info.png similarity index 100% rename from OTMonsterConverter/Images/info.png rename to app/OTMonsterConverter/Images/info.png diff --git a/OTMonsterConverter/MainWindow.xaml b/app/OTMonsterConverter/MainWindow.xaml similarity index 85% rename from OTMonsterConverter/MainWindow.xaml rename to app/OTMonsterConverter/MainWindow.xaml index eb476ab0..b77e97e9 100644 --- a/OTMonsterConverter/MainWindow.xaml +++ b/app/OTMonsterConverter/MainWindow.xaml @@ -39,12 +39,7 @@