Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor builtin HUD #14346

Merged
merged 26 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3b86bb8
Refactor builtin HUD
cx384 Feb 4, 2024
d1e2bba
Re-add minimap
cx384 Feb 8, 2024
af18d72
Reuse breath and breath_max
cx384 Mar 19, 2024
b00ee05
Use assert and fix statbar check
cx384 Mar 19, 2024
d0d57bf
Improve comments
cx384 Mar 30, 2024
20781c4
Apply suggestions
cx384 Mar 30, 2024
b180224
Reuse update_hud to avoid duplication
cx384 Mar 30, 2024
0f8f9da
Apply missed suggestion
cx384 Mar 30, 2024
79dfac7
Fix l
cx384 Mar 30, 2024
980daa6
Remove player_event_handler bool returns
cx384 Mar 30, 2024
a22b2d0
Remove player check
cx384 Mar 30, 2024
46bae54
Document bug
cx384 Mar 30, 2024
02db2de
Remove variable
cx384 Mar 30, 2024
9606a7d
Update builtin/game/hud.lua
cx384 Mar 31, 2024
69f4d3e
Update builtin/game/hud.lua
cx384 Mar 31, 2024
d928ef1
Change comment
cx384 Mar 31, 2024
25fec43
Apply suggestions and fix duplicate breathbar
cx384 Mar 31, 2024
864572c
Remove deprecated flags change
cx384 Mar 31, 2024
4118dd6
Fix broken delayed removal, move removal code out of getter function
grorp Apr 1, 2024
1b02932
More consistent naming, reorder code in update_def to actually fix ba…
grorp Apr 1, 2024
721ef7d
Update code style according to https://dev.minetest.net/Lua_code_styl…
grorp Apr 1, 2024
325050b
Consistent order for HUD definition members
grorp Apr 1, 2024
ede7e57
Don't update the minimap element on "properties_changed" events
grorp Apr 1, 2024
b53d197
Fix docs?
grorp Apr 1, 2024
dc3b01b
Merge pull request #2 from grorp/builtin_hud_refactor
cx384 Apr 6, 2024
a433606
Fix `minetest` being used instead of `core`
grorp Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
235 changes: 235 additions & 0 deletions builtin/game/hud.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
--[[
Register function to easily register new builtin hud elements
Contains:
cx384 marked this conversation as resolved.
Show resolved Hide resolved
elem_def the HUD element definion which can be changed with hud_replace_builtin
event (optional) for an additional eventname on which update_element is called
cx384 marked this conversation as resolved.
Show resolved Hide resolved
("hud_changed" and "properties_changed" will always be used.)
hud_change(id, player)
(optional) a function to change the element after it has been updated
show_elem(player, flags, id)
(optional) a function to decide if the element should be shown to a player
cx384 marked this conversation as resolved.
Show resolved Hide resolved
]]--
local registered_elements = {}
local update_events = {}
local function register_builtin_hud_element(name, def)
registered_elements[name] = def
if def.event then
local events = update_events[def.event]
if events then
table.insert(events, name)
else
update_events[def.event] = {name}
end
cx384 marked this conversation as resolved.
Show resolved Hide resolved
end
end

-- Stores HUD ids for all players
local hud_ids = {}

-- Updates one element
-- In case the element is already added, it does only call the hud_change function from
cx384 marked this conversation as resolved.
Show resolved Hide resolved
-- registered_elements. (To completely update the element call player:hud_remove(id) first.)
local function update_element(player, player_hud_ids, elem_name, flags)
local def = registered_elements[elem_name]
local id = player_hud_ids[elem_name]

if def.show_elem and not def.show_elem(player, flags, id) then
if id then
player:hud_remove(id)
cx384 marked this conversation as resolved.
Show resolved Hide resolved
end
return
end

if not id then
id = player:hud_add(def.elem_def)
player_hud_ids[elem_name] = id
end

if def.hud_change then
def.hud_change(player, id)
end
cx384 marked this conversation as resolved.
Show resolved Hide resolved
end

-- Updates all elements
local function update_hud(player)
local flags = player:hud_get_flags()
local playername = player:get_player_name()
local player_hud_ids = hud_ids[playername]
if not player_hud_ids then
player_hud_ids = {}
hud_ids[playername] = player_hud_ids
end
cx384 marked this conversation as resolved.
Show resolved Hide resolved
for elem_name, _ in pairs(registered_elements) do
update_element(player, player_hud_ids, elem_name, flags)
end
end

local function player_event_handler(player, eventname)
cx384 marked this conversation as resolved.
Show resolved Hide resolved
assert(player:is_player())

if eventname == "hud_changed" or eventname == "properties_changed" then
update_hud(player)
cx384 marked this conversation as resolved.
Show resolved Hide resolved
return true
end

-- Custom events
local to_update = update_events[eventname]
if to_update then
local flags = player:hud_get_flags()
local playername = player:get_player_name()
local player_hud_ids = hud_ids[playername]
if not player_hud_ids then
player_hud_ids = {}
hud_ids[playername] = player_hud_ids
end
for _, elem_name in ipairs(to_update) do
update_element(player, player_hud_ids, elem_name, flags)
end
cx384 marked this conversation as resolved.
Show resolved Hide resolved
return true
end

return false
end

-- Returns true if successful, otherwise false,
-- but currently the return value is not part of the lua API.
cx384 marked this conversation as resolved.
Show resolved Hide resolved
function core.hud_replace_builtin(elem_name, definition)
assert(type(definition) == "table")

local registered = registered_elements[elem_name]
if not registered then
return false
end

registered.elem_def = table.copy(definition)

for playername, player_hud_ids in pairs(hud_ids) do
local player = core.get_player_by_name(playername)
local id = player_hud_ids[elem_name]
if player and id then
player:hud_remove(id)
cx384 marked this conversation as resolved.
Show resolved Hide resolved
update_element(player, player_hud_ids, elem_name, player:hud_get_flags())
end
end
return true
end

local function cleanup_builtin_hud(player)
local name = player:get_player_name()
if name == "" then
return
end
cx384 marked this conversation as resolved.
Show resolved Hide resolved
hud_ids[name] = nil
end


-- Append "update_hud" as late as possible
-- This ensures that the HUD is hidden when the flags are updated in this callback
core.register_on_mods_loaded(function()
core.register_on_joinplayer(update_hud)
end)
core.register_on_leaveplayer(cleanup_builtin_hud)
core.register_playerevent(player_event_handler)


---- Builtin HUD Elements

--- Healthbar

-- Cache setting
local enable_damage = core.settings:get_bool("enable_damage")

local function scaleToHudMax(player, field)
-- Scale "hp" or "breath" to the hud maximum dimensions
local current = player["get_" .. field](player)
local nominal
if field == "hp" then -- HUD is called health but field is hp
nominal = registered_elements.health.elem_def.item
else
nominal = registered_elements[field].elem_def.item
end
local max_display = math.max(player:get_properties()[field .. "_max"], current)
return math.ceil(current / max_display * nominal)
end

register_builtin_hud_element("health", {
elem_def = {
type = "statbar",
position = {x = 0.5, y = 1},
text = "heart.png",
text2 = "heart_gone.png",
number = core.PLAYER_MAX_HP_DEFAULT,
item = core.PLAYER_MAX_HP_DEFAULT,
direction = 0,
size = {x = 24, y = 24},
offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 16)},
},
show_elem = function(player, flags)
return flags.healthbar and enable_damage and player:get_armor_groups().immortal ~= 1
end,
event = "health_changed",
hud_change = function(player, id)
player:hud_change(id, "number", scaleToHudMax(player, "hp"))
end,
})

--- Breathbar

register_builtin_hud_element("breath", {
elem_def = {
type = "statbar",
position = {x = 0.5, y = 1},
text = "bubble.png",
text2 = "bubble_gone.png",
number = core.PLAYER_MAX_BREATH_DEFAULT * 2,
item = core.PLAYER_MAX_BREATH_DEFAULT * 2,
direction = 0,
size = {x = 24, y = 24},
offset = {x = 25, y= -(48 + 24 + 16)},
},
show_elem = function(player, flags, id)
local breath = player:get_breath()
local breath_max = player:get_properties().breath_max
cx384 marked this conversation as resolved.
Show resolved Hide resolved
local show_breathbar = flags.breathbar and enable_damage and player:get_armor_groups().immortal ~= 1
cx384 marked this conversation as resolved.
Show resolved Hide resolved

if id then
if breath == breath_max then
local player_name = player:get_player_name()
-- The breathbar stays for some time and then gets removed.
core.after(1, function(player_name, id)
local player = core.get_player_by_name(player_name)
if player then
player:hud_remove(id)
end
end, player_name, id)
cx384 marked this conversation as resolved.
Show resolved Hide resolved
hud_ids[player_name].breath = nil
cx384 marked this conversation as resolved.
Show resolved Hide resolved
end

return show_breathbar
cx384 marked this conversation as resolved.
Show resolved Hide resolved
else
-- Only if the element does not already exist the breath amount is considered.
return show_breathbar and breath < breath_max
end
end,
event = "breath_changed",
hud_change = function(player, id)
player:hud_change(id, "number", scaleToHudMax(player, "breath"))
end,
})

--- Minimap

register_builtin_hud_element("minimap", {
elem_def = {
type = "minimap",
position = {x = 1, y = 0},
alignment = {x = -1, y = 1},
offset = {x = -10, y = 10},
size = {x = 256, y = 256},
},
show_elem = function(player, flags)
-- Don't add a minimap for clients which already have it hardcoded in C++.
return minetest.get_player_information(player:get_player_name()).protocol_version >= 44
and flags.minimap
end,
})
2 changes: 1 addition & 1 deletion builtin/game/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ assert(loadfile(gamepath .. "falling.lua"))(builtin_shared)
dofile(gamepath .. "features.lua")
dofile(gamepath .. "voxelarea.lua")
dofile(gamepath .. "forceloading.lua")
dofile(gamepath .. "statbars.lua")
dofile(gamepath .. "hud.lua")
dofile(gamepath .. "knockback.lua")
dofile(gamepath .. "async.lua")

Expand Down