We have detected that cookies are not enabled on your browser. Please enable cookies to ensure the proper experience.
Results 1 to 13 of 13
  1. #1
    Join Date
    Jun 2007
    Posts
    305

    Request for step-by-step guide to creating a Hello World plugin for LotRO

    First, I apologize if what I'm looking for already exists and I just didn't find it. Please reply with a link if that's the case!
    ---

    I've got some programming experience and am interested in trying my hand at creating some plugins for LotRO. However, I am finding that the APIs and sample scripts are not sufficient for me to get past the learning curve and start whipping them up. I am wondering if some expert would be willing to make a "for Dummies" type of step-by-step guide to creating a super-simple plugin.

    Here are some things I've found that didn't fit the bill:
    - API documentation specific to LotRO (I don't even know what to incorporate them into!)
    - Sample scripts for LotRO (I don't understand enough about what I'm seeing to know how to modify them!)
    - General LUA tutorials on the web (I don't know how they apply to LotRO)

    Anyway, I realize this would probably be a big pain for somebody, so I don't have any expectations. I also realize that this is the internet, so I'm at least as likely to get ridicule as to get help. Still, I figured if I didn't ask, then I'd never learn!

    Thanks in advance for any assistance.

  2. #2
    Join Date
    Mar 2007
    Posts
    1,780

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    I know exactly what you mean. I found it surprisingly difficult to get started writing plugins due to the limited information. I did start working on a guide a while ago. I'll try and get something written in the next couple of days but no guarantees.
    [B]Elendilmir - [COLOR=#3333ff]Evenwyn[/COLOR][/B] Burglar[B] - [COLOR=#3333ff]Evendale[/COLOR][/B] Guardian
    [FONT=Verdana][COLOR=#ff0000][SIZE=2][B]Combat Analysis[/B] [/SIZE][/COLOR][SIZE=2]([B]v4.2.3b[/B]) - [/SIZE][/FONT]Download "[URL="http://www.lotrointerface.com/downloads/info502-CombatAnalysis.html"]here[/URL]"

  3. #3
    Join Date
    Mar 2007
    Posts
    1,182

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    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
    GETTING STARTED
    __init__.lua FILES
    LOADING A PLUGIN
    HELLO WORLD
    ... 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.

    GETTING STARTED
    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:
    Plugins\
    ____AuthorName\
    ________PluginName\
    ____________Resources

    "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:
    Code:
    <?xml version="1.0"?>
    <Plugin>
     <Information>
      <Name>PluginName</Name>
      <Author>AuthorName</Author>
      <Version>VersionNumber</Version>
     </Information>
     <Package>pathToMainLuaFile</Package>
     <Configuration Apartment="ApartmentName" />
    </Plugin>
    "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.

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

    __init__.lua FILES
    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.

    HELLO WORLD
    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:
    Code:
    <?xml version="1.0"?>
    <Plugin>
     <Information>
      <Name>HelloWorld</Name>
      <Author>YourName</Author>
      <Version>1.00</Version>
     </Information>
     <Package>YourName.HelloWorld.Main</Package>
    </Plugin>
    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.
    Code:
    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)
    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.

    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.
    Last edited by Garan; Oct 25 2011 at 06:39 PM.

  4. #4
    Join Date
    Jun 2007
    Posts
    305

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    Thanks a lot, guys. I appreciate the responses.

    Garan, I'll take a closer look at your post this weekend and see where it takes me.

  5. #5
    Join Date
    Jun 2011
    Location
    Spain
    Posts
    10

    Thumbs up Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    Thank you very much Garan, like Zelxyb, I was looking for something like this...
    [RIGHT][SIZE=1][COLOR=black].[/COLOR][/SIZE]
    [SIZE=3][B][URL="http://comunidadhispania.com"]Comunidad HISPANIA[/URL]
    [/B][/SIZE]

    [/RIGHT]

  6. #6

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    Just like to say thanks for this, I now have my own little skirmish raid tracker - my desk can't cope with another bit of LOTRO related paper
    [SIZE=3][COLOR="#006400"]Wal's Army on Eldar - Walred (Champ), Walbert (Cappy), Walmur (RK), Walori (Guard), Walrandir (LM)[/COLOR][/SIZE]

  7. #7
    Join Date
    Dec 2007
    Posts
    174

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    That's awesome Garan! Thank you!
    [charsig=http://lotrosigs.level3.turbine.com/0920d0000001dd1fe/01003/signature.png]undefined[/charsig]

  8. #8
    Join Date
    Mar 2007
    Posts
    1,182

    Re: Request for step-by-step guide to creating a Hello World plugin for LotRO

    Quote Originally Posted by Jhenox View Post
    That's awesome Garan! Thank you!
    You're welcome. The more complete verson is also available:
    http://forums.lotro.com/showthread.p...gins-for-Noobs

  9. #9
    Join Date
    Jan 2012
    Location
    Orem
    Posts
    873
    how would I make a plugin load my ui settings?

  10. #10
    Join Date
    Mar 2007
    Posts
    1,182
    Quote Originally Posted by Zepherzaper View Post
    how would I make a plugin load my ui settings?
    If you are referring to the UI settings saved by the "/ui save" chat command, it is not exposed to LUA so it can not be automated. The best you can do is assign the Alias, "/ui save", to a quickslot so that a user can click it.

  11. #11
    Join Date
    Jan 2012
    Location
    Orem
    Posts
    873
    Quote Originally Posted by Garan View Post
    If you are referring to the UI settings saved by the "/ui save" chat command, it is not exposed to LUA so it can not be automated. The best you can do is assign the Alias, "/ui save", to a quickslot so that a user can click it.
    actually what you said is false. also I found a way to have a plugin load my ui what I did was moddify the plugin named chatedits color changer/message sender which channels it sends messages to is located in the file named dropdown.lua this is the file that controlls the drop down menu which selects the channel in which your message is sent to like your basic chat channels listed below all are chat commands look at the bold lettering.anyway using that reasoning that they are all commands to send a colored message to a channel you would be using a chat command.
    Chat Channel Access

    These are commands that are entered on the chat line. All commands are prefaced by '/'.

    • advice -- usage: /advice <msg> -- send a message to the Advice channel
    • f -- /f <msg> - send <msg> to your fellowship's chat channel
    • k -- usage: /k <msg> send <msg> to your kinship channel
    • ko -- usage: /ko <msg> - send <msg> to all officers of your kinship
    • lff -- usage: /lff <msg> -- Looking for Fellowship
    • msg -- usage: /tell <target name> <message>
    • o -- usage: /o <msg> - send <msg> to all officers of your kinship
    • officer -- usage: /officer <msg> - send <msg> to all officers of your kinship
    • ooc -- usage: /OOC <msg>
    • r -- usage: /reply message
    • ra -- /ra <msg> - send <msg> to the raid's chat channel
    • regional -- usage: /regional <msg>
    • reply -- usage: /reply message
    • retell -- usage: /retell message
    • rt -- usage: /retell message
    • say -- usage: /say <text>
    • shout -- usage: /shout <text>
    • t -- usage: /tell <target name> <message>
    • tell -- usage: /tell <target name> <message>
    • w -- usage: /tell <target name> <message>
    • whisper -- usage: /tell <target name> <message>


    in the lua plugin the chat channels look like this in code in the plugin chatedit's drop down menu selections located in dropdown.lua

    Before My editing.

    tChatCommands =
    {
    [1] =
    {
    ["Name"] = "Advice";
    ["Comm"] = "/advice";
    ["Length"] = 50;
    };
    [2] =
    {
    ["Name"] = "AFK";
    ["Comm"] = "/afk";
    ["Length"] = 30;
    };
    [3] =
    {
    ["Name"] = "Emote";
    ["Comm"] = "/emote";
    ["Length"] = 48;
    };
    [4] =
    {
    ["Name"] = "Fellowship";
    ["Comm"] = "/f";
    ["Length"] = 72;
    };
    [5] =
    {
    ["Name"] = "Kinship";
    ["Comm"] = "/k";
    ["Length"] = 50;
    };
    [6] =
    {
    ["Name"] = "LFF";
    ["Comm"] = "/lff";
    ["Length"] = 30;
    };
    [7] =
    {
    ["Name"] = "OOC";
    ["Comm"] = "/ooc";
    ["Length"] = 35;
    };
    [8] =
    {
    ["Name"] = "Officer";
    ["Comm"] = "/o";
    ["Length"] = 50;
    };
    [9] =
    {
    ["Name"] = "Raid";
    ["Comm"] = "/ra";
    ["Length"] = 32;
    };
    [10] =
    {
    ["Name"] = "Regional";
    ["Comm"] = "/regional";
    ["Length"] = 59;
    };
    [11] =
    {
    ["Name"] = "Say";
    ["Comm"] = "/say";
    ["Length"] = 30;
    };
    [12] =
    {
    ["Name"] = "Tell";
    ["Comm"] = "/tell";
    ["Length"] = 30;
    };
    [13] =
    {
    ["Name"] = "Trade";
    ["Comm"] = "/trade";
    ["Length"] = 45;
    };
    [14] =
    {
    ["Name"] = "World";
    ["Comm"] = "/wd";
    ["Length"] = 45;
    };
    [15] =
    {
    ["Name"] = "UC1";
    ["Comm"] = "/1";
    ["Length"] = 30;
    };
    [16] =
    {
    ["Name"] = "UC2";
    ["Comm"] = "/2";
    ["Length"] = 30;
    };
    [17] =
    {
    ["Name"] = "UC3";
    ["Comm"] = "/3";
    ["Length"] = 30;
    };
    [18] =
    {
    ["Name"] = "UC4";
    ["Comm"] = "/4";
    ["Length"] = 30;
    };
    };


    local numOfSlots = 17;




    After My Editing
    tChatCommands =
    {
    [1] =
    {
    ["Name"] = "Advice";
    ["Comm"] = "/advice";
    ["Length"] = 50;
    };
    [2] =
    {
    ["Name"] = "AFK";
    ["Comm"] = "/afk";
    ["Length"] = 30;
    };
    [3] =
    {
    ["Name"] = "Emote";
    ["Comm"] = "/emote";
    ["Length"] = 48;
    };
    [4] =
    {
    ["Name"] = "Fellowship";
    ["Comm"] = "/f";
    ["Length"] = 72;
    };
    [5] =
    {
    ["Name"] = "Kinship";
    ["Comm"] = "/k";
    ["Length"] = 50;
    };
    [6] =
    {
    ["Name"] = "LFF";
    ["Comm"] = "/lff";
    ["Length"] = 30;
    };
    [7] =
    {
    ["Name"] = "OOC";
    ["Comm"] = "/ooc";
    ["Length"] = 35;
    };
    [8] =
    {
    ["Name"] = "Officer";
    ["Comm"] = "/o";
    ["Length"] = 50;
    };
    [9] =
    {
    ["Name"] = "Raid";
    ["Comm"] = "/ra";
    ["Length"] = 32;
    };
    [10] =
    {
    ["Name"] = "Regional";
    ["Comm"] = "/regional";
    ["Length"] = 59;
    };
    [11] =
    {
    ["Name"] = "Say";
    ["Comm"] = "/say";
    ["Length"] = 30;
    };
    [12] =
    {
    ["Name"] = "Tell";
    ["Comm"] = "/tell";
    ["Length"] = 30;
    };
    [13] =
    {
    ["Name"] = "Trade";
    ["Comm"] = "/trade";
    ["Length"] = 45;
    };
    [14] =
    {
    ["Name"] = "World";
    ["Comm"] = "/wd";
    ["Length"] = 45;
    };
    [15] =
    {
    ["Name"] = "UC1";
    ["Comm"] = "/1";
    ["Length"] = 30;
    };
    [16] =
    {
    ["Name"] = "UC2";
    ["Comm"] = "/2";
    ["Length"] = 30;
    };
    [17] =
    {
    ["Name"] = "UC3";
    ["Comm"] = "/3";
    ["Length"] = 30;
    };
    [18] =
    {
    ["Name"] = "UC4";
    ["Comm"] = "/4";
    ["Length"] = 30;
    };
    [19] =
    {
    ["Name"] = "UI Save";
    ["Comm"] = "/ui layout save";
    ["Length"] = 50;
    };
    [20] =
    {
    ["Name"] = "UI Load";
    ["Comm"] = "/ui layout load";
    ["Length"] = 50;
    };
    };


    local numOfSlots = 20;


    you will notice that it was 17 slots before my edit I cerrected a error in the original coding disabling which was hiding the user chat channel 4 from the menu.
    so I not only found a way to solve my problem I found a error in the origanal code. anyway if you copy the new code and replace the old code in the dropdown.lua file you will be able to save your ui settings with your chatedit plugin.

    also I want ya to know that I almost know nothing about lua script I am just able to spot what changes in a program that need changed to fix a problem.
    Last edited by Zepherzaper; Dec 30 2014 at 01:35 AM.

  12. #12
    Join Date
    Mar 2007
    Posts
    1,182
    Quote Originally Posted by Zepherzaper View Post
    actually what you said is false.
    Actually, what I said was true, the only solution is to assign the /ui command as an Alias to a quickslot which is exactly what chat edit does. I believe you got confused by my statement that the process can not be automated (performed without user intervention) but that the best you could do is create an additional quickslot which the user has to press. Neither part of my original response was false. I'm glad to hear that you found a way to create an Alias and assign it to a quickslot even if you don't realize that is exactly what you did. I did notice that the syntax in my original response was incorrect, the /ui command to save the layout is "/ui layout [ save | load ]" (lotro-wiki left out the "layout"), and my answer should have said to use "/ui layout load" to load the layout but I don't believe that is what you were referring to as false.

    FWIW, additional information on how to implement a quickslot and even make the quickslot look more like a button is covered in the thread:
    https://www.lotro.com/en/forums/show...gins-for-Noobs

    P.S. in your post, the original value for numOfSlots was 17 with 18 slots defined which implies that either the original plugin had a typo or numOfSlots is the upper bound of a 0 based array of controls. If it is a 0 based array, you probably should assign numOfSlots to 19, not 20 as the plugin might generate errors attempting to build a control for a nil value.
    Last edited by Garan; Dec 30 2014 at 07:53 AM.

  13. #13
    Join Date
    Jan 2012
    Location
    Orem
    Posts
    873
    Quote Originally Posted by Garan View Post
    Actually, what I said was true, the only solution is to assign the /ui command as an Alias to a quickslot which is exactly what chat edit does. I believe you got confused by my statement that the process can not be automated (performed without user intervention) but that the best you could do is create an additional quickslot which the user has to press. Neither part of my original response was false. I'm glad to hear that you found a way to create an Alias and assign it to a quickslot even if you don't realize that is exactly what you did. I did notice that the syntax in my original response was incorrect, the /ui command to save the layout is "/ui layout [ save | load ]" (lotro-wiki left out the "layout"), and my answer should have said to use "/ui layout load" to load the layout but I don't believe that is what you were referring to as false.

    FWIW, additional information on how to implement a quickslot and even make the quickslot look more like a button is covered in the thread:
    https://www.lotro.com/en/forums/show...gins-for-Noobs

    P.S. in your post, the original value for numOfSlots was 17 with 18 slots defined which implies that either the original plugin had a typo or numOfSlots is the upper bound of a 0 based array of controls. If it is a 0 based array, you probably should assign numOfSlots to 19, not 20 as the plugin might generate errors attempting to build a control for a nil value.
    it was a typo in the original text which I fixed with my changes.

    I see what your saying it is not though if it was listed from 0-17 then user chat 4 would of been showing up before I made the changes yet it did not. the latest release actually has the code fixed to have 18 slots. I looked at the script because of curiosity.

    I figured it was based 1-# because the first number in the list is 1 not 0 anyway. I might be wrong I don't think I am though. anyway I hope my editing helped someone.

 

 

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

This form's session has expired. You need to reload the page.

Reload