Arenas can now forcibly terminated by admins via /forceend | spring cleaning

master
Zughy 2020-08-25 22:28:45 +02:00
parent 9c713a0de8
commit dab851ac71
9 changed files with 143 additions and 37 deletions

20
DOCS.md
View File

@ -175,11 +175,17 @@ The second field, on the contrary, is a table of parameters: they define the ver
* `arenalib_admin`: allows to use the `/kick` command
### 2.2 Commands
A couple of general commands are already declared inside arena_lib, them being:
* `/kick player_name`: kicks a player out of an ongoing game. The sender needs the `arenalib_admin` privilege in order to use it
A couple of general commands are already declared inside arena_lib, them being:
* `/quit`: quits a game
* `/all`: to write in the global chat of an arena
* `/t`: to write in the team chat of an arena (if teams are enabled)
* `/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:
* `/kick 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](https://rubenwardy.com/minetest_modding_book/en/players/chat_complex.html) by rubenwardy. [This](https://gitlab.com/zughy-friends-minetest/minetest-quake/-/blob/master/commands.lua) 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.
@ -195,11 +201,11 @@ To customise your mod even more, there are a few empty callbacks you can use. Th
* `arena_lib.on_timeout(mod, function(arena))`: called when the timer of an arena, if exists, reaches 0
* `arena_lib.on_eliminate(mod, function(arena, p_name))`: called when a player is eliminated (see `arena_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))`: called when a player quits 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 via `force_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 quit
* `arena_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, its deaths increase by 1. These callbacks exist just in case you want to add some extra behaviour to arena_lib's.
> 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:
@ -276,11 +282,13 @@ There are also some other functions which might turn useful. They are:
* `arena_lib.is_player_in_arena(p_name, <mod>)`: returns a boolean. Same as above
* `arena_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 not
* `arena_lib.is_team_declared(mod_ref, team_name)`: returns true if there is a team called `team_name`. Otherwise it returns false
* `arena_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>)`: 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. Calls `on_disconnect`
* `1`: player eliminated. Calls `on_eliminate`
* `2`: player kicked. Calls `on_kick`
* `3`: player quit. Calls `on_quit`
* `4`: forced by the mod. This should NOT be used but internally. Calls `on_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)
* `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 team
* `arena_lib.teleport_in_arena(sender, mod, arena_name)`: teleport the sender into the arena if at least one spawner has been set

82
api.lua
View File

@ -991,7 +991,6 @@ end
function arena_lib.load_celebration(mod, arena, winner_name)
local mod_ref = arena_lib.mods[mod]
local winning_message = ""
arena.in_celebration = true
arena_lib.update_sign(arena)
@ -1015,6 +1014,8 @@ function arena_lib.load_celebration(mod, arena, winner_name)
end
local winning_message = ""
-- determino il messaggio da inviare
if type(winner_name) == "string" then
winning_message = S("@1 wins the game", winner_name)
@ -1049,13 +1050,6 @@ function arena_lib.end_arena(mod_ref, mod, arena)
players[pl_name] = stats
arena.players[pl_name] = nil
players_in_game[pl_name] = nil
arena.players_amount = 0
arena.timer_current = nil
if arena.teams_enabled then
for i = 1, #arena.teams do
arena.players_amount_per_team[i] = 0
end
end
local player = minetest.get_player_by_name(pl_name)
@ -1085,6 +1079,18 @@ function arena_lib.end_arena(mod_ref, mod, arena)
player:hud_set_flags({minimap = true})
end
-- azzero il numero di giocatori
arena.players_amount = 0
if arena.teams_enabled then
for i = 1, #arena.teams do
arena.players_amount_per_team[i] = 0
end
end
-- azzero il timer
arena.timer_current = nil
-- resetto le proprietà temporanee
for temp_property, v in pairs(mod_ref.temp_properties) do
if type(v) == "string" then
@ -1107,16 +1113,17 @@ function arena_lib.end_arena(mod_ref, mod, arena)
end
end
local id = arena_lib.get_arena_by_name(mod, arena.name)
-- eventuale codice aggiuntivo
if mod_ref.on_end then
mod_ref.on_end(arena, players)
end
arena.in_loading = false -- nel caso venga forzata mentre sta caricando, sennò rimane a caricare all'infinito
arena.in_celebration = false
arena.in_game = false
local id = arena_lib.get_arena_by_name(mod, arena.name)
-- aggiorno storage per le properties e cartello
update_storage(false, mod, id, arena)
arena_lib.update_sign(arena)
@ -1132,7 +1139,11 @@ end
function arena_lib.remove_from_queue(p_name)
local arena = arena_lib.get_arena_by_player(p_name)
players_in_queue[p_name] = nil
arena.players[p_name] = nil
end
@ -1204,17 +1215,53 @@ end
function arena_lib.force_arena_ending(mod, arena, sender)
local mod_ref = arena_lib.mods[mod]
-- se il minigioco non esiste, annullo
if not mod_ref then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This minigame doesn't exist!")))
return end
-- se l'arena non esiste, annullo
if not arena then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This arena doesn't exist!")))
return end
-- se l'arena non è in partita, annullo
if not arena.in_game then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] No ongoing game!")))
return end
if sender then
arena_lib.send_message_players_in_arena(arena, minetest.colorize("#d69298", S("The arena has been forcibly terminated by @1", sender)))
minetest.chat_send_player(sender, S("Game in arena @1 successfully terminated", arena.name))
else
arena_lib.send_message_players_in_arena(arena, minetest.colorize("#d69298", S("The arena has been forcibly terminated")))
end
-- caccio tutti i giocatori
for pl_name, _ in pairs(arena.players) do
arena_lib.remove_player_from_arena(pl_name, 4)
end
arena_lib.end_arena(mod_ref, mod, arena)
end
function arena_lib.remove_player_from_arena(p_name, reason)
-- reason 0 = has disconnected
-- reason 1 = has been eliminated
-- reason 2 = has been kicked
-- reason 3 = has quit the arena
-- reason 4 = has been forced to quit the arena
-- se il giocatore non è in partita, annullo
if not arena_lib.is_player_in_arena(p_name) then return end
local mod = arena_lib.get_mod_by_player(p_name)
-- se il giocatore non è né in coda né in partita, annullo
if not mod then return end
local mod_ref = arena_lib.mods[mod]
local arena = arena_lib.get_arena_by_player(p_name)
@ -1265,6 +1312,10 @@ function arena_lib.remove_player_from_arena(p_name, reason)
if mod_ref.on_quit then
mod_ref.on_quit(arena, p_name)
end
elseif reason == 4 then
if mod_ref.on_quit then
mod_ref.on_quit(arena, p_name, true)
end
end
else
arena_lib.send_message_players_in_arena(arena, minetest.colorize("#f16a54", "<<< " .. p_name ))
@ -1283,6 +1334,9 @@ function arena_lib.remove_player_from_arena(p_name, reason)
end
arena.players[p_name] = nil
-- se il termine dell'arena è stato forzato, non c'è bisogno di andare oltre
if reason == 4 then return end
-- se l'arena era in coda e ora ci son troppi pochi giocatori, annullo la coda
if arena.in_queue then

View File

@ -67,6 +67,32 @@ minetest.register_chatcommand("quit", {
minetest.register_chatcommand("forceend", {
description = S("Forcibly ends an ongoing game"),
privs = {
arenalib_admin = true,
},
func = function(name, param)
local mod, arena_name = string.match(param, "^([%a%d_-]+) ([%a%d_-]+)$")
-- se i parametri sono errati, annullo
if not mod or not arena_name then
minetest.chat_send_player(name, minetest.colorize("#e6482e", S("[!] Parameters don't seem right!")))
return end
local id, arena = arena_lib.get_arena_by_name(mod, arena_name)
arena_lib.force_arena_ending(mod, arena, name)
end
})
minetest.register_chatcommand("all", {
description = S("Write a message in the arena global chat while in a game"),

View File

@ -180,9 +180,14 @@ end
function arena_lib.print_arena_stats(sender, mod, arena_name)
local arena_ID, arena = arena_lib.get_arena_by_name(mod, arena_name)
if arena == nil then minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This arena doesn't exist!"))) return end
if not arena.in_game and not arena.in_celebration then minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] No ongoing game!"))) return end
if arena == nil then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This arena doesn't exist!")))
return end
if not arena.in_game and not arena.in_celebration then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] No ongoing game!")))
return end
for pl_name, stats in pairs(arena.players) do

View File

@ -1,4 +1,4 @@
local version = "3.4.0"
local version = "3.5.0-dev"
dofile(minetest.get_modpath("arena_lib") .. "/api.lua")
dofile(minetest.get_modpath("arena_lib") .. "/callbacks.lua")

View File

@ -1,4 +1,4 @@
# version 3.4.0
# version 3.5.0-dev
# author(s): Zughy
# reviewer(s):
# textdomain: arena_lib
@ -42,6 +42,12 @@ Arena @1 successfully enabled=Arena @1 abilitata con successo
Arena @1 successfully disabled=Arena @1 disabilitata con successo
@1 wins the game=@1 ha vinto la partita
Team @1 wins the game=La squadra @1 ha vinto la partita
[!] This minigame doesn't exist!=[!] Questo minigioco non esiste!
[!] This arena doesn't exist!=[!] Quest'arena non esiste!
[!] No ongoing game!=[!] Nessuna partita in corso!
The arena has been forcibly terminated by @1=La conclusione della partita è stata forzata da @1
Game in arena @1 successfully terminated=La partita nell'arena @1 è stata terminata con successo
The arena has been forcibly terminated=La conclusione della partita è stata forzata
@1 has been eliminated=@1 è stato eliminato
@1 has been kicked=@1 è stato cacciato
@1 has quit the match=@1 ha abbandonato la partita
@ -59,6 +65,7 @@ Kick a player from an ongoing game=Caccia un giocatore da una partita in corso
[!] The player must be in a game to perform this action!=[!] Il giocatore deve essere in partita per eseguire questa azione!
[!] You must be in a game to perform this action!=[!] Devi essere in partita per eseguire questa azione!
Quit an ongoing game=Abbandona una partita in corso
Forcibly ends an ongoing game=Forza la conclusione di una partita in corso
[!] You can't perform this action if you're the only one left!=[!] Non puoi eseguire quest'azione se sei l'unico giocatore rimasto!
Write a message in the arena global chat while in a game=Scrive un messaggio nella chat globale dell'arena mentre si è in una partita
Write a message in the arena team chat while in a game (if teams are enabled)=Scrive un messaggio nella chat di squadra dell'arena mentre si è in una partita (se le squadre sono abilitate)
@ -89,7 +96,6 @@ Spawn points: =Punti di spawn:
Properties: =Proprietà:
Temp properties: =Proprietà temporanee:
Team properties: =Proprietà squadra:
[!] No ongoing game! =[!] Nessuna partita in corso!
Player: =Giocatore:
, kills: =, uccisioni:
, deaths: =, morti:
@ -121,7 +127,6 @@ Get ready!=Preparati!
#Waiting=In attesa
# utils.lua
[!] This arena doesn't exist!=[!] Quest'arena non esiste!
[!] You must disable the arena first!=[!] Devi prima disabilitare l'arena!
[!] There must be no one inside the editor of the arena to perform this command! (now inside: @1)=[!] Non deve esserci nessuno nell'editor dell'arena per poter eseguire questo comando! (attualmente dentro: @1)

View File

@ -1,4 +1,4 @@
# version 3.4.0
# version 3.5.0-dev
# author(s):
# reviewer(s):
# textdomain: arena_lib
@ -42,6 +42,12 @@ Arena @1 successfully enabled=
Arena @1 successfully disabled=
@1 wins the game=
Team @1 wins the game=
[!] This minigame doesn't exist!=
[!] This arena doesn't exist!=
[!] No ongoing game!=
The arena has been forcibly terminated by @1=
Game in arena @1 successfully terminated=
The arena has been forcibly terminated=
@1 has been eliminated=
@1 has been kicked=
@1 has quit the match=
@ -60,6 +66,7 @@ Kick a player from an ongoing game=
[!] You must be in a game to perform this action!=
Quit an ongoing game=
[!] You can't perform this action if you're the only one left!=
Forcibly ends an ongoing game=
Write a message in the arena global chat while in a game=
Write a message in the arena team chat while in a game (if teams are enabled)=
@ -89,7 +96,6 @@ Spawn points: =
Properties: =
Temp properties: =
Team properties: =
[!] No ongoing game! =
Player: =
, kills: =
, deaths: =
@ -121,7 +127,6 @@ Get ready!=
#Waiting=
# utils.lua
[!] This arena doesn't exist!=
[!] You must disable the arena first!=
[!] There must be no one inside the editor of the arena to perform this command! (now inside: @1)=

View File

@ -31,6 +31,13 @@ minetest.register_on_leaveplayer(function(player)
arena_lib.remove_player_from_arena(p_name)
end
--TODO
--[[if arena_lib.is_player_in_arena(p_name) then
arena_lib.remove_player_from_arena(p_name)
elseif arena_lib.is_player_in_queue(p_name) then
arena_lib.remove_from_queue(p_name)
end]]
if arena_lib.is_player_in_edit_mode(p_name) then
arena_lib.quit_editor(player)
end

View File

@ -102,9 +102,8 @@ minetest.override_item("default:sign_wall", {
for _, pl_name in pairs(party_members) do
arena_lib.HUD_hide("all", pl_name)
arena_lib.remove_from_queue(pl_name)
arena_lib.send_message_players_in_arena(sign_arena, minetest.colorize("#d69298", sign_arena.name .. " < " .. pl_name))
sign_arena.players[pl_name] = nil
arena_lib.remove_from_queue(pl_name)
end
-- sennò rimuovo il singolo utente
@ -115,9 +114,8 @@ minetest.override_item("default:sign_wall", {
end
arena_lib.HUD_hide("all", p_name)
arena_lib.remove_from_queue(p_name)
arena_lib.send_message_players_in_arena(sign_arena, minetest.colorize("#d69298", sign_arena.name .. " < " .. p_name))
sign_arena.players[p_name] = nil
arena_lib.remove_from_queue(p_name)
end
local players_required = get_players_required(sign_arena)
@ -162,9 +160,8 @@ minetest.override_item("default:sign_wall", {
for _, pl_name in pairs(party_members) do
arena_lib.HUD_hide("broadcast", pl_name)
arena_lib.remove_from_queue(pl_name)
arena_lib.send_message_players_in_arena(old_arena, minetest.colorize("#d69298", old_arena.name .. " < " .. pl_name))
old_arena.players[pl_name] = nil
arena_lib.remove_from_queue(pl_name)
end
-- sennò è singolo utente
else
@ -174,9 +171,8 @@ minetest.override_item("default:sign_wall", {
end
arena_lib.HUD_hide("broadcast", p_name)
arena_lib.remove_from_queue(p_name)
arena_lib.send_message_players_in_arena(old_arena, minetest.colorize("#d69298", old_arena.name .. " < " .. p_name))
old_arena.players[p_name] = nil
arena_lib.remove_from_queue(p_name)
end
local players_required = get_players_required(old_arena)