Skip to content

Code documentation

Bartosz Korczyński edited this page Jul 20, 2022 · 7 revisions

This page contains various basic information about the code structure and how things are designed here.

-- WIP --

General

MVVM and ViewModel first approach

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.

Modules

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. image

Registering Views by convention

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)

Common interfaces

This chapter briefly describes the common interfaces used to implement editing features.

WDE.Common.Windows.ITool

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.

image

Note: please don't confuse the interface with Dock.Model.Controls.ITool which is also defined in the solution.

WDE.Common.Managers.IDocument

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.

WDE.Common.ISolutionItem

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.

image

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).

Related interfaces

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 method string GetName(T item) to provide a name for a solution item (must have).
  • ISolutionItemSqlProvider<T> - implement this interface and method Task<IQuery> GenerateSql(T item) to provide a method that generates a query for this item (must have).
  • ISolutionItemIconProvider<T> - implement this interface and method ImageUri 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> and ISolutionItemDeserializer<T> - implement this interfaces as an alternative method of serializing and deserializing solution items (must have). Note: Type field in ISmartScriptProjectItem 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 method IDocument GetEditor(T item) to construct a view model (which implements IDocument) for this solution item
  • ISolutionItemRemoteCommandProvider<T> - implement this interface and method IRemoteCommand[] 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 method Task<RelatedSolutionItem?> GetRelated(T item) to provide information what 'related' things can be opened (icons in the top right corner) (optional)
image
  • ISolutionItemDocument - this is an extension of IDocument interface, it additionally contains ISolutionItem SolutionItem { get; } property and Task<IQuery> GenerateQuery(). All the 'document editors' view models should implement this interface. _todo: I guess ISolutionItemEditorProvider<T> should return ISolutionItemDocument instead of IDocument then.

ISolutionItemProvider

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.

image

(Quick load and File -> New/Open are added dynamically based on ISolutionItemProvider implementations).

Brief recap:

image

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.