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 @@
-
-
-
-
-
-
+
@@ -57,12 +52,7 @@
-
-
-
-
-
-
+
diff --git a/OTMonsterConverter/MainWindow.xaml.cs b/app/OTMonsterConverter/MainWindow.xaml.cs
similarity index 81%
rename from OTMonsterConverter/MainWindow.xaml.cs
rename to app/OTMonsterConverter/MainWindow.xaml.cs
index 4a823717..c6a5c520 100644
--- a/OTMonsterConverter/MainWindow.xaml.cs
+++ b/app/OTMonsterConverter/MainWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using MonsterConverterInterface;
+using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
@@ -47,11 +48,20 @@ private void ValidateControls()
{
bool result = false;
- MonsterFormat? inputFormat = GetMonsterFormatFromCombo(comboInputFormat);
- textBoxInputPath.IsEnabled = (inputFormat != MonsterFormat.TibiaWiki);
- buttonInputPath.IsEnabled = (inputFormat != MonsterFormat.TibiaWiki);
+ // Control file selection controls properly
+ if (comboInputFormat.SelectedItem == null)
+ {
+ textBoxInputPath.IsEnabled = true;
+ buttonInputPath.IsEnabled = true;
+ }
+ else
+ {
+ textBoxInputPath.IsEnabled = (((IMonsterConverter)comboInputFormat.SelectedItem).FileSource == FileSource.LocalFiles);
+ buttonInputPath.IsEnabled = (((IMonsterConverter)comboInputFormat.SelectedItem).FileSource == FileSource.LocalFiles);
+ }
- if ((inputFormat != null) && (inputFormat == MonsterFormat.TibiaWiki))
+ // Determine that all finds are set correctly before the convert button is enabled
+ if ((comboInputFormat.SelectedItem != null) && (((IMonsterConverter)comboInputFormat.SelectedItem).FileSource == FileSource.Web))
{
result = ((textBoxOutputPath.Text != "") &&
(comboInputFormat.SelectedItem != null) &&
@@ -70,8 +80,17 @@ private void ValidateControls()
}
}
- private void Window_Loaded(object sender, RoutedEventArgs e)
+ private async void Window_Loaded(object sender, RoutedEventArgs e)
{
+ PluginHelper plugins = await PluginHelper.Instance;
+ foreach (var p in plugins.Converters)
+ {
+ if (p.IsReadSupported)
+ comboInputFormat.Items.Add(p);
+ if (p.IsWriteSupported)
+ comboOutputFormat.Items.Add(p);
+ }
+
ValidateControls();
monsterListDataTable = new DataTable("MonsterList");
monsterListDataTable.Columns.Add("Monster", typeof(string));
@@ -116,8 +135,8 @@ private async void buttonConvert_Click(object sender, RoutedEventArgs e)
string inputDir = textBoxInputPath.Text;
string outputDir = textBoxOutputPath.Text;
- MonsterFormat inputFormat = (MonsterFormat)GetMonsterFormatFromCombo(comboInputFormat);
- MonsterFormat outputFormat = (MonsterFormat)GetMonsterFormatFromCombo(comboOutputFormat);
+ IMonsterConverter inputFormat = (IMonsterConverter)comboInputFormat.SelectedItem;
+ IMonsterConverter outputFormat = (IMonsterConverter)comboOutputFormat.SelectedItem;
ScanError result = ScanError.Success;
await Task.Run(() =>
{
@@ -153,15 +172,6 @@ await Task.Run(() =>
buttonConvert.IsEnabled = true;
}
- private MonsterFormat? GetMonsterFormatFromCombo(ComboBox comboBox)
- {
- if (comboBox.SelectedItem == null)
- return null;
-
- string tag = (string)((Control)(comboBox.SelectedItem)).Tag;
- return (MonsterFormat)int.Parse(tag);
- }
-
private void comboInputFormat_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ValidateControls();
diff --git a/OTMonsterConverter/MonsterFileProcessor.cs b/app/OTMonsterConverter/MonsterFileProcessor.cs
similarity index 57%
rename from OTMonsterConverter/MonsterFileProcessor.cs
rename to app/OTMonsterConverter/MonsterFileProcessor.cs
index 223bb510..9f00b59f 100644
--- a/OTMonsterConverter/MonsterFileProcessor.cs
+++ b/app/OTMonsterConverter/MonsterFileProcessor.cs
@@ -1,7 +1,5 @@
-using OTMonsterConverter.Converter;
-using OTMonsterConverter.MonsterTypes;
-using ScrapySharp.Extensions;
-using ScrapySharp.Network;
+using MonsterConverterInterface;
+using MonsterConverterInterface.MonsterTypes;
using System;
using System.Collections.Generic;
using System.IO;
@@ -22,14 +20,6 @@ public enum ScanError
DirectoriesMatch
}
- public enum MonsterFormat
- {
- PyOT,
- TfsXml,
- TfsRevScriptSys,
- TibiaWiki
- }
-
public sealed class FileProcessorEventArgs : EventArgs
{
public FileProcessorEventArgs(string sourceMonsterFile, string destinationFile, bool convertedSuccessfully = true)
@@ -50,9 +40,9 @@ public class MonsterFileProcessor : EventArgs
public event EventHandler OnMonsterConverted;
// Functions
- public ScanError ConvertMonsterFiles(string monsterDirectory, MonsterFormat inputFormat, string outputDirectory, MonsterFormat outputFormat, bool mirroredFolderStructure = false)
+ public ScanError ConvertMonsterFiles(string monsterDirectory, IMonsterConverter inputConverter, string outputDirectory, IMonsterConverter outputConverter, bool mirroredFolderStructure = false)
{
- if ((inputFormat != MonsterFormat.TibiaWiki) && (!Directory.Exists(monsterDirectory)))
+ if ((inputConverter.FileSource == FileSource.LocalFiles) && (!Directory.Exists(monsterDirectory)))
{
return ScanError.InvalidMonsterDirectory;
}
@@ -69,31 +59,18 @@ public ScanError ConvertMonsterFiles(string monsterDirectory, MonsterFormat inpu
}
}
- if ((inputFormat != MonsterFormat.TibiaWiki) &&
+ if ((inputConverter.FileSource == FileSource.LocalFiles) &&
(Path.GetFullPath(monsterDirectory) == Path.GetFullPath(outputDirectory)))
{
return ScanError.DirectoriesMatch;
}
- var result = FormatToConverter(inputFormat, out IMonsterConverter inputConverter);
- if (result != ScanError.Success)
- return result;
-
- result = FormatToConverter(outputFormat, out IMonsterConverter outputConverter);
- if (result != ScanError.Success)
- return result;
-
- string[] files;
- if (inputFormat == MonsterFormat.TibiaWiki)
+ string[] files = inputConverter.GetFilesForConversion(monsterDirectory);
+ if (inputConverter.FileSource == FileSource.Web)
{
- files = GetWikiMonsters();
// TibiaWiki provides a flat list
mirroredFolderStructure = false;
}
- else
- {
- files = GetLocalFiles(monsterDirectory, inputConverter.FileExtRegEx);
- }
if ((files != null) && (files.Length == 0))
{
return ScanError.NoMonstersFound;
@@ -111,40 +88,6 @@ public ScanError ConvertMonsterFiles(string monsterDirectory, MonsterFormat inpu
return ScanError.Success;
}
- private string[] GetLocalFiles(string directory, string pattern)
- {
- return Directory.GetFiles(directory, pattern, SearchOption.AllDirectories);
- }
-
- private string[] GetWikiMonsters()
- {
- 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();
- }
-
private string FindExactFileDestination(string inputDirectory, string outputDirectory, string file, bool mirroredFolderStructure)
{
if (mirroredFolderStructure)
@@ -161,33 +104,6 @@ private string FindExactFileDestination(string inputDirectory, string outputDire
}
}
- // This is dumb
- private ScanError FormatToConverter(MonsterFormat format, out IMonsterConverter converter)
- {
- if (format == MonsterFormat.TfsXml)
- {
- converter = new TfsXmlConverter();
- }
- else if (format == MonsterFormat.PyOT)
- {
- converter = new PyOtConverter();
- }
- else if (format == MonsterFormat.TfsRevScriptSys)
- {
- converter = new TfsRevScriptSysConverter();
- }
- else if (format == MonsterFormat.TibiaWiki)
- {
- converter = new TibiaWikiConverter();
- }
- else
- {
- converter = null;
- return ScanError.InvalidMonsterFormat;
- }
- return ScanError.Success;
- }
-
private bool ProcessFile(string file, IMonsterConverter input, IMonsterConverter output, string outputDir)
{
bool result = false;
diff --git a/app/OTMonsterConverter/OTMonsterConverter.csproj b/app/OTMonsterConverter/OTMonsterConverter.csproj
new file mode 100644
index 00000000..d4cc1a9d
--- /dev/null
+++ b/app/OTMonsterConverter/OTMonsterConverter.csproj
@@ -0,0 +1,37 @@
+
+
+
+ Exe
+ net5.0-windows
+ true
+ true
+ app.ico
+ Soul4Soul
+ 2.0.0.0
+
+
+
+ ..\..\bin\$(Configuration)
+ false
+
+
+
+ ..\..\bin\$(Configuration)
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/OTMonsterConverter/PluginHelper.cs b/app/OTMonsterConverter/PluginHelper.cs
new file mode 100644
index 00000000..dceb442e
--- /dev/null
+++ b/app/OTMonsterConverter/PluginHelper.cs
@@ -0,0 +1,109 @@
+using Microsoft.VisualStudio.Composition;
+using MonsterConverterInterface;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Reflection;
+using System.Text;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Nito.AsyncEx;
+
+namespace OTMonsterConverter
+{
+ class PluginHelper
+ {
+ private static readonly AsyncLazy instance = new AsyncLazy(CreateAndLoadData);
+ private static readonly object lockobject = new object();
+
+ public IList Converters { get; private set; }
+
+ private PluginHelper()
+ {
+ }
+
+ public static AsyncLazy Instance
+ {
+ get { return instance; }
+ }
+
+ // This method could also be an async lambda passed to the AsyncLazy constructor.
+ private static async Task CreateAndLoadData()
+ {
+ var ret = new PluginHelper();
+ await ret.FindConvertersAsync();
+ return ret;
+ }
+
+ private async Task FindConvertersAsync()
+ {
+ // Build up a catalog of MEF parts
+ var catalog = await CreateProductCatalogAsync();
+
+ // Assemble the parts into a valid graph.
+ var config = CompositionConfiguration.Create(catalog);
+
+ // Prepare an ExportProvider factory based on this graph.
+ var epf = config.CreateExportProviderFactory();
+
+ // Create an export provider, which represents a unique container of values.
+ // You can create as many of these as you want, but typically an app needs just one.
+ var exportProvider = epf.CreateExportProvider();
+
+ // Obtain converts exported from the assemblies in the catalog
+ Converters = exportProvider.GetExportedValues().ToList();
+ }
+
+ ///
+ /// The MEF discovery module to use (which finds both MEFv1 and MEFv2 parts).
+ ///
+ private readonly PartDiscovery discoverer = PartDiscovery.Combine(
+ new AttributedPartDiscovery(Resolver.DefaultInstance, isNonPublicSupported: true),
+ new AttributedPartDiscoveryV1(Resolver.DefaultInstance));
+
+ ///
+ /// Gets the names of assemblies that belong to the application .exe folder.
+ ///
+ /// A list of assembly names.
+ private static IEnumerable GetAssemblyNames()
+ {
+ string directoryToSearch = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
+ foreach (string file in Directory.EnumerateFiles(directoryToSearch, "*.dll"))
+ {
+ string assemblyFullPath = null;
+ try
+ {
+ var assemblyName = AssemblyName.GetAssemblyName(file);
+ if (assemblyName != null)
+ {
+ assemblyFullPath = Path.Combine(directoryToSearch, $"{assemblyName.Name}.dll");
+ }
+ }
+ catch (Exception)
+ {
+ }
+
+ if (assemblyFullPath != null)
+ {
+ yield return assemblyFullPath;
+ }
+ }
+ }
+
+ ///
+ /// Creates a catalog with all the assemblies from the application .exe's directory.
+ ///
+ /// A task whose result is the .
+ private async Task CreateProductCatalogAsync()
+ {
+ var assemblyNames = GetAssemblyNames();
+ var assemblies = assemblyNames.Select(Assembly.LoadFrom);
+ var discoveredParts = await this.discoverer.CreatePartsAsync(assemblies);
+ var catalog = ComposableCatalog.Create(Resolver.DefaultInstance)
+ .AddParts(discoveredParts);
+ return catalog;
+ }
+ }
+}
diff --git a/OTMonsterConverter/Program.cs b/app/OTMonsterConverter/Program.cs
similarity index 88%
rename from OTMonsterConverter/Program.cs
rename to app/OTMonsterConverter/Program.cs
index 5c4d2f5a..98bda0f4 100644
--- a/OTMonsterConverter/Program.cs
+++ b/app/OTMonsterConverter/Program.cs
@@ -1,86 +1,86 @@
-using Mono.Options;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Windows;
-
-namespace OTMonsterConverter
-{
- class Program
- {
- ///
- /// The main entry point for the application.
- ///
- [STAThread]
- static int Main(string[] args)
- {
- bool showHelp = false;
-
- string inputDirectory = "";
- string outputDirectory = "";
- MonsterFormat inputFormat = MonsterFormat.TfsXml;
- MonsterFormat outputFormat = MonsterFormat.TfsRevScriptSys;
- bool mirrorFolderStructure = true;
-
- var p = new OptionSet()
- {
- "Usage: OTMonsterConverter [OPTIONS]+",
- "",
- "Options:",
- { "i|inputDirectory=", "The directory of monster files to parse.", v => inputDirectory = v },
- { "o|outputDirectory=", "The directory of monster files to parse.", v => outputDirectory = v },
- { "inputFormat=", "The starting monster file format.", (MonsterFormat v) => inputFormat = v },
- { "outputFormat=", "The format to converter the monster files to.", (MonsterFormat v) => outputFormat = v },
- { "m|MirrorFolders", "True to mirror the folder structure of the input directory", v => mirrorFolderStructure = v != null },
- { "h|help", "show this message and exit", v => showHelp = v != null },
- };
-
- List extra;
- try
- {
- extra = p.Parse(args);
- }
- catch (OptionException e)
- {
- Console.Write("OTMonsterConverter: ");
- Console.WriteLine(e.Message);
- Console.WriteLine("Try `OTMonsterConverter --help' for more information.");
- return -1;
- }
-
- // Command line arguments detected stay on the CLI
- if (args.Length != 0)
- {
- if (showHelp)
- {
- p.WriteOptionDescriptions(Console.Out);
- return 0 ;
- }
-
- ConsoleWindow consoleWindow = new ConsoleWindow(inputDirectory, outputDirectory, inputFormat, outputFormat, mirrorFolderStructure);
- if (!consoleWindow.ValidateValues())
- {
- return -2;
- }
- if (!consoleWindow.ScanFiles())
- {
- return -3;
- }
- else
- {
- return 0;
- }
- }
- else
- {
- FreeConsole(); // detach console
- Application app = new Application();
- app.Run(new MainWindow());
- return 0;
- }
- }
-
- [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool FreeConsole();
- }
-}
+using Mono.Options;
+using System;
+using System.Collections.Generic;
+using System.Windows;
+
+namespace OTMonsterConverter
+{
+ class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static int Main(string[] args)
+ {
+ bool showHelp = false;
+
+ string inputDirectory = "";
+ string outputDirectory = "";
+ string inputFormat = "";
+ string outputFormat = "";
+ bool mirrorFolderStructure = true;
+
+ var p = new OptionSet()
+ {
+ "Usage: OTMonsterConverter [OPTIONS]+",
+ "",
+ "Options:",
+ { "i|inputDirectory=", "The directory of monster files to parse.", v => inputDirectory = v },
+ { "o|outputDirectory=", "The directory of monster files to parse.", v => outputDirectory = v },
+ { "inputFormat=", "The starting monster file format.", v => inputFormat = v },
+ { "outputFormat=", "The format to converter the monster files to.", v => outputFormat = v },
+ { "m|MirrorFolders", "True to mirror the folder structure of the input directory", v => mirrorFolderStructure = v != null },
+ { "h|help", "show this message and exit", v => showHelp = v != null },
+ };
+ // need new option to list all valid input and output converters that were discovered
+
+ List extra;
+ try
+ {
+ extra = p.Parse(args);
+ }
+ catch (OptionException e)
+ {
+ Console.Write("OTMonsterConverter: ");
+ Console.WriteLine(e.Message);
+ Console.WriteLine("Try `OTMonsterConverter --help' for more information.");
+ return -1;
+ }
+
+ // Command line arguments detected stay on the CLI
+ if (args.Length != 0)
+ {
+ if (showHelp)
+ {
+ p.WriteOptionDescriptions(Console.Out);
+ return 0 ;
+ }
+
+ ConsoleWindow consoleWindow = new ConsoleWindow(inputDirectory, outputDirectory, inputFormat, outputFormat, mirrorFolderStructure);
+ if (!consoleWindow.ValidateValues())
+ {
+ return -2;
+ }
+ if (!consoleWindow.ScanFiles())
+ {
+ return -3;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ FreeConsole(); // detach console
+ Application app = new Application();
+ app.Run(new MainWindow());
+ return 0;
+ }
+ }
+
+ [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool FreeConsole();
+ }
+}
diff --git a/OTMonsterConverter/app.ico b/app/OTMonsterConverter/app.ico
similarity index 100%
rename from OTMonsterConverter/app.ico
rename to app/OTMonsterConverter/app.ico