Modding Guide
Contents
Capabilities
What can I mod? What can't I mod?
- The Official Map is currently moddable in a very limited way. You can not change the terrain mesh geometry or textures, nor remove any static objects.
- Custom Creatures are currently not moddable in Unity.
- Custom Equipment is currently not moddable in Unity.
- Custom Maps can be made in Unity and run in game.
- They also no longer fall under NDA, so you are already permitted to host them for players.
- Custom Assets (such as custom objects) can already be added and set up for the client to properly use.
- This includes adding object or surface collision, transparency colliders or collapsible roofs for houses, as well as object bounds and picker boxes for support players to be able to interact with them.
- Custom Maps currently do not support a proper SFX set up. Both music and environment effects can be placed in the scene for testing and they will play in the client. However, you can not lower or increase the volume in the client properties.
- World Streamer is not supported for modding at this time. This means you can not create a large, open-world environment with custom maps. You can only build content with World Streamer in mind.
Necessary Tools
For the time being, modding is only feasible on Windows machines.
- Unity 3D editor: Download Unity3D Installer version 2018.1.9 (at least version 5.6). You will need to create an account.
- Note: When you download and install Unity, to be sure to also download and install the standard assets. It is possible to install unity without these. If you do, then you will need to manually add them to be able to import.
- Editing Lua scripts and XML files: Download Sublime Text or any other editor with syntax highlighting, e.g. Notepad++.
- The latest Legends of Aria Toolkit.
Note: Unity3D useful tip to move the camera: Press right-clight to enter "WASD" camera control mode. Add 'SHIFT' to accelerate camera movement.
Tips for Beginners
Backup Regularly. Be sure to always back up your complete unity project on a regular basis.
Ask For Help. I can not stress this enough. Ask for help. Unity has a steep learning curve. You are working in a professional game engine. If you encounter issues, do not try to figure it out yourself for hours on end. Instead, ask for help. On top of that, you might actually be doing everything right. The LoA toolkit still has quite it's share of bugs, and you do not want to be spending time kicking yourself because you think you screwed up. So, you guessed it, ask for help. If you are worried your question might be dumb, still ask for help. You are a modder, not a professional game developer. We all have to start somewhere.
Start Small. For your first project, start with a very small map and work on it from start to finish. That is the best way to familiarize you with all of the steps, know how everything interacts, and get a sense of how much time what takes.
Creating a new project, based or not on the Celador map
Cf. this video introducing the setup.
NOTE: You must have first installed a LoA server before to proceed with the direction below.
- Launch Unity3D, create a "New" "3D" project, assigning it with a name, preferably in a folder of your choice. No Unity Analytics is needed.
- Import assets: in "Assets" menu, "Import Package" and import both "Effects" and "Environment" (Press "Import" for each new window opening).
- Do not import any other standard packages. A common mistake is that new map creators believe it is better to import all of the standard assets. It is not. It may break your project. I will get into that a little further down the road when we cover custom assets.
- The Standard Assets package from the asset store is not the same as the one you import here. The one from the asset store can actually break your project. If you do not see them, the unity download you used does not include the files. You will need to download them manually and add them. The guide for this is at the end of this chapter.
- From the Assets store (in "Window" menu, select "Asset Store"), search for the "Post Processing Stack" package ("Unity Essentials" from "Unity Technologies"), install and import it.
- The Post Processing Stack is made by Unity and is free. It combines a complete set of image effects into a single post-process pipeline. As Legends of Aria recently began to use post-processing profiles on it's camera, you want to have this for everything to function properly.
- in "Assets" menu, "Import Package", import "Custom Package" and select the Legends of Aria Toolkit you previously downloaded. Click "Import" on the new widow, this will take several minutes.
- You should now have a new "LoA Toolkit" menu item in Unity3D.
- Under that new menu item, select "Settings".
- "Browse" the "Base Path" to reflect the path: <server>\Build\base
- "Browse" the "mods Path" to reflect the path: <server>\mods
- Press "Save".
- If you are editing a mod that you already created, select the consistent mod name in the "Mod" pull-down list (You might have to "save" first and reopen the Settings).
- If you are starting a new mod, select "Create Mod" under the "LoA Toolkit" menu.
Your Mods folder under <server> should then reflect the structure displayed on the right.
Modding the Celador maps
- Look in Unity's "Project" widget, select the "Legends of Aria Toolkit" folder and double-click on the "ShardsToolkit.unity" Unity asset (It's a scene map loader helper).
- Select the "Game" above the viewer window and press the "Play" button on the top right of that same window.
- You can select any scene map to be loaded by pressing its button.
- For "New Celador", there is an exception: the map is split into sub-scenes because it is very big: Under the "LoA Toolkit" menu, select "Utils" then "World Streamer Manager". You can then select a "Preset" selection of scene respective to the area(s) you are looking to edit. You can alternatively load individual scenes by clicking on them.
- Switch to the "Scene" view by pressing the "#Scene" button above the Unity viewer (from the "Game" view you currently are on).
- You can add Prefabs to the map, as well as Seed Objects (cf. below).
Make sure you save your mod after edition.
Modder Tip: Not all files in the base folder are overridable (moddable). Here is a full list of these files:
- ClientIdReference.txt
- ObjectCollisionData.xml
- ObjectTagDefinitions.xml
- mapdata/MAPNAME/StaticCollision.xml
Starting a new map
See this video for more detail.
- From the "LoA Toolkit" menu, select "Custom Assets", then "Create New Custom Map". You can choose either it's an exterior or interior map. A new "MapData" asset will be created under your new "Untitled" (a least until you save it) unity scene in Unity's "Hierarchy" widget.
- The reason we are creating our new scene this way and not the way you would normally in Unity is that this will add a couple of important things to your scene for you. These are the MapData object, the DefaultOutdoorLighting or DefaultIndoorLighting objects, and the DefaultOutdoorCamera or DefaultIndoorCamera objects. You should always have these in your scene. If you do not, something went wrong.
- Create a new terrain, either by right clicking in the "Hierarchy" widget or under the "GameObject" menu, then "3D Object" and "Terrain".
- Note: It is important to position the Terrain object in the "Hierarchy" widget as a top node, i.e. not under any other object (including not under the "MapData" object). Drag the Terrain object if needed.
- You can edit the terrain properties (size, center, texture, etc.) from Unity's "Inspector" widget. You can also use some Unity Terrain generators to help you create terrains easily (some are free in Unity's asset store)
- You can now add Prefabs to the map, as well as Seed Objects (cf. below).
Make sure you save your mod after edition.
Saving your mod
- First, make sure you have saved your Unity project, saved all your seed objects (if any), built your custom objects library (if any).
- When done, select "MapData" in Unity's "Hierarchy" widget. Select "Reset Permanent IDs" (unless you have a script that refers to any Permanent IDs) in Unity's "Inspector" widget and press "Build". If you haven't saved the Unity project or scene yet, Unity will require you to save it first.
- To make sure your server loads your modifications, make sure you consistently edit the "<Mod>" section of the ClusterConfig.xml file, i.e. put your mod name there.
- If you have created a new map, make sure you add a "<ClientBundle>" subsection in that section and add or edit the consistent "<Region>".
- Also, make sure you clean up all your server backups before to reload it (careful of what you delete as well, like characters' data, if you're in production).
Potential issues
Here is a list of potential issues you might encounter when testing your mod, and ways to fix those:
- Custom objects collision not working properly, especially on custom maps, even though you are 100% sure your collision is set up correctly.
- This might be a "Terrain" issue. Make sure your Terrain object isn't under another object, i.e. is at the top level of the Hierarchy, and that it doesn't contain any child object.
- This might also be a cache issue. You can try to delete the folders related to your mod (usually starting with your mod name) in <C:\Users\YOUR WINDOWS ACCOUNT NAME\AppData\LocalLow\Unity\Citadel Studios Inc__Legends of Aria>
Dynamic Game Objects (GameObj)
Legends of Aria is a true world simulation in the sense that there are very little arbitrary rules on the dynamic game objects in the world. Dynamic game objects (GameObjs) can be placed anywhere and are defined by their properties. GameObjs that contain a mobile component can move smoothly throughout the world using the pathing algorithm. All GameObjs are created from templates. The template is the definition for the initial state of an object at creation. It defines things like: What does it look like (Client Id)? What is its name? What sorts of behaviors does this object have? etc. Once the GameObj is created, the template is never referenced again and every property about that object can be changed by scripts or god powers.
NOTE: In Lua, the reference type for dynamic game objects is GameObj and we will refer to them as such in this handbook.
Seed Objects
Seed objects are dynamic object that spawns when the server resets or when loaded the first time. Many of these “Seed Objects” are invisible to mortal players and are used as a source for controller scripts. The simplest and most common example of a controller script is a spawner, a behavior that spawns other GameObjs like monsters or animals on the map. In Unity3D, they can be grouped, under "category" or "group", so they can be loaded, saved and edited all at once or separately. Celador base map's Seed Objects are grouped by zone and types.
In Unity3D, to access Seed Objects functionality, in the "LoA Toolkit" menu, select "Dynamic Editors" then "Seed Object Editor".
Loading
If you are editing from the Celador base map, select the "Default" "Mod", otherwise load your module's specific group (if not already loaded). You can select in the "Seed Object Editor" to "Load All Seed Objects" or the specific "Group" that you want to load to edit.
Creating an Instance
It is advised to create groups/categories to have a finer detail of finding, editing and saving/loading of seed objects. In order to do this, click on "Create New Category" on the "Seed Object Editor" window. You can rename each category or seed object from Unity's "Hierarchy" widget. Then you can "Create New Seed Object" from the "Seed Object Editor" window. You will want to drag that "New Seed" object within the consistent category (that you created above) in Unity's "Hierarchy" widget, and rename it. Then select that seed in the "Hierarchy" widget and you will see Unity's "Inspector" widget updating, as well as the bottom of the "Seed Object Editor" window, showing "Seed Object Selected". You can "Select" a template to be used for that seed (You might have to re-select "Default" for "Mod" to get all the templates if you had changed it before).
A useful thing when your editing point-of-view is pointing at the location you want to place your item at, is to use the "GameObject" menu's "Move To View" function. Double-clicking on an object in Unity's "Hierarchy" will move the point-of-view to point to the object's location.
Make sure you save your seed objects when done.
Saving
If you have modified any group of seed object or single object from the "Default" Celador map, make sure you select your "Mod" in the "Seed Object Editor" before saving. Ditto if you want to override any "Default" group, you can also create a group of the same name of a "Default" Celador group to override.
You can choose to "Save All Seed Objects" or select individual groups/categories to be saved. Make sure you save the seeds as often as possible not to loose your work (since it's independent from Unity's scene/project saving).
Properties
If you understand all of the different types of properties and behaviors that can be assigned to GameObjs then you essentially understand how Legends of Aria works at its core. Let’s quickly go through these properties and behaviors (some will be explained in more detail later).
Base Properties
These properties exist on every GameObj in the game. If a property is not defined in the template, it will fall back to its default value (assuming it’s not required)
- ClientId (required) – This is the art asset id the client uses to display this object. It also determines which Shared Object Properties (See section under Lua Script Engine) this object has and their default values.
- Name - Modder Tip: Nearly every string in the game, including names, can be color coded. It uses html color codes in square brackets and is terminated with a dash in square brackets. Example: A blue string would be “[0000FF]Blue String[-]”
- ScaleModifier – Optionally modifies the size of the object by multiplying the default scale of the object by this value.
- Hue – This is a hexadecimal color code in the format 0xARGB. Example: Red is 0xFFFF0000
Mobile Component
This must exist on any object that can move smoothly across the map using the pathing algorithm. Currently, this is limited to players, NPCs and creatures, however, later this could be expanded to vehicles such as carts and boats.
- BaseRunSpeed – Default is currently 6 (units/sec)
- MobileType – This is used to group mobs together for player targeting purposes. For example, if a mobile is “Friendly” then players will need to force an attack on them. This value is also accessible in the Lua script engine.
Object Variable Component
Object Variables are for storage of persistent information about the object. This means it is maintained across server restarts. Object variables are attached to the GameObj itself and are accessible to any behavior, even behaviors attached to other GameObjs. For example, the number of PvP kills could be stored on a player object in the “PlayerKills” object variable.
Modder Tip: Many behaviors expect certain object variables to be set on an object. For example, the ”weapon_base” behavior expects the “WeaponType” object variable to be set.
Script Engine Component
This is the component that creates Lua environments for any behaviors attached to the GameObj. These behaviors define what an object can do. For example, attaching the food behavior to an object makes it able to be eaten, or attaching an AI script to a creature.
Note: Even if your object does not have any Object Variables or Behaviors at creation, it should still have an empty ObjectVariableComponent and ScriptEngineComponent node in its template file. This is because the engine does not yet automatically create these for you when they are needed at runtime. If you are using the template editor tool, this is automatically done for you.
Prefabs
Prefabs are usually static objects that can be place on a map, i.e. a building, trees, etc. You can use "Default" Celador prefabs, which can be found in Unity's "Project" widget, under "Assets", "Legends of Aria Toolkit", "Default Object Library", "Prefabs".
Permanent Objects (PermanentObj)
In order to allow the user to interact with the thousands of rocks and trees on the map without killing server performance, we also have a second, simpler, type of object for them called “Permanent Objects”. These are map objects that never move and have no base properties or behaviors. The only information that is stored for each is a single visual state (Example: a tree could have full, stump and hidden).
Client Only Objects
These are objects that are built into the map and the server has no access to. This means players and other objects cannot interact with them. A simple example of this is grass or a bridge. Collision for client only objects is also built into the map and cannot be changed.
Custom Objects
If the default set of prefabs from LoA isn't sufficient for you, you can create or import your own objects, either from scratch or using assets available from Unity3D's asset store (Under the "Window" menu, "Asset Store").
All of the objects you place on your map also seem to work without setting up your Custom Object Library. Why do it then?
The reason for this is because it currently only works due to a problematic bug. Right now Citadel Studios does not use, nor support the method that Unity uses to assign assets to specific bundles.
While it works for now, you do not want to end up having to do tons of work once that changes.
Especially if you use a lot of assets, it can quickly become a staggering amount of work that will be frustrating to get through.
Check this video for a detailed tutorial.
Custom Objects Library
The following steps are necessary to create a custom object library:
- In Unity's "Project" widget, Select "Assets" and right-click "Create" then "Folder". Rename that folder with the name of you new library, e.g. "MyCustomLibrary".
- Select that new folder. Under the "LoA Toolkit" menu, select "Custom Assets" then "Create New Custom Object Library". A new "Custom Object Library" library will be created under that folder.
- Click on the "Custom Object Library" and in Unity's "Inspector" widget, set the "Bundle Name" to the same name you used in step 1, e.g. "MyCustomeLibrary".
Creating Object Prefabs
The following steps are to create a new "Prefab" Object to be added to your library, and be reused in the game:
- In Unity's "Hierarchy" widget, right-click and select "Create Empty" (an alternative is to go in the "GameObject" menu and "Create Empty" from there). It will create a new empty "GameObject" object, that will be referred as "parent" object in the next steps.
- Rename that "parent" object consistently and, after having selecting it, go in the "Inspector" widget and press "Add Component". Search for "Client Object" and assign it to it.
- When your camera is pointed at a location you want to visualize the object, and while the "parent" object you created is selected in the "Hierarchy", go in the "GameObject" menu and select "Move To View". It shall be centered on your view, sitting on the ground.
- You can now import an external object, e.g. from another library or from your own creation, as a children of the "parent" object that you created in the previous steps. It will probably not be added under the object you created right away, thus make sure you drag it there from the "Hierarchy" widget.
- If you import an object from an external asset library (e.g. from the asset store), make sure you break the link from its original template. Select the custom object and in the "GameObject" menu, select "Break Prefab Instance".
- If you import an object, it might already contain a Collider property. Since LoA manages Colliders of its own (cf. here under), make sure you delete any existing Collider from the imported model.
- You might need to apply scaling to that child object so it fits within the scale of the map.
- Do not apply scaling to the "parent" object, since this one can be manipulated by the client game engine.
---------------------------------------------------------------------------------------------------------
- Do not apply scaling to the "parent" object, since this one can be manipulated by the client game engine.
- For all custom objects you are importing/creating, you have to create a bounding box representing the space the object takes up in the world:
- Select the "parent" object and under the "GameObject" menu, select "Create Empty Child".
- Rename that new object "ObjectBounds" (exactly that name, or it won't work) and move it as the first child of the "parent" object.
- Select that "ObjectBounds" and in the "Inspector", "Add Component", search for "Box Collider" (LoA only works with Box Colliders) and select it.
- Set the "Box Collider" values in the "Inspector" so it matches what you want. Depending on the object, you might want to create a Bounding Box that is bigger than the object itself (e.g. to leave enough space around a house for placing decorations, etc).
---------------------------------------------------------------------------------------------------------
- If the custom object you are importing/creating is an object that players are supposed to interact with (e.g. grab them), you will have to create a picker object:
- Select the "parent" object and under the "GameObject" menu, select "Create Empty Child".
- Rename that new object, e.g. "PickerBounds" (you can choose any name), and move it as the first child of the "parent" object.
- Select that "PickerBounds" and in the "Inspector", change "Layer" to "PickerCollider".
- Select that "PickerBounds" and in the "Inspector", "Add Component", and use any type of Unity Collider best adapted to your object's shape (e.g. "Box Collider" or, more commonly, "Capsule Collider") and select it.
- Set the "Box Collider" values in the "Inspector" so it matches what you want, i.e. to best fit the object (might want to make it bigger if the object is small).
---------------------------------------------------------------------------------------------------------
- If you need Collision detection, so no character can go through that object (e.g. only through a house door or around a tree), you can add 1 or more "Collider"s (i.e. 1 for a tree, several for house walls):
- Select the "parent" object and under the "GameObject" menu, select "Create Empty Child".
- Rename that new object "Collider" (exactly that name, or it won't work) and move it as the first child of the "parent" object.
- Select that "Collider" and in the "Inspector", "Add Component", search for "Box Collider" (LoA only works with Box Colliders) and select it.
- Set the "Box Collider" values in the "Inspector" so it matches what you want.
- Repeat the steps above to create as many colliders as needed for this object.
---------------------------------------------------------------------------------------------------------
- If the custom object you are importing/creating is a house or building, you will probably need to create collapsible roofs and walls for inside view:
- Watch the video listed above for a detailed description
---------------------------------------------------------------------------------------------------------
- Watch the video listed above for a detailed description
- When done editing, drag the finalized object from "Hierarchy" into your custom library folder in Unity's "Project" widget.
- Click on your custom objects library in the "Project" widget and click on "Add Field". A new empty "Element" entry will be created.
- Drag the custom object from the custom library folder in "Project" in the field next to the new "Element" in "Inspector". You can alternatively press the round button next to the field and search for your custom object in the window that opens.
- Save your Unity project/scene and build the custom assets library.
- If you just need the object you created as a template, and not an instance in the world, i.e. not as a static object in the world, you can delete the object from Unity's "Hierarchy" widget. You can reuse it later from your custom object library later or use it inside a Lua script.
Repeat those steps above for any new custom object you are creating.
Note: If you modify any property from a custom object in Unity's "Hierarchy", and you want that change to be taken into account in the template, make sure you click in Unity's "Inspector" widget on the "Apply" button of "Prefab"
Saving the custom objects library
Once you have created all your custom objects, or adding any new ones, or editing any existing ones, make sure you (re)build the library:
- In Unity's "Project" widget, select your custom objects library asset, which is under the folder you created earlier in this section.
- In Unity's "Inspector" widget, press the "Build" button. This will take several minutes. Alternatively, you can also "Build" your mapData, this will also trigger building the custom objects library.
- Make sure you have edited the "Mod" section of your server "ClusterConfig.xml" file to add the consistent "<ClientBundle Type="ClientObjects" ...>".
Object Templates
Object templates are custom objects that you can dynamically spawn within the game, either by a player with enough rights to do so, or through a Lua script.
- Make sure you first created that custom object and added it to your custom objects library.
- Go to your mod's template folder, located under <server>\mods\YOUR MOD NAME\templates (You can create sub-folders as needed for your organization, i.e. by category/group or region, since sub-folders are ignored by the engine).
- Create a XML file for your object template, e.g. <object_template.xml> and open it for editing
- Fill the file with a basic description:
<ObjectTemplate> <ClientId>In Unity3D's "Project", select your asset prefab from the custom objects folder, put here the value of "Client Id", e.g. 584</ClientId> <Name>Put here the name of your custom object, e.g. MyCustomObject</Name> <CustomAssetBundle>Put here the name of your custom library, e.g. MyCustomLibrary</CustomAssetBundle> <SharedStateEntry name="Weight" type="int" value="1"/> </ObjectTemplate>
Save the file. You can now try running the server, logging as a "God" character and use the "/create" call to instantiate your object.