Plug-in scripting tutorial: Difference between revisions
(12 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
==Introduction== | ==Introduction== | ||
Line 9: | Line 7: | ||
Hopefully, this approach will allow beginners to progress with careful study, but at the same time will not bore experienced programmers to tears. | Hopefully, this approach will allow beginners to progress with careful study, but at the same time will not bore experienced programmers to tears. | ||
''' | '''Vendetta and the Lua Scripting Language''' | ||
Many games today allow player created plug-ins and mods. Most games do this in the same basic way. First the core of the game (both server and client code) is written in a language such as C or C++, which is very efficient but takes a lot of experience and care to avoid subtle mistakes. The language is chosen to achieve the best possible performance at the cost of slower development time or more complicated code. | Many games today allow player created plug-ins and mods. Most games do this in the same basic way. First the core of the game (both server and client code) is written in a language such as C or C++, which is very efficient but takes a lot of experience and care to avoid subtle mistakes. The language is chosen to achieve the best possible performance at the cost of slower development time or more complicated code. | ||
Line 130: | Line 128: | ||
The output should display in your message window. | The output should display in your message window. | ||
== | == The Basic Building Blocks of Plug-ins == | ||
'''Creating a namespace for your work''' | '''Creating a namespace for your work''' | ||
Line 254: | Line 252: | ||
</source> | </source> | ||
== | '''Example Plug-in: MyPlugIn''' | ||
This is a small example that shows one way to set up class-like function calls and member variables. | |||
<source lang="lua"> | |||
-- An example showing one approach to setting up function calls and "class" | |||
-- variables. | |||
local MyPlugIn = {}; | |||
function MyPlugIn:init() | |||
-- set up some "class" variables. | |||
self.message_three_text = "my_plugin: message three."; | |||
end | |||
function MyPlugIn:print_msg_one() | |||
-- demonstrate that functions work... | |||
print("my_plugin: message one."); | |||
end | |||
function MyPlugIn:print_msg_two() | |||
-- demonstrate that functions work... | |||
print("my_plugin: message two."); | |||
end | |||
function MyPlugIn:print_msg_three() | |||
-- demonstrate that functions work... | |||
print(self.message_three_text); | |||
end | |||
function MyPlugIn:command_console() | |||
self:init(); | |||
self:print_msg_one(); | |||
self:print_msg_two(); | |||
self:print_msg_three(); | |||
end | |||
RegisterUserCommand("my_plugin", MyPlugIn.command_console, MyPlugIn); | |||
</source> | |||
==Summary== | |||
This tutorial was written by a beginner with other beginners in mind. I hope this tutorial has given you a quick and relatively painless introduction to Vendetta Plug-in scripting. If you have feedback, feel free to post it on the discussion page. | |||
I look forward to using your plug-ins in the game. | |||
: [[User:Rubin427|Rubin427]] 16:53, 19 June 2009 (UTC) | |||
==Appendix A: Links and Resources== | |||
<ul> | <ul> |
Latest revision as of 16:53, 19 June 2009
Introduction
This tutorial is designed for anyone new to writing Vendetta plug-ins that wants to jump in and get started. The format of the tutorial will be to introduce a couple of new ideas and then use those ideas in an example creating a small plug-in for the purposes of demonstration.
Hopefully, this approach will allow beginners to progress with careful study, but at the same time will not bore experienced programmers to tears.
Vendetta and the Lua Scripting Language
Many games today allow player created plug-ins and mods. Most games do this in the same basic way. First the core of the game (both server and client code) is written in a language such as C or C++, which is very efficient but takes a lot of experience and care to avoid subtle mistakes. The language is chosen to achieve the best possible performance at the cost of slower development time or more complicated code.
Then, to allow programmers to build upon this core rapidly, a second programming language is used. This second language is known as a scripting language. The principle benefit of a scripting language is that scripts are isolated from many low level, complex, details of the game core. This allow code written in scripts to be comparatively simple and easy to read (once you get the hang of it). As a result, development times using scripts can be very fast. As an added bonus, anyone, whether they are a member of the game development team, or regular a player, can use the scripting language to build upon the core game in creative new ways.
In Vendetta, that scripting language is Lua. All of the Vendetta Plug-in code you write will be written in Lua. Lua is a widely used language with free documentation and interpreters available on-line. So, the time you spend learning Lua while writing Vendetta plug-ins is a good investment, because you are free install Lua on your machine at any time and use the language however you see fit.
This tutorial will not spend much time covering the features of Lua itself, but will focus on using Lua in combination with Vendetta plug-ins. If you are new to Lua, you may benefit from spending an hour or two with some of the excellent Lua tutorials available on-line.
Getting Started with the Command Console
Getting started with Lua scripting in Vendetta is so easy, you don't even have to leave the game. That is because Lua is available to us via the in game command console.
First we'll open the command console. The default method of opening the command console is with the ` key (left of the '1' key). The command console can also be opened by typing /ConsoleToggle into any chat channel.
Then, we can access the Lua scripting language by starting the line with the command /lua. The output form Lua commands will appear in your message window. Let's do a couple of examples to get started.
<source lang="text"> /lua print("hello."); </source>
One of the handy features you can start using right away is Lua's built in support for basic arithmetic. Suppose the station I'm docked at sells Synthetic Hydrocarbons at a price of 27c each. If I want to know the price for buying 117 Synthetic Hydrocarbons, the total cost can be quickly calculated in Lua.
<source lang="text"> /lua print(27 * 117); </source>
The answer: 3159
For our last example of Lua in the Command Console, we'll use an API call to find out something about the state of the game. We'll get the id of the active chat channel.
<source lang="text"> /lua print(GetActiveChatChannel()); </source>
As you can see, lua script executed via the command console run immediately when you press ENTER. However, if you want to run the same command again in the future, you must retype it completely. As your scripts become more complex, you'll need to store the scripts in files so they can be executed again and again with minimal typing.
We do this by creating a plug-in, which is the topic of the next section.
"Hello, World!" Vendetta Plug-in
In this section we are going to get all the busy work of making a new plug-in out of the way. We'll cover where to put your files and how to load your plug-in without restarting the game. But we won't be too focused on what is actually going on in the code. For now, copy and paste to make it work. Later on we'll discuss the details of the code.
Let's get started.
Where to put your code:
In order for Vendetta to find your plug-in, it must be located in the correct place on your system. Our plug-in code will always be in a file named "main.lua". However the directory that main.lua belongs in is different for each of the three major operating systems supported by Vendetta, so we'll cover each in turn.
In general plug-ins reside in directory called 'plugins', and each plug-in needs to have it's own directory there.
VO tries to load a main.lua file from each directory inside plugins. What differes between OSes is where plugins directory is located.
The instructions here are brief, so if you need additional information see slime73's post on this topic in the forums[3]
Linux
In linux, each user has a hidden folder called .vendetta in his or her home directory. This directory contains customized settings, as well as all plug-ins.
first we'll make a directory for the HelloWorld plug-in:
<source lang="text"> mkdir -p ~/.vendetta/plugins/HelloWorld </source>
then well create the main.lua file.
<source lang="text"> touch ~/.vendetta/plugins/HelloWorld/main.lua </source>
Edit the file using your favorite text editor, such as vim.
Mac OSX
Right click(or command-click?) Vendetta package and click 'Select package contents'.
Create plugins directory there and then a directory for your plugin.
Windows
Plug-ins directory will need to be created in directory you installed VO to.
Usually it's c:\Program Files\Vendetta Online\
Create plugins directory there.
Hello, World! script
The code for the HelloWorld plug-in is as basic as possible. It prints the message "Hello, World!" to the message window when called from the command console by the user.
<source lang="lua"> declare('HelloWorld', HelloWorld or {})
function HelloWorld.cmd(_,data)
print ("Hello, World!");
end
RegisterUserCommand("say_hi",HelloWorld.cmd); </source>
running the script
To reload all plug-ins without restarting Vendetta, you can use the following command: <source lang="text"> /lua ReloadInterface() </source>
Finally, to run the code, we execute the command we created in this plug-in: <source lang="text"> /say_hi </source>
The output should display in your message window.
The Basic Building Blocks of Plug-ins
Creating a namespace for your work
When writing a plug-in, we want to begin by working in an area that is all our own. We do not want to run the risk of getting function names or variable names mixed up with the resources of another plug-in.
To do this, we declare a namespace (technically, a table) with the same name as our plug-in and carefully keep all of our work inside that area.
<source lang="lua">
declare('MyPlugIn', MyPlugIn or {})
</source>
This namespace does much more than just protect us from name collisions, but additional features won't be covered just yet. Instead you'll learn more about it as you gain experience writing your own plug-ins.
Unterstanding Entry Points
'Entry point' is a term used to describe when and where your code will start running from. For example, in C, the most common entry point is the first line of code in the function 'main()'. In a Vendetta plug-in, there is no single common entry point. So, we are free to chose between a few possible entry points based on which best fit our needs. Also, we can use any number of entry points in combination with each other.
- Entry Point: Command Console The most basic entry point is to interact with the user via command console. The steps to do this are: In our plug-in's code: 1) declare a function. <source lang="lua"> function MyPlugIn.cmd(_,data) --code goes here. end </source> 2) Register the function with the vendetta command console. <source lang="lua"> RegisterUserCommand('myplugin', MyPlugIn.cmd) </source> The user : 3) The user calls the function via command console by running the newly created command. <source lang="text"> /myplugin </source>
- Entry Point: Events Another entry point available to us is to respond to events. Events inform us of what is going on in the game. There are a large number of events available to us, some examples include: getting hit in combat, docking with a station, joining a group, receiving a new inventory item, and so on. Our plug-in will not receive any events until we specify which, if any, we are interested in. There is more than one way to register for events, but for now, we'll just cover the steps for creating an OnEvent function (The other methods are covered here[4]). The steps are as follows: In our plug-in's code: 1) Add an 'OnEvent' function to your plug-in. <source lang="lua"> function MyPlugIn:OnEvent(event, data) --code goes here. end </source> It's important to note, the function name must be exactly OnEvent, the name is case sensitive. 2) Register to recieve the events you are interested in. <source lang="lua"> RegisterEvent(MyPlugIn, "GROUP_MEMBER_DIED") </source> Your Plug-in can register for as many events as you are interested in. The User: 3) Later, during normal game play, every time an event that your plug-in registered for happens, the code in your OnEvent function will be run. In the example from step two above, our code would run every time a group member died. If your plug in needs to stop processing events you've registered for, it can unregister for the event to save processing time, as follows: <source lang="lua"> UnregisterEvent(MyPlugIn, "GROUP_MEMBER_DIED") </source>
- Entry Point: Custom GUI Custom GUI creation is beyond the scope of this tutorial, but keep in mind this is an option available to you using the Vendetta API.
Understanding entry points is important because it will help you plan the design of your code. It will also help you understand other people's plug-in code if you start by analyzing the entry points to determine: 1) what causes their code to run, and 2) what their code does each time it runs.
Vendetta Lua API calls
The final basic building block of Vendetta plug-ins is API calls[5]. Unlike events, that let us know when something is happening, api calls can be used at any time to find out the current status of our character, or another aspect of the game.
Browsing through the API is a great way to get ideas about what is possible in a plug-in or to discover new ways to do things.
Example Plug-in: StationReminder
This is a small example that shows the use of events together with calls to the Vendetta Lua API:
<source lang="lua"> -- StationReminder -- -- A plug-in that prints the sector of any station we leave to the message box.
declare("StationReminder", StationReminder or {})
function StationReminder:OnEvent(event, data)
-- This function triggers when we receive a LEAVING_STATION event. -- It prints the sector name every time we leave a station in case we -- need to look it up. print("Leaving station " .. AbbrLocationStr(GetCurrentSectorid()));
end
-- register to recieve the LEAVING_STATION event. RegisterEvent(StationReminder, "LEAVING_STATION") </source>
Example Plug-in: MyPlugIn
This is a small example that shows one way to set up class-like function calls and member variables.
<source lang="lua"> -- An example showing one approach to setting up function calls and "class" -- variables.
local MyPlugIn = {};
function MyPlugIn:init()
-- set up some "class" variables. self.message_three_text = "my_plugin: message three.";
end
function MyPlugIn:print_msg_one()
-- demonstrate that functions work... print("my_plugin: message one.");
end
function MyPlugIn:print_msg_two()
-- demonstrate that functions work... print("my_plugin: message two.");
end
function MyPlugIn:print_msg_three()
-- demonstrate that functions work... print(self.message_three_text);
end
function MyPlugIn:command_console()
self:init(); self:print_msg_one(); self:print_msg_two(); self:print_msg_three();
end
RegisterUserCommand("my_plugin", MyPlugIn.command_console, MyPlugIn); </source>
Summary
This tutorial was written by a beginner with other beginners in mind. I hope this tutorial has given you a quick and relatively painless introduction to Vendetta Plug-in scripting. If you have feedback, feel free to post it on the discussion page.
I look forward to using your plug-ins in the game.
- Rubin427 16:53, 19 June 2009 (UTC)