-
Notifications
You must be signed in to change notification settings - Fork 157
Code documentation
This page contains various basic information about the code structure and how things are designed here.
-- WIP --
The editor uses MVVM (Model-view-view model) pattern, in particular it uses View Model first
(instead of View first
) approach. Explaining MVVM is out of this wiki scope, if you want to read more about it, just google for MVVM
, e.g. https://docs.avaloniaui.net/guides/basics/mvvm .
Regarding the 'View Model first' approach - it means everywhere in the code we are referring to the view model. And the view
is created automatically underneath. E.g. if you want to display a new dialog window, you should create a View Model for the window and the view will be created automatically. In the other approach (View first) you would create a view instance first and the view model would be created automatically. This however couples your UI framework, meanwhile, view models in WoW Database Editor are view agnostic. In the past there were two versions - one using WPF, the other one using Avalonia, both reusing the same Models and View Models, while only views were different.
Wow Database Editor is built in a modular way, that means projects are de-coupled from each other and they don't know about other projects whenever possible. It is even possible to load an external .dll as a plugin (even though it is not used now). Things are resolved dynamically, usually using shared interfaces, defined in the project WDE.Common
.
The core project (sometimes referred as a "shell") doesn't even know what particular things can be edited, all the editors like 'Creature script', 'WoW Sniff', 'Creature texts' are resolved dynamically, all the tool windows like 'Tables', 'Sessions', 'History' are resolved dynamically.
By default, when you are about to display some View Model, View is resolved automatically by name convention - ViewModel
in class full name is replaced with View
. E.g. if you have class WDE.SmartScriptEditor.ViewModels.EditorViewModel
, the editor will try to instantiate class WDE.SmartScriptEditor.Views.EditorView
as a view.
Alternatively, you can manually assign a view to your viewmodel, in the method public override void RegisterViews(IViewLocator viewLocator)
in your module class (class that extends ModuleBase
)
This chapter briefly describes the common interfaces used to implement editing features.
Implement this interface, to add a new tool window, like 'Tables', 'Sessions', 'History'. Once you add a class that implements this interface, the editor will automatically find it and add it to 'Views' menu, so that the user is able to open it.
Note: please don't confuse the interface with Dock.Model.Controls.ITool
which is also defined in the solution.
The most important and basic interface representing a basic document that can be opened in the editor. It contains basic data like Title, Icon of the document, Cut, Paste, Copy commands implementation for this document. It doesn't have to be wow-related, it doesn't have to be save-able. I.e. "Quick start" is a document, "Settings" is a document. But also each editor (smart script editor, table editor) is a document.
Note: please don't confuse the interface with Dock.Model.Controls.IDocument
which is also defined in the solution.
This is the most basic interface, the most basic unit that represents an editable thing, that represents a thing that can be opened
, edited
, saved
, a thing that can be stored in a solution
or in a session
.
The Solution Explorer tool contains ISolutionItems
. E.g. a folder is implemented by WDE.Solutions.SolutionFolderItem
class, smart scripts are implemented by WDE.SmartScriptEditor.SmartScriptSolutionItem
class, table editors are implemented by WDE.DatabaseEditors.Solution.DatabaseTableSolutionItem
class.
Those ISolutionItem
are serialized automatically by Newtonsoft.Json library, so if there is something you don't want to be serialized, you might need to use additional attributes on fields/properties, e.g. look at SmartScriptSolutionItem
class ([JsonIgnore]
attributes) or DatabaseTableSolutionItem
class ([JsonProperty]
attributes).
There is a series of ISolutionItem related interfaces that provide additional data regarding the solution item, e.g. name or icon.
note: T there will be your particular ISolutionItem implementation
-
ISolutionNameProvider<T>
- implement this interface and methodstring GetName(T item)
to provide a name for a solution item (must have). -
ISolutionItemSqlProvider<T>
- implement this interface and methodTask<IQuery> GenerateSql(T item)
to provide a method that generates a query for this item (must have). -
ISolutionItemIconProvider<T>
- implement this interface and methodImageUri GetIcon(T item)
to provide an icon for a solution item. E.g. icons in the solution explorer tool are resolved using this interface (pretty much must have). -
ISolutionItemSerializer<T>
andISolutionItemDeserializer<T>
- implement this interfaces as an alternative method of serializing and deserializing solution items (must have). Note:Type
field inISmartScriptProjectItem
must be unique per solution item and also is now an arbitrary number, which is not the best design decision (considering we support modularity). -
ISolutionItemEditorProvider<T>
- implement this interface and methodIDocument GetEditor(T item)
to construct a view model (which implementsIDocument
) for this solution item -
ISolutionItemRemoteCommandProvider<T>
- implement this interface and methodIRemoteCommand[] GenerateCommand(T item)
to generate a series of server commands that will be remotely executed to reload this solution item. E.g. editing creature_template of entry X, can return.reload creature_template X
command (optional) -
ISolutionItemRelatedProvider<T>
- implement this interface and methodTask<RelatedSolutionItem?> GetRelated(T item)
to provide information what 'related' things can be opened (icons in the top right corner) (optional)
-
ISolutionItemDocument
- this is an extension ofIDocument
interface, it additionally containsISolutionItem SolutionItem { get; }
property andTask<IQuery> GenerateQuery()
. All the 'document editors' view models should implement this interface. _todo: I guessISolutionItemEditorProvider<T>
should returnISolutionItemDocument
instead ofIDocument
then.
Implement this interface, to provide a "factory" class for your T : ISolutionItem
. It contains a "name", "description" and "icon" of the thing that can be created using this interface. It has a method Task<ISolutionItem?> CreateSolutionItem()
used to create a new solution item. This method returns a Task
, which means you can open additional async windows, e.g. open a window to pick a creature entry, which later will be used to construct your ISolutionItem
instance.
In this interface you can also decide whether your particular ISolutionItem
makes sense with currently selected ICoreVersion
(= emulator version/type). E.g. Smart Scripts are not supported by (c)mangos, they are supported by Trinity based emulators tho. Therefore a provider for SmartScriptSolutionItem
can decide whether the current core version is Trinity or Mangos and allow creating this type of solution item or not.
(Quick load
and File -> New/Open
are added dynamically based on ISolutionItemProvider
implementations).
To sum this up, the fact that Creature Script
is visible in the Quick Load panel means, there is some ISolutionItemProvider
implementation for this.
When I click on the creature script
button, it will execute ISolutionItemProvider::CreateSolutionItem()
method, which will create a new ISolutionItem
. In case of SAI Creature Script, it will create a new SmartScriptSolutionItem
instance with chosen "entryorguid" and SmartScriptType.Creature
enum as type.
Once the SmartScriptSolutionItem
is created, in order to display an editor for this item, a document-editor needs to be created. This means
the editor will look up for a class that implements ISolutionItemEditorProvider<SmartScriptSolutionItem>
and it will invoke GetEditor()
method, in case of SAI, check the WDE.TrinitySmartScriptEditor.Providers.SmartScriptEditorProvider
class.