I've been slowly working on a tutorial guide. Here's a rough draft of the first part, up to "Hello World" (bear in mind, in it's finished form it would be displayed with html links and formatting and there's a lot of editting yet to be done). There's a whole lot more that digs into the API, Event Handling, Saving and Loading data, Internationalization, etc. but it won't be ready for a while yet. I was just working on the section dealing with my favorite undocumented methods SetStretchMode and SetRotation last night.
LoTRO Lua Plugins for Noobs
Table of Contents
BEFORE YOU BEGIN
LOADING A PLUGIN
... lots of stuff edited out because it's not even close to being ready for publication...
BEFORE YOU BEGIN
The tools you will need are fairly simple. First, you will need a language reference. I personally use http://www.lua.org/manual/5.1/ which is fairly easy to understand and navigate.
Second, you will want the Turbine API documentation. As of the time this guide was written, the lastest API docs were published on the LoTROInterface.com website at http://www.lotrointerface.com/downlo...mentation.html
You will need an editor, a simple text editor like Notepad will suffice but some users prefer syntax highlighting editors or project managers to organize their files (I generally just use Notepad).
If you plan on using any custom graphics, you will want an image editor that can generate .jpg and/or .tga files as these are the only file formats that LoTRO Lua will display.
The last thing you might want are some sample plugins to dissect and play around with. Turbine published a package of sample files which can be downloaded in a 7zip archive from http://content.turbine.com/sites/lot..._LuaPlugins.7z You may also want to check out LoTROInterface.com or other plugin sources. One of the best ways to learn is to dig in, twist, pull, yank and turn and see what happens
One rule to bear in mind, most things dealing with Lua are case sensitive so if you keep getting a nil value or an error that a function doesn't exist or any other mysterious error, always double check that you have the correct case.
Every plugin has at least two elements, a .plugin definition file and one or more .lua code files. The .plugin file must be in a subfolder of the "My Documents\The Lord of the Rings\Plugins" folder (there are slight variations on the path to My Documents based on operating system versions). The most common accepted standard for folder structure is:
"AuthorName" is a distinct folder used to group all plugins written by an author. The "AuthorName" folder usually contains only .plugin definition files.
Each plugin then generally has a subfolder with a name based on the plugin. The "PluginName" folder generally contains all of the .lua code files for a plugin unless the plugin uses files from a shared library. The major benefit of using a shared library for common classes is that code can be maintained in one location. The major drawback of using a shared library is that any changes to the shared code can potentially cause undesirable effects in plugins. I generally prefer to keep a separate copy of all .lua files in each plugin folder so that I will not run into compatability issues (a distant cousin of that old plague called "DLL Hell") if someone wants to only update one of several plugins that might use a common class file.
The Resources folder is just a convention that got adopted from the Turbine samples. This folder is used to hold any .jpg or .tga files that the plugin uses.
The .plugin file is an xml file with the structure:
"PluginName" is the name used to load the plugin with the "/plugins load PluginName" as well as how it will appear in game in the "/plugins list" and "/plugins refresh" commands. If you use a plugin manager (a plugin that controls loading other plugins) this is also the name that will be listed in the manager.
<Configuration Apartment="ApartmentName" />
"AuthorName" is the name of the plugin author and is only included for documentary/organizational purposes. This has no actual impact on the functioning of the plugin but can be access programatially using the Plugins table.
"VersionNumber" is the version that will be displayed in the "/plugins list", "/plugins refresh" and plugin manager lists. This value can also be used programatically for tagging saved data and automatically processing data updates.
The "pathToMainLuaFile" value is the path relative to the Plugins folder to the main Lua code file. Note that the path uses "." as a folder separator instead of "\" or "/". This is usually the first file that will be loaded, parsed and processed. However, it is possible to supercede the processing of this file by including a "__init__.lua" file in the same folder as this file.
The Configuration setting is optional and will allow a plugin to run in it's own Apartment or address space, meaning that it will get it's own copy of all Turbine objects and global environment. The most common reasons for including a Configuration setting are to allow a plugin to be unloaded without affecting other plugins or to prevent other plugins from interfering with global values and event handlers. If your plugin does not need to be unloaded and if it uses safe event handlers (discussed later) then you probably do not need a separate apartment. Note that using a separate apartment will significantly increase the amount of memory used by the Lua system since multiple copies of the environment and global object must be created for each apartment.
Before processing any files in a folder, the Lua system will look for an optional __init__.lua file and if one is found it will be processed first. The __init__.lua file is used to "import" or include code from multiple files in the same folder. This eliminates the need to put separate "import" statements in the other .lua files as all files in the __init__.lua file will be automatically imported. It is important to note that the files will be processed in the order in which they are imported in the __init__.lua file so if any file depends on an object or function defined in another file the dependant file must be loaded after the one that defines the object or function. The __init__.lua file will be processed before the main Lua file in the Package setting of the .plugin file. The __init__.lua file should only import files that are in it's own folder. Each folder may have it's own __init__.lua file.
LOADING A PLUGIN
When a user executes the "/plugins load PluginName" command, the .plugin file with a Name setting matching PluginName will be processed. If the .plugin file contains a Configuration setting with a distinct Apartment name a new global environment is created, otherwise the default global environment is used. The Lua system looks in the folder containing the file pointed to by the Package setting for a __init__.lua file and if one is found it is processed. Once the __init__.lua file is processed, the file in the Package setting is loaded, parsed and executed. Since Lua is a scripting language, each line is processed in sequence. The parser will continue reading the file until it reaches the end of an executable statement at which point that statement is executed. A semi-colon can be used to terminate a statement but is not required. If the parser detects an error prior to completing processing the main file an error message will be generated and the plugin will not complete loading. Code within functions is compiled but variables and external references are not evaluated until the function is called so it is possible for an error to manifest well after the plugin is loaded and running.
At this point, you are probably ready for your first plugin. Tradition demands that we start with a simple Hello World plugin. The first thing to do is create a .plugin file, we shall call this one, HelloWorld.plugin and it should be saved in the MyDocuments\The Lord of the Rings\Plugins\YourName folder:
Note that there is no Configuration tags as this example hardly requires the need to be unloaded separately nor does it need to load or save data in real time and has no event handlers for shared objects.
The next step is to create the Main.lua file which should be saved in the MyDocuments\The Lord of the Rings\Plugins\YourName\HelloWo rld folder.
After creating the files, load the game and type "/plugins list". If you created the files in the correct location, you will see an entry for HelloWorld (1.00) in the list. This is a good first check to be sure that the files are in the correct location. If they are not, be sure to double check the path you are using is your documents folder, NOT the Program Files folder where the LoTRO programs are installed.
import "Turbine.UI"; -- this will expose the label control that we will implement
import "Turbine.UI.Lotro"; -- this will expose the standard window that we will implement
HelloWindow=Turbine.UI.Lotro.Window(); -- we call the constructor of the standard window object to create an instance
HelloWindow:SetSize(200,200); -- sets the window size to 200 by 200 pixels
HelloWindow:SetPosition(Turbine.UI.Display:GetWidth()/2-100,Turbine.UI.Display:GetHeight()/2-100); -- centers the window in the display
HelloWindow:SetText("Hello World Window"); -- assigns the title bar text
HelloWindow.Message=Turbine.UI.Label(); -- create a label control to display our message
HelloWindow.Message:SetParent(HelloWindow); -- sets the label as a child of the main window
HelloWindow.Message:SetSize(180,20); -- sets the message size
HelloWindow.Message:SetPosition(10,90); -- places the message control in the vertical middle of the window with a 10 pixel left and right border
HelloWindow.Message:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter); -- centers the text in the message control both horizontally and vertically
HelloWindow.Message:SetText("Hello World"); -- sets the actual message text
HelloWindow:SetVisible(true); -- display the window (windows are not visible by default)
Once you have verified that the plugin is in the list, enter "/plugins load HelloWorld". Note that while most things in Lua are case sensitive, the name of the plugin in the command is not. If you created the files correctly, you will be rewarded with a simple window displayed in the center of your display with the title, "Hello World", a border, a close button and most importantly the message "Hello World" in the middle of the window.