Skip to content

Commit d87d1d1

Browse files
authored
First pass documentation
1 parent 9c1aad6 commit d87d1d1

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

README.md

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
# Unity-Lua
2+
A wrapper around MoonSharp that allows easy development of moddable Unity games
3+
4+
# Installation
5+
* Create "Assets/Plugins/Lua" in your Unity project
6+
* Download and place the contents of this repository to the newly created folder
7+
8+
# Dependancies
9+
[MoonSharp](http://www.moonsharp.org/) & [Unity-Logger](https://github.com/Semaeopus/Unity-Logger)
10+
11+
# Code Breakdown
12+
13+
This codebase allows Unity developers to easily create game specific modding apis for their Unity games!
14+
It was created during the development of [Off Grid](http://www.offgridthegame.com)
15+
16+
## Executing Lua Code
17+
LuaVM is the main Lua interface, it's the class you use to run Lua scripts or individual Lua command strings.
18+
19+
### Executing a string
20+
21+
```C#
22+
const string luaCode = @"
23+
-- Lua Code
24+
num = 1 + 1
25+
print(num)
26+
";
27+
28+
LuaVM vm = new LuaVM();
29+
vm.ExecuteString(luaCode); // Prints 2
30+
```
31+
32+
### Executing a script
33+
34+
Most of the time you'll want to load and execute Lua code from a script file written to disk, here's an example of how that's achieved.
35+
36+
Contents of fruits.lua
37+
```lua
38+
fruits = {
39+
"apple",
40+
"banana",
41+
}
42+
43+
GetRandomFruit = function()
44+
return fruits[math.random(1, #fruits)]
45+
end
46+
```
47+
48+
Here's some code that loads the fruits table from the script, as well as getting a reference to the GetRandomFruit and calling it.
49+
```C#
50+
LuaVM vm = new LuaVM();
51+
vm.ExecuteScript("/path/to/fruits.lua");
52+
53+
// Get table to iterate
54+
Table fruitTable = vm.GetGlobalTable("fruits");
55+
foreach (DynValue fruit in fruitTable.Values)
56+
{
57+
Debug.Log(fruit.String); // Prints "apple" then "banana"
58+
}
59+
60+
// Or get a lua function and call it
61+
DynValue fruitFunction = vm.GetGlobal("GetRandomFruit");
62+
Debug.Log(vm.Call(fruitFunction).String); // Prints return of GetRandomFruit
63+
```
64+
65+
## Creating an API
66+
Creating an api with this framework is incredibly simple, let's say we're making a game where the player can interact with supermarkets.
67+
We of course want this game to be moddable, so let's write up information about the super market in Lua, things like stock and name for a start.
68+
69+
Here's an example of a very simple Lua api to let the players get random items that can go in their shops stocklist.
70+
71+
```C#
72+
[LuaApi(
73+
luaName = "SuperMarket",
74+
description = "This is a test lua api")]
75+
public class SuperMarketAPI : LuaAPIBase
76+
{
77+
private readonly List<string> m_Veggies = new List<string>
78+
{
79+
"Aubergine",
80+
"Broccoli",
81+
"Cauliflower",
82+
"Carrot",
83+
"Kale",
84+
};
85+
86+
private readonly List<string> m_Fruits = new List<string>
87+
{
88+
"Strawberry",
89+
"Grape",
90+
"Lychee",
91+
"Melon",
92+
"Apple",
93+
};
94+
95+
public SuperMarketAPI()
96+
: base("SuperMarket")
97+
{
98+
}
99+
100+
protected override void InitialiseAPITable()
101+
{
102+
m_ApiTable["GetRandomVeg"] = (System.Func<string>) (Lua_GetRandomVeggies);
103+
m_ApiTable["GetRandomFruit"] = (System.Func<string>) (Lua_GetRandomFruits);
104+
m_ApiTable["MaxStock"] = MaxStock;
105+
}
106+
107+
[LuaApiEnumValue(description = "The max stock any shop should contain")]
108+
private const int MaxStock = 10;
109+
110+
[LuaApiFunction(
111+
name = "GetRandomVeg",
112+
description = "Returns a random vegetable that can be stocked by an in-game shop"
113+
)]
114+
private string Lua_GetRandomVeggies()
115+
{
116+
int randomIndex = Random.Range(0, m_Veggies.Count - 1);
117+
return m_Veggies[randomIndex];
118+
}
119+
120+
[LuaApiFunction(
121+
name = "GetRandomFruit",
122+
description = "Returns a random fruit that can be stocked by an in-game shop"
123+
)]
124+
private string Lua_GetRandomFruits()
125+
{
126+
int randomIndex = Random.Range(0, m_Fruits.Count - 1);
127+
return m_Fruits[randomIndex];
128+
}
129+
}
130+
131+
```
132+
Lua apis become available to LuaVM instances by default, the first time a LuaVM is created reflection is used to cache all types that derive from LuaAPIBase.
133+
Here's a Lua script that uses the brand new SuperMarket api:
134+
135+
```lua
136+
Shop = {
137+
Name = "Dumpling's Super Store",
138+
Stock = {},
139+
}
140+
141+
-- Generate the stock items
142+
for i= 1, SuperMarket.MaxStock do
143+
table.insert(Shop.Stock, SuperMarket.GetRandomVeg())
144+
table.insert(Shop.Stock, SuperMarket.GetRandomFruit())
145+
end
146+
```
147+
148+
Corrisponding C# code
149+
150+
```C#
151+
LuaVM vm = new LuaVM();
152+
vm.ExecuteScript("/path/to/DumplingsStore.lua");
153+
154+
// Get the shops name
155+
string shopName = vm.GetGlobal("Shop", "Name").String;
156+
Debug.Log(shopName); // Prints "Dumpling's Super Store"
157+
158+
// Get Items in stock
159+
Table fruitTable = vm.GetGlobalTable("Shop", "Stock");
160+
foreach (DynValue item in fruitTable.Values)
161+
{
162+
Debug.Log(item.String);
163+
}
164+
165+
```
166+
167+
So there's a really simple example of how you can add arbitrary apis to your game for use in Lua.
168+
LuaApiBase uses the string passed into its constructor as the true name of the Lua api, in this example that's "SuperMarket".
169+
It then allows the derived type to fill in m_ApiTable, note how above this is really a MoonSharp wrapper around a Lua table, meaning that it's not just functions.
170+
Above we've used a MaxStock int which whilst it's currently a const, could be set by calling into a gameplay system.
171+
172+
### Exposing Enums
173+
One thing that can be a pain when dealing with lua is having to use raw ints rather than enums, using this framework fixes this issue by allowing the automatic generation of Lua versions of your enums.
174+
Let's say in our game the player can adopt pets, and we want modders to be able to create new pets with different personalities and abilities.
175+
Here's how you could go about exposing an enum type to your modders in order to know how to render the correct model/sprite.
176+
177+
```C#
178+
[LuaApiEnum(
179+
name = "PetType",
180+
description = "Defines what type a pet is")]
181+
public enum PetType
182+
{
183+
[LuaApiEnumValue(
184+
description = "Aloof and occasionally affectionate")]
185+
Cat,
186+
187+
[LuaApiEnumValue(
188+
description = "A loyal best friend")]
189+
Dog,
190+
191+
[LuaApiEnumValue(
192+
description = "Slow and a bit snappy")]
193+
Turtle,
194+
195+
[LuaApiEnumValue(
196+
description = "Cute, small and loves grain")]
197+
Hamster,
198+
199+
// Not ready for modders yet!
200+
[LuaApiEnumValue(hidden = true)]
201+
Dragon,
202+
}
203+
```
204+
205+
In a similar vein to how Lua apis are automatically detected by LuaVM, any enum with the LuaApiEnum is automatically exposed to all lua scripts run from LuaVM.
206+
So modders can now use it like so:
207+
208+
```Lua
209+
Pet = {
210+
Name = "Rex",
211+
Type = PetType.Dog,
212+
attack = function(target)
213+
-- Attack Logic
214+
end
215+
}
216+
```
217+
218+
** Note: ** It's worth noting that enum values can be hidden from exposure by the LuaApiEnumValue attributes hidden value, just as we've done with the Dragon type above.
219+
220+
## Options
221+
The LuaVM constructor optionally takes in an instance of the VMSettings flag, this allows the user to attach only attach apis, enums, both or none at all.
222+
If you know you're not going to need any of the attachments, it's more performant to use ```new LuaVM(VMSettings.None)```
223+
224+
# Documentation Creation
225+
One of this frameworks most handy features is its automatic documentation creation.
226+
Document creation is triggered by using the built in Unity menu items:
227+
228+
![](https://i.imgur.com/AKUEhMS.png)
229+
230+
Currently the framework supports the creation of the following documentation:
231+
* MediaWiki pages per api
232+
* Visual Studio Code snippets for auto complete
233+
* Atom Snippets for auto complete
234+
235+
These are all created by using the attributes attached to your apis, api function, api variables and enums.
236+
All the available attributes are used in the code snippets above, however here's a quick reference:
237+
238+
| Attribute | Use |
239+
|:---------:|---|
240+
| LuaApi | Above LuaApiBase derived type |
241+
| LuaApiFunction | Above functions that are part of the Lua api table |
242+
| LuaApiVariable | Above variables that are part of the Lua api table |
243+
| LuaApiEnum | Above enums that you want to be attached to LuaVMs |
244+
| LuaApiEnumValue | Above enums values that you'd like to describe or hide |
245+
246+
Adding more documentation formats is very easy, why not try adding another doucmentation type yourself in LuaDocGenerator.cs!

0 commit comments

Comments
 (0)