WCell Addons
From WCell Wiki
Contents |
Introduction
WCell uses Addons to extend customization. These Addons are external libraries and are completely separate from the core itself. They are limited only by your own imagination. Using WCell's powerful API, you can do absolutely anything while keeping the core itself untouched. You can easily declare new quests/npcs or hook up to the base steps of the corresponding server. Addons are event driven. Nearly every major step and procedure triggers an event. Addons can be written in any .NET supported language such as: C#, F#, VB, etc.
Usage
- Both, RealmServer and AuthServer, are capable of loading .NET DLLs (so called Assemblies) at startup and during runtime
- Addons can currently not be un-loaded or re-loaded, after they have been loaded the first time
- All .dll files within the AddonFolder and its sub folders (by default Run/<server>/AddonBin/) are automatically attempted to be loaded when the server starts
- You can specify that you want to exclude certain files or folders by adding them to your Config.xml:
- IgnoredAddonFiles is a string of files and folders to be ignored, seperated by semicolon (;)
- There are two types of Assemblies that can be loaded:
- Actual Addons that have one class that implements IWCellAddon and can have a configuration and whose global variables can be manipulated at runtime
- Library files that are used by actual Addons and cannot be configured or manipulated at runtime
Creating Addons
Setup
This guide shows how to create an addon, step by step. We will be using Visual C# Express Edition as our IDE because it is powerful, free and easy to use for every beginner.
PROTIP: Usually you want to create a new solution for every Addon and add all of WCell's projects that you will use (except for maybe WCell.Constants) to it.
Creating a new project
- Create a new Project
- Choose Class Library
- Name it whatever you want
- Choose to place it in WCell's /Addons folder
- Solution: Create new Solution
- Uncheck Create directory for solution
- Add references
- Add the following WCell projects - WCell.Core,WCell.Constants,WCell.RealmServer,WCell.Util.
- Expand the references block
- Right click on references
- Choose the Projects tab and select WCell.Core, WCell.Constants, WCell.RealmServer, WCell.Util and anything else that you might need/want
- Set Copy Local of all WCell*, NHibernate, ActiveRecord, logging references and all other references that are part of the WCell core, to False!
- Set the Output Path
- Right-click your Addon project in the Solution Explorer and select Properties
- Go to the Build tab
- Set Output Path to: ..\..\Run\<Build Mode>\RealmServerAddons\ - Replacing <Build Mode> with either Debug or Release for the respective configurations
Coding
How to develop a WCell-Addon
- Read up on the WCell API and use the code, the code documentation, the API Articles and the dump files (as described in that article) as reference
- Ask the WCell team for help directly, using IRC: #WCell on irc.quakenet.org
- Look at how existing code customizes WCell in the DefaultAddon:
Implementing IWCellAddon
- You must declare a public class which either implements IWCellAddon or -unless you have a good reason- not to, directly inherits from WCellAddonBase and implements all of WCellAddonBase's abstract members
- Edit the class members correspondingly
NOTE: This can be a a completely standalone class, containing no other code than the implementation of WCellAddonBase members.
Initialization
- Create a new class
- You must have a public static method with the Initialization attribute
- The Initialization attribute declares on which step during Initialization your method will be called. Take a look at InitializationPass to help you choose the correct pass.
- If you want to change Spells, you *must* use the second InitializationPass
- If you want to change NPCs, Quests, Items, GOs, Loot or any other content that is loaded from DB, make sure to add the DependentInitializationAttribute
- Example:
[Initialization(InitializationPass.Second)]
public static void FixConeOfCold()
{
// Cone of cold is missing Range
SpellLineId.MageConeOfCold.Apply(spell =>
{
spell.Range.MaxDist = 10;
});
}
[Initialization]
[DependentInitialization(typeof(GOMgr))]
public static void InitGOs()
{
// do something to GOs
}
[Initialization]
[DependentInitialization(typeof(NPCMgr))]
[DependentInitialization(typeof(ItemMgr))]
public static void InitNPCs()
{
// do something to NPCs and Items
}
NOTE: These methods can be declared in any public Type, as far as it still is a part of the Addon's project and has the aforementioned attribute.
Add content
- See the article Extend WCell for more information.
Addon Configuration
- Addons have been hooked up to the same configuration system both RealmServer and AuthServer are using.
- If you want an Addon with a configuration file, declare UseConfig true in the class which implements WCellAddonBase.
public override bool UseConfig
{
get { return true; }
}
- If you want certain fields or properties to be configurable, declare it public static and the value in your code will be the default value.
- The field or parameter can be string, any enum type, primitive type, or array or IList<T> of such
- An example of 4 nodes: an int, a boolean, a string and an enum:
public static int ReConnectWaitTimer = 5;
public static bool ReJoinOnKick = true;
public static string WCellCmdPrefix = "#";
public static IrcCmdCallingRange IrcCmdCallingRange = IrcCmdCallingRange.LocalChannel;
- Properties can be configurable as well:
public static int SendQueue
{
get { return ThrottledSendQueue.CharsPerSecond; }
set { ThrottledSendQueue.CharsPerSecond = value; }
}
Changing the Configuration during runtime
See Configuration
An Example Addon
using System.Globalization;
using WCell.Core.Addons;
using WCell.RealmServer.Spells;
using WCell.RealmServer.Entities;
using WCell.Constants.Spells;
using WCell.Core.Initialization;
using WCell.RealmServer.Chat;
using WCell.Util.Graphics;
namespace WCell.Addons
{
/// <summary>
/// WCell's own default addon. Contains some useful additions to the WCell RealmServer that should not be part of the Core.
/// </summary>
public class DefaultAddon : WCellAddonBase
{
public const SpellId TeleSpellId = //SpellId.UnusedNPCPORTTEST;
SpellId.UnusedDistractTest;
public override bool UseConfig
{
get { return true; }
}
#region WCellAddon Members
public override string Name
{
get { return "WCell Default Addon"; }
}
public override string ShortName
{
get { return "Default"; }
}
public override string Author
{
get { return "The WCell Team"; }
}
public override string Website
{
get { return "http://wcell.org"; }
}
public override string GetLocalizedName(CultureInfo culture)
{
return "WCell Default Addon";
}
public override void TearDown()
{
// does nothing
}
/// <summary>
/// Add something to the Last Initialization-Step, so that WCell is already fully initialized before this method is called.
/// </summary>
[Initialization(InitializationPass.Last, "Initialize Default Addon")]
public static void Init()
{
// Make some deprecated spell (with an area target) an instant teleport spell:
SpellHandler.Get(TeleSpellId).SpecialCast = delegate(Spell spell, WorldObject caster, WorldObject target, ref Vector3 targetPos)
{
if (caster is Unit)
{
var unitCaster = caster as Unit;
unitCaster.TeleportTo(unitCaster.Region, ref targetPos);
}
};
// add the spell to any newly created staff-Character
Character.Created += chr =>
{
if (chr.Account.Role.IsStaff)
{
chr.Spells.Add(TeleSpellId);
}
};
// let staff members join the staff channel
Character.LoggedIn += (chr, firstConnect) =>
{
if (firstConnect)
{
if (chr.Account.Role.IsStaff && ChatChannel.Staff != null)
{
chr.AddMessage(() => ChatChannel.Staff.TryJoin(chr));
}
}
};
}
#endregion
}
}
Community
- If you want to see more demonstrations of Addons, go to WCell Extended Forum
- Any questions should go to:
- Our IRC channel for instant help: #WCell on irc.quakenet.org
- The Addon Discussion Forum
