30 KiB
Arena_lib docs
Table of Contents
- 1. Arenas
- 2. Configuration
- 3. About the author(s)
1. Arenas
Not the theory-kind of person? Skip it going to point #2 (but I highly suggest you at least the arena phases in 1.3)
It all starts with a table called arena_lib.mods = {}
. This table allows arena_lib
to be subdivided per mod and it has different parameters, one being arena_lib.mods[yourmod].arenas
. Here is where every new arena created gets put.
An arena is a table having as a key an ID and as a value its parameters. They are:
name
: (string) the name of the arena, declared when creating itsign
: (pos) the position of the sign associated with the arena.players
: (table) where to store playersteams
: (table) where to store teams. If there are none, it's {-1}teams_enabled
: (boolean) whether teams are enabled in the arena. Requires teamsplayers_amount
: (int) separately stores how many players are inside the arena/queuemax_players
: (string) default is 4. When this value is reached, queue time decreases to 5 if it's not lower alreadymin_players
: (string) default is 2. When this value is reached, a queue startsinitial_time
: (int) in seconds. It's nil when the mod doesn't keep track of time, it's 0 when the mod does it incrementally and it's inherited by the mod if the mod has a timer. In this case, every arena can have its specific value. By default time tracking is disabled, hence it's nilcurrent_time
: (int) in seconds. It requiresinitial_time
and it exists only when a game is in progress, keeping track of the current timein_queue
: (bool) about phases, look at "Arena phases" down belowin_loading
: (bool)in_game
: (bool)in_celebration
: (bool)enabled
: (bool) by default an arena is disabled, to avoid any unwanted damage
Being arenas stored by ID, they can be easily retrieved by arena_libs.mods[yourmod].arenas[THEARENAID]
.
There are two ways to know an arena ID: the first is in-game via the two debug utilities:
arena_lib.print_arenas(sender, mod)
: coincisearena_lib.print_arena_info(sender, mod, arena_name)
: extended with much more information (this one is implemented in the editor by default)
The second is via code by the functions:
arena_lib.get_arenaID_by_player(p_name)
: the player must be queueing for the arena, or playing itarena_lib.get_arena_by_name(mod, arena_name)
: it returns both the ID and the arena (so, the table)
Beware: this is an API. It means all the functions illustrated here must be connected to your mod BY YOU. Nonetheless, I've created both an in-game editor to let you skip most of these steps and linked a configuration file example (that uses commands) close to the end. In short: I got you :)
1.1 Creating and removing arenas
There are two functions for it and they all need to be connected to some command in your mod. These functions are
arena_lib.create_arena(sender, mod, arena_name, <min_players>, <max_players>)
: it doesn't accept duplicates. Sender is a string, fields between < > are optionalarena_lib.remove_arena(mod, arena_name)
: if a game is taking place in it, it won't go through
1.1.1 Storing arenas
Arenas and their settings are stored inside the mod storage. What is not stored are players, their stats and such.
Better said, these kind of parameters are emptied every time the server starts. And not when it ends, because handling situations like crashes is simply not possible.
1.1.2 Renaming an arena
Being arenas stored by ID, changing their names is no big deal. An arena can be renamed via
arena_lib.rename_arena(sender, mod, arena_name, new_name)
In order to do so, it must be disabled.
1.2 Setting up an arena
Two things are needed to have an arena up to go: spawners and signs. There are two functions for that:
arena_lib.set_spawner(sender, mod, arena_name, <teamID_or_name>, <param>, <ID>)
: spawners can't exceed the maximum players of an arena and, more specifically, they must be the same number. A spawner is a table withpos
andteam_ID
as values.arena_lib.set_sign(sender, <pos, remove>, <mod, arena_name>)
: there must be one and only one sign per arena. Signs are the bridge between the arena and the rest of the world
1.2.1 Editor
Since 3.0, arena_lib comes with a fancy editor via hotbar so you don't have to configure and memorise a lot of commands (if you still want to go full CLI/chat though, skip this paragraph).
In order to use the editor, no other players must be editing the same arena. When entering it, the arena is disabled automatically. The rest is pretty straightforward :D if you're not sure of what something does, just open the inventory and read its name.
The function calling the editor is
arena_lib.enter_editor(sender, mod, arena_name)
1.2.2 CLI
If you don't want to rely on the hotbar, or you want both the editor and the commands via chat, here's how the commands work. Note that there actually is another parameter at the end of each of these functions named in_editor
but, since it's solely used by the editor itself in order to run less checks, I chose to odmit it (it's in set_spawner
too).
1.2.2.1 Players management
arena_lib.change_players_amount(sender, mod, arena_name, min_players, max_players)
changes the amount of players in a specific arena. It also works by specifying only one field (such as ([...] myarena, 3)
or ([...] myarena, nil, 6)
). It returns true if it succeeded.
1.2.2.2 Enabling/Disabling teams
arena_lib.toggle_teams_per_arena(sender, mod, arena_name, enable)
enables/disables teams per single arena. enable
is an int, where 0 disables teams and 1 enables them.
1.2.2.3 Timers
arena_lib.set_timer(sender, mod, arena_name, timer)
changes the timer of the arena. It only works if timers are enabled (explained further below).
1.2.2.4 Arena properties
Properties are explained down below, but essentially they allow you to create additional attributes specifically suited for what you have in mind (e.g. a score to reach to win the game).
arena_lib.change_arena_property(sender, mod, arena_name, property, new_value)
changes the specified arena property with new_value
. Keep in mind you can't change a property type (a number must remain a number, a string a string etc), and strings need quotes surrounding them - so false
is a boolean, but "false"
is a string. Also, this works for arena properties only. Not for temporary, players, nor team ones.
1.2.2.5 Spawners
arena_lib.set_spawner(sender, mod, arena_name, <teamID_or_name>, <param>, <ID>)
creates a spawner where the sender is standing, so be sure to stand where you want the spawn point to be.
teamID_or_name
can be both a string and a number. It must be specified if your arena uses teamsparam
is a string, specifically "overwrite", "delete" or "deleteall". "deleteall" aside, the other ones need an ID after them. Also, if a team is specified with deleteall, it will only delete the spawners belonging to that teamID
is the spawner ID, forparam
I suggest you using ChatCmdBuilder by rubenwardy and connect theset_spawner
function to a few subcommands such as:
local mod = "mymod" -- more about this later
ChatCmdBuilder.new("NAMEOFYOURCOMMAND", function(cmd)
-- for creating spawners without teams
cmd:sub("setspawn :arena", function(sender, arena)
arena_lib.set_spawner(sender, mod, arena)
end)
-- for creating spawners with teams
cmd:sub("setspawn :arena :team:word", function(sender, arena, team)
arena_lib.set_spawner(sender, mod, arena, team)
end)
-- for using 'param' (just pass a random number for deleteall as it won't matter)
cmd:sub("setspawn :arena :param:word :ID:int", function(sender, arena, param, ID)
arena_lib.set_spawner(sender, mod, arena, nil, param, ID)
end)
-- for using 'param' with teams
cmd:sub("setspawn :arena :team:word :param:word :ID:int", function(sender, arena, team, param, ID)
arena_lib.set_spawner(sender, mod, arena, team, param, ID)
end)
[etc.]
1.2.2.6 Signs
arena_lib.set_sign(sender, <pos, remove>, <mod, arena_name>)
via chat uses sender
, mod
and arena_name
, while the editor pos
and remove
(hence the weird subdivision). When used via chat, it takes the block the player is pointing at in a 5 blocks radius. If the block is a sign, it then creates (or remove if already set) the "arena sign".
1.2.3 Enabling an arena
When a sign has been set, it won't work. This because an arena must be enabled manually via
arena_lib.enable_arena(sender, mod, arena_name)
or by using the Enable and Leave button in the editor.
If all the conditions are met, you'll receive a confirmation. If not, you'll receive the reason why it didn't through and the arena will remain disabled. Conditions are:
- all spawn points set
- sign placed
Arenas can be disabled too, via
arena_lib.disable_arena(sender, mod, arena_name)
(or by entering the editor, as previously said).
In order to do that, no game must be taking place in that specific arena.
1.3 Arena phases
An arena comes in 4 phases, each one of them linked to a specific function:
waiting phase
: it's the queuing process. People hit a sign waiting for other players to play withloading phase
: it's the pre-match. By default players get teleported in the arena not being able to do anything but jumpfighting phase
: the actual gamecelebration phase
: the after-match. By default people stroll around for the arena knowing who won, waiting to be teleported
The 4 functions, intertwined with the previously mentioned phases are:
arena_lib.load_arena(mod, arena_ID)
: between the waiting and the loading phase. Called when the queue timer reaches 0, it teleports people inside.arena_lib.start_arena(mod_ref, arena)
: between the loading and the fighting phase. Called when the loading phase timer reaches 0.arena_lib.load_celebration(mod, arena, winner_name)
: between the fighting and the celebration phase. Called when the winning conditions are met.winner_name
can be both a string and a table (in case of teams)arena_lib.end_arena(mod_ref, mod, arena)
: at the very end of the celebration phase. It teleports people outside the arena
Overriding these functions is not recommended. Instead, there are 4 respective callbacks made specifically to customise the behaviour of the formers, sharing (almost) the same variables. They are called after the function they're associated with and by default they are empty, so feel free to override them. They are on_load
, on_start
, on_celebration
and on_end
, and they are explained later in 2.3.
2. Configuration
Still a TL;DR? Check out the example file
First of all download the mod and put it in your mods folder.
Then, you need to register your minigame in arena_lib, possibly inside the init.lua, via:
arena_lib.register_minigame("yourmod", {parameter1, parameter2 etc})
"yourmod" is how arena_lib will store your mod inside its storage, and it's also what it needs in order to understand you're referring to that specific mod (that's why almost every arena_lib
function contains "mod" as a parameter).You'll need it when calling for commands or callbacks. Use the same name you used in mod.conf or some features won't be available.
The second field, on the contrary, is a table of parameters: they define the very features of your minigame. They are:
prefix
: what's going to appear in most of the lines printed by your mod. Default is[Arena_lib]
hub_spawn_point
: where players will be teleported when a match in your mod ends. Default is{ x = 0, y = 20, z = 0 }
teams
: a table of strings containing teams. If not declared, your minigame won't have teams and the table will be equal to{-1}
. You can add as many teams as you like, as the number of spawners (and players) will be multiplied by the number of teams (somax_players = 4
* 3 teams =max_players = 12
)teams_color_overlay
: a table of color strings. It applies a color overlay onto the players' skin according to their team, to better distinguish them. It requires team. Default is noneis_team_chat_default
: whether players messages in a game should be sent to their teammates only. It requiresteams
, default is falsemod_ref.chat_all_prefix
: prefix for every message sent in arena, team chat aside. Default is nonemod_ref.chat_team_prefix
: prefix for every message sent in the team chat. Default is[team]
(geolocalised)mod_ref.chat_all_color
: color for every message sent in arena, team chat aside. Default is white ("#ffffff"
)mod_ref.chat_team_color
: color for every message sent in the team chat. Default is light sky blue ("#ddfdff"
)join_while_in_progress
: whether the minigame allows to join an ongoing match. Default is falsekeep_inventory
: whether to keep players inventories when joining an arena. Default is falseshow_nametags
: whether to show the players nametags while in game. Default is falseshow_minimap
: whether to allow players to use the builtin minimap function. Default is falsetime_mode
: whether arenas will keep track of the time or not.0
: no time tracking at all (default)1
: incremental time (0, 1, 2, ...)2
: decremental time, as in a timer (3, 2, 1, 0). The timer value is 300 seconds by default, but it can be changed per arena
queue_waiting_time
: the time to wait before the loading phase starts. It gets triggered when the minimium amount of players has been reached to start the queue. Default is 10load_time
: the time between the loading state and the start of the match. Default is 3celebration_time
: the time between the celebration state and the end of the match. Default is 3in_game_physics
: an optional table containing a physical override to set to each player when they enter an arenadisabled_damage_types
: a table containing which damage types will be disabled once in a game. Damage types are strings, the same as in reason.type in the minetest APIproperties
: explained down belowtemp_properties
: sameplayer_properties
: sameteam_properties
: same (it won't work ifteams
hasn't been declared)
Beware: as you noticed, the hub spawn point is bound to the very minigame. In fact, there is no global spawn point as arena_lib could be used even in a survival server that wants to feature just a couple minigames. If you're looking for a hub manager because your goal is to create a full minigame server, have a look at my other mod Hub Manager. Also, if you want to be sure to join the same arena/team with your friends, you need to install my other mod Parties
2.1 Privileges
arenalib_admin
: allows to use the/arenakick
command
2.2 Commands
A couple of general commands are already declared inside arena_lib, them being:
/quit
: quits a game/all
: writes in the arena global chat/t
: writes in the arena team chat (if teams are enabled)
2.2.1 Admins only
A couple more are available for players having the arenalib_admin
privilege:
/arenakick player_name
: kicks a player out of an ongoing game/forceend mod arena_name
: forcibly ends an ongoing game
Those aside, you need to connect a few functions with your mod in order to use them. The best way is with commands and again I suggest you the ChatCmdBuilder by rubenwardy. This is what I came up with in my Quake minigame, which relies on arena_lib. As you can see, I declared a local mod = "quake"
at the beginning, because it's how I stored my mod inside the library. Also, I created the support for both the editor and the chat commands.
2.3 Callbacks
To customise your mod even more, there are a few empty callbacks you can use. They are:
arena_lib.on_enable(mod, function(arena, p_name)
: use it to run more checks before enabling an arena. Must return true if all conditions are metarena_lib.on_disable(mod, function(arena, p_name)
: use it to run more checks before disabling an arena. Must return true if all conditions are metarena_lib.on_load(mod, function(arena)
(we saw these 4 earlier)arena_lib.on_start(mod, function(arena))
arena_lib.on_celebration(mod, function(arena, winner_name)
arena_lib.on_end(mod, function(arena, players))
arena_lib.on_join(mod, function(p_name, arena))
: called when a player joins an ongoing matcharena_lib.on_death(mod, function(arena, p_name, reason))
: called when a player diesarena_lib.on_time_tick(mod, function(arena))
: called every second inside the arena iftime_mode
is 2.arena_lib.on_timeout(mod, function(arena))
: called when the timer of an arena, if exists (time_mode = 2
), reaches 0. Not declaring it will make the server crash when time runs outarena_lib.on_eliminate(mod, function(arena, p_name))
: called when a player is eliminated (seearena_lib.remove_player_from_arena(...)
)arena_lib.on_kick(mod, function(arena, p_name))
: called when a player is kicked from a match (same as above)arena_lib.on_quit(mod, function(arena, p_name, is_forced))
: called when a player quits from a match (same as above).is_forced
is true when the match has been terminated viaforce_arena_ending(...)
arena_lib.on_prequit(mod, function(arena, p_name))
: called when a player tries to quit. If it returns false, quit is cancelled. Useful ie. to ask confirmation first, or simply impede a player to quitarena_lib.on_disconnect(mod, function(arena, p_name))
: called when a player disconnects while in a match
Beware: there is a default behaviour already for most of these situations: for instance when a player dies, their deaths increase by 1. These callbacks exist just in case you want to add some extra behaviour to arena_lib's.
So for instance, if we want to add an object in the first slot when a player joins the pre-match, we can simply do:
arena_lib.on_load("mymod", function(arena)
local item = ItemStack("default:dirt")
for pl_name, stats in pairs(arena.players) do
pl_name:get_inventory():set_stack("main", 1, item)
end
end)
2.4 Additional properties
Let's say you want to add a kill leader parameter. Arena_lib
doesn't provide specific parameters, as its role is to be generic. Instead, you can create your own kill leader parameter by using the four tables properties
, temp_properties
, player_properties
and team_properties
. The first two are for the arena, the third is for players and the fourth for teams.
No matter the type of property, they're all shared between arenas. Better said, their values can change, but there can't be an arena with more or less properties than another.
2.4.1 Arena properties
The difference between properties
and temp/player/team's is that the former will be stored by the the mod so that when the server reboots it'll still be there, while the others won't and they reset every time a match ends. Everything but properties
is temporary. In our case, for instance, we don't want the kill leader to be preserved outside of a match, thus we go to our arena_lib.register_minigame(...)
and write:
arena_lib.register_minigame("mymod", {
--whatever stuff we already have
temp_properties = {
kill_leader = ""
}
}
in doing so, we can easily access the kill_leader
field whenever we want from every arena we have, via ourarena.kill_leader
. E.g. when creating a function calculating the arena kill leader
Beware: you DO need to initialise your properties (whatever type) or it'll return an error
2.4.1.1 Updating non temporary properties via code
Let's say you want to change a property from your mod. A naive approach would be doing yourarena.property = something
. This, though, won't update it in the storage, so when you restart the server it'll still have the old value.
Instead, the right way to permanently update a property for an arena is calling arena_lib.change_arena_property(<sender>, mod, arena_name, property, new_value)
. If sender
is nil, the output message will be printed in the log.
2.4.1.2 Updating properties for old arenas
This is done automatically by arena_lib every time you change the properties declaration in register_minigame
, so don't worry. Just, keep in mind that when a property is removed, it'll be removed from every arena; so if you're not sure about what you're doing, do a backup first.
2.4.2 Player properties
These are a particular type of temporary properties, as they're attached to every player in the arena. Let's say you now want to keep track of how many kills a player does in a streak without dying. You just need to create a killstreak parameter, declaring it like so
arena_lib.register_minigame("mymod", {
--stuff
temp_properties = {
kill_leader = ""
},
player_properties = {
killstreak = 0
}
}
Now you can easily access the killstreak
parameter by retrieving the player inside an arena. Also, don't forget to reset it when a player dies via the on_death
callback we saw earlier:
arena_lib.on_death("mymod", function(arena, p_name, reason)
arena.players[p_name].killstreak = 0
end)
2.4.3 Team properties
Same as above, but for teams. For instance, you could count how many rounds of a single match has been won by a specific team, and then call a load_celebration when one of them reaches 3 wins.
Check out this example for a full configuration file
2.5 HUD
arena_lib
also comes with a double practical HUD: broadcast
and hotbar
. These HUDs only appear when a message is sent to them and they can be easily used via the following commands:
arena_lib.HUD_send_msg(HUD_type, p_name, msg, <duration>, <sound>)
: send a message to the specified player in the specified HUD type ("broadcast" or "hotbar"). If no duration is declared, it won't disappear by itself. If a sound is declared, it'll be played at the very showing of the HUDarena_lib.HUD_send_msg_all(HUD_type, arena, msg, <duration>, <sound>)
: same as above, but for all the players inside the arenaarena_lib.HUD_hide(HUD_type, player_or_arena)
: it makes the specified HUD disappear; it can take both a player than a whole arena. Also, a special parameterall
can be used inHUD_type
to make both the HUDs disappear
2.6 Extendable editor
Since 4.0, every minigame can extend the editor with an additional custom section on the 5th slot. To do that, the function is
arena_lib.register_editor_section("yourmod", {parameter1, parameter2 etc})
On the contrary of when an arena is registered, every parameter here is mandatory. They are:
name
: the name of the item that will represent the sectionicon
: the icon of the item that will represent the sectionhotbar_message
: the message that will appear in the hotbar HUD once the section has been openedgive_items = function(itemstack, user, arena)
: this function must return the list of items to give to the player once the section has been opened, or nil if we want to deny the access. Having a function instead of a list is useful as it allows to run whatever check inside of it, and to give different items accordingly
When a player is inside the editor, they have 2 string metadata containing the name of the mod and the name of the arena that's currently being modified. These are necessary to do whatever arena operation with items passed via give_items
, as they allow to obtain the arena ID and the arena itself via arena_lib.get_arena_by_name(mod, arena_name)
. To better understand this, have a look at how arena_lib does
2.7 Utils
There are also some other functions which might turn useful. They are:
arena_lib.is_player_in_queue(p_name, <mod>)
: returns a boolean. If a mod is specified, returns true only if it's inside a queue of that specific modarena_lib.is_player_in_arena(p_name, <mod>)
: returns a boolean. Same as abovearena_lib.is_player_in_same_team(arena, p_name, t_name)
: compares two players teams by the players names. Returns true if on the same team, false if notarena_lib.is_team_declared(mod_ref, team_name)
: returns true if there is a team calledteam_name
. Otherwise it returns falsearena_lib.force_arena_ending(mod, arena, <sender>)
: forcibly ends an ongoing game. It's usually called by/forceend
, but it can be used, for instance, to annul a game.arena_lib.remove_player_from_arena(p_name, <reason>, <executioner>)
: removes the player from the arena and it brings back the player to the lobby if still online. Reason is an int, and if specified equals to...0
: player disconnected. Callson_disconnect
1
: player eliminated. Callson_eliminate
if declared. Otherwise callson_quit
2
: player kicked. Callson_kick
if declared. Otherwise callson_quit
3
: player quit. Callson_quit
4
: forced by the mod. This should NOT be used but internally. Callson_quit
Default is 0 and these are mostly hardcoded in arena_lib already, so it's advised to not touch it and to use callbacks. The only exception is in case of manual elimination (ie. in a murder minigame, so reason = 1).
Executioner can be passed to tell who removed the player. By default, this happens when someone uses /arenakick and /forceend, so that these commands can't be abused without consequences for the admin.
arena_lib.send_message_players_in_arena(arena, msg, <teamID>, <except_teamID>)
: send a message to all the players in that specific arena. If a teamID is specified, it'll be only sent to the players inside that very team. On the contrary, if except_teamID is true, it'll be sent to every player BUT the ones in the specified teamarena_lib.teleport_in_arena(sender, mod, arena_name)
: teleport the sender into the arena if at least one spawner has been setarena_lib.is_arena_in_edit_mode(arena_name)
: returns whether the arena is in edit mode or not, as a booleanarena_lib.is_player_in_edit_mode(p_name)
: returns whether a player is editing an arena, as a boolean
2.8 Getters
arena_lib.get_arena_by_name(mod, arena_name)
: returns the ID and the whole arena (so a table)arena_lib.get_players_in_game()
: returns all the players playing in whatever arena of whatever minigamearena_lib.get_players_in_team(arena, team_ID, <to_players>)
: returns a table containing either the name of the players in the specified team or the players theirselves if to_player is truearena_lib.get_mod_by_player(p_name)
: returns the minigame a player's in (game or queue)arena_lib.get_arena_by_player(p_name)
: returns the arena the player's in, (game or queue)arena_lib.get_arenaID_by_player(p_name)
: returns the ID of the arena the player's playing inarena_lib.get_queueID_by_player(p_name)
: returns the ID of the arena the player's queueing forarena_lib.get_arena_spawners_count(arena, <team_ID>)
: returns the total amount of spawners declared in the specified arena. If team_ID is specified, it only counts the ones belonging to that teamarena_lib.get_random_spawner(arena, <team_ID>)
: returns a random spawner declared in the specified arena. If team_ID is specified, it only considers the ones belonging to that teamarena_lib.get_player_in_edit_mode(arena_name)
: returns the name of the player who's editingarena_name
, if there is any
2.9 Things you don't want to do with a light heart
- Changing the number of the teams: it'll delete your spawners (this has to be done in order to avoid further problems)
- Any action in the "Players" section of the editor, except changing their minimum amount: it'll delete your spawners (same as above)
- Removing properties in the minigame declaration: it'll delete them from every arena, without any possibility to get them back. Always do a backup first
- Disabling timers (
time_mode = 2
to something else) when arenas have custom timer values: it'll reset every custom value, so you have to put them again manually if/when you decide to turning timers back up.
3. About the author(s)
I'm Zughy (Marco), a professional Italian pixel artist who fights for FOSS and digital ethics. If this library spared you a lot of time and you want to support me somehow, please consider donating on LiberaPay. Also, this project wouldn't have been possible if it hadn't been for some friends who helped me testing through: Giov4
, SonoMichele
, _Zaizen_
and Xx_Crazyminer_xX