Dehardcode the death formspec (#15155)

Co-authored-by: Paul Ouellette <oue.paul18@gmail.com>
This commit is contained in:
grorp 2024-09-24 22:37:44 +02:00 committed by GitHub
parent 3c48671076
commit 526a2f7b8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
79 changed files with 242 additions and 172 deletions

@ -1,15 +0,0 @@
-- CSM death formspec. Only used when clientside modding is enabled, otherwise
-- handled by the engine.
core.register_on_death(function()
local formspec = "size[11,5.5]bgcolor[#320000b4;true]" ..
"label[4.85,1.35;" .. fgettext("You died") ..
"]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]"
core.show_formspec("bultin:death", formspec)
end)
core.register_on_formspec_input(function(formname, fields)
if formname == "bultin:death" then
core.send_respawn()
end
end)

@ -9,6 +9,5 @@ dofile(commonpath .. "mod_storage.lua")
dofile(commonpath .. "chatcommands.lua") dofile(commonpath .. "chatcommands.lua")
dofile(commonpath .. "information_formspecs.lua") dofile(commonpath .. "information_formspecs.lua")
dofile(clientpath .. "chatcommands.lua") dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "death_formspec.lua")
dofile(clientpath .. "misc.lua") dofile(clientpath .. "misc.lua")
assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions

@ -0,0 +1,31 @@
local F = core.formspec_escape
local S = core.get_translator("__builtin")
function core.show_death_screen(player, _reason)
local fs = {
"formspec_version[1]",
"size[11,5.5,true]",
"bgcolor[#320000b4;true]",
"label[4.85,1.35;", F(S("You died")), "]",
"button_exit[4,3;3,0.5;btn_respawn;", F(S("Respawn")), "]",
}
core.show_formspec(player:get_player_name(), "__builtin:death", table.concat(fs, ""))
end
core.register_on_dieplayer(function(player, reason)
core.show_death_screen(player, reason)
end)
core.register_on_joinplayer(function(player)
if player:get_hp() == 0 then
core.show_death_screen(player, nil)
end
end)
core.register_on_player_receive_fields(function(player, formname, fields)
if formname == "__builtin:death" and fields.quit and player:get_hp() == 0 then
player:respawn()
core.log("action", player:get_player_name() .. " respawns at " ..
player:get_pos():to_string())
end
end)

@ -38,6 +38,7 @@ dofile(gamepath .. "forceloading.lua")
dofile(gamepath .. "hud.lua") dofile(gamepath .. "hud.lua")
dofile(gamepath .. "knockback.lua") dofile(gamepath .. "knockback.lua")
dofile(gamepath .. "async.lua") dofile(gamepath .. "async.lua")
dofile(gamepath .. "death_screen.lua")
core.after(0, builtin_shared.cache_content_ids) core.after(0, builtin_shared.cache_content_ids)

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Вы загінулі
Respawn=Адрадзіцца

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Умряхте
Respawn=Прераждане

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Has mort
Respawn=Reaparèixer

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Zemřel jsi
Respawn=Oživit

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Buest ti farw
Respawn=Atgyfodi

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Du døde
Respawn=Genopstå

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Es wurden insgesamt @1 Datenpunkt(e) aufgeze
The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“. The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“.
Saving of profile failed: @1=Speichern des Profils fehlgeschlagen: @1 Saving of profile failed: @1=Speichern des Profils fehlgeschlagen: @1
Profile saved to @1=Profil abgespeichert nach @1 Profile saved to @1=Profil abgespeichert nach @1
You died=Sie sind gestorben
Respawn=Wiederbeleben

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Πέθανες
Respawn=Επανεμφάνηση

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Sume @1 ekzemplero(j) konserviĝis.
The output is limited to '@1'.=La eligo estas limigita al «@1». The output is limited to '@1'.=La eligo estas limigita al «@1».
Saving of profile failed: @1=Konservado de profilo malsukcesis: @1 Saving of profile failed: @1=Konservado de profilo malsukcesis: @1
Profile saved to @1=Profilo konservita al @1 Profile saved to @1=Profilo konservita al @1
You died=Vi mortis
Respawn=Renaskiĝi

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Has muerto
Respawn=Reaparecer

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Said surma
Respawn=Ärka ellu

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Hil zara
Respawn=Birsortu

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Kuolit
Respawn=Synny uudelleen

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Namatay ka
Respawn=Mag-respawn

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=@1 échantillons ont été collectés.
The output is limited to '@1'.=La sortie est limitée à '@1'. The output is limited to '@1'.=La sortie est limitée à '@1'.
Saving of profile failed: @1=La sauvegarde du profil a échoué : @1 Saving of profile failed: @1=La sauvegarde du profil a échoué : @1
Profile saved to @1=Le profil a été sauvegardé dans @1 Profile saved to @1=Le profil a été sauvegardé dans @1
You died=Vous êtes mort
Respawn=Réapparaître

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Fuair tú bás
Respawn=Athsceith

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Morreches
Respawn=Reaparecer

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Meghaltál
Respawn=Újraéledés

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Total @1 sampel yang diambil.
The output is limited to '@1'.=Keluaran dibatasi ke '@1'. The output is limited to '@1'.=Keluaran dibatasi ke '@1'.
Saving of profile failed: @1=Penyimpanan profil gagal: @1 Saving of profile failed: @1=Penyimpanan profil gagal: @1
Profile saved to @1=Profil disimpan ke @1 Profile saved to @1=Profil disimpan ke @1
You died=Anda mati
Respawn=Bangkit kembali

@ -245,3 +245,5 @@ A total of @1 sample(s) were taken.=Son stati ottenuti campioni per un totale di
The output is limited to '@1'.=L'output è limitato a '@1'. The output is limited to '@1'.=L'output è limitato a '@1'.
Saving of profile failed: @1=Errore nel salvare il profilo: @1 Saving of profile failed: @1=Errore nel salvare il profilo: @1
Profile saved to @1=Profilo salvato in @1 Profile saved to @1=Profilo salvato in @1
You died=Sei morto
Respawn=Rinasci

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=死んでしまった
Respawn=リスポーン

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=.i do morsi
Respawn=tolcanci

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Panjenengan pejah
Respawn=Bangkit Malilh

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=사망했습니다
Respawn=리스폰

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Кулінныд
Respawn=Ловзьыны

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Сиз өлдүңүз.
Respawn=Кайтадан жаралуу

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Jūs numirėte
Respawn=Prisikelti

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Jūs nomirāt
Respawn=Atdzīvoties

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=尔死矣
Respawn=复生

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Та үхсэн
Respawn=Дахин төрөх

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=तू मेलास
Respawn=पुनर्जन्म

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Sebanyak @1 sampel telah diambil secara kese
The output is limited to '@1'.=Output dihadkan kepada '@1'. The output is limited to '@1'.=Output dihadkan kepada '@1'.
Saving of profile failed: @1=Penyimpanan profil telah gagal: @1 Saving of profile failed: @1=Penyimpanan profil telah gagal: @1
Profile saved to @1=Profil telah disimpan ke @1 Profile saved to @1=Profil telah disimpan ke @1
You died=Anda telah meninggal
Respawn=Jelma semula

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Du døde
Respawn=Gjenoppstå

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Je bent gestorven
Respawn=Herboren worden

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Du døydde
Respawn=Kom opp att

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Setz mòrt·a
Respawn=Tornar

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Nie żyjesz
Respawn=Wróć do gry

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Você morreu
Respawn=Renascer

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Um total de @1 amostra(s) foi coletada.
The output is limited to '@1'.=A saída é limitada a '@1'. The output is limited to '@1'.=A saída é limitada a '@1'.
Saving of profile failed: @1=Falha ao salvar o perfil: @1 Saving of profile failed: @1=Falha ao salvar o perfil: @1
Profile saved to @1=Perfil salvo em @1 Profile saved to @1=Perfil salvo em @1
You died=Você morreu
Respawn=Reviver

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Ai murit
Respawn=Reînviere

@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Всего было взято @1 образ
The output is limited to '@1'.=Вывод ограничен значением '@1'. The output is limited to '@1'.=Вывод ограничен значением '@1'.
Saving of profile failed: @1=Не удалось сохранить данные профилирования: @1 Saving of profile failed: @1=Не удалось сохранить данные профилирования: @1
Profile saved to @1=Данные профилирования сохранены в @1 Profile saved to @1=Данные профилирования сохранены в @1
You died=Вы умерли
Respawn=Возродиться

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Zomrel si
Respawn=Oživiť

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Umrl si
Respawn=Ponovno oživi

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Умро си
Respawn=Врати се у живот

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Umro/la si.
Respawn=Vrati se u zivot

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Du dog
Respawn=Återuppstå

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Umekufa.
Respawn=Respawn

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=sina moli
Respawn=o kama sin

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Öldün
Respawn=Yeniden Canlan

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Сез үлдегез
Respawn=Тергезелергә

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Ви загинули
Respawn=Відродитися

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=Bạn đã bị chết
Respawn=Hồi sinh

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=您已死亡
Respawn=重生

@ -0,0 +1,3 @@
# textdomain: __builtin
You died=您已死亡
Respawn=重生

@ -338,8 +338,6 @@ Call these functions only at load time!
is checked to see if the command exists, but after the input is parsed. is checked to see if the command exists, but after the input is parsed.
* Return `true` to mark the command as handled, which means that the default * Return `true` to mark the command as handled, which means that the default
handlers will be prevented. handlers will be prevented.
* `minetest.register_on_death(function())`
* Called when the local player dies
* `minetest.register_on_hp_modification(function(hp))` * `minetest.register_on_hp_modification(function(hp))`
* Called when server modified player's HP * Called when server modified player's HP
* `minetest.register_on_damage_taken(function(hp))` * `minetest.register_on_damage_taken(function(hp))`
@ -487,8 +485,6 @@ Call these functions only at load time!
* Returns `false` if the client is already disconnecting otherwise returns `true`. * Returns `false` if the client is already disconnecting otherwise returns `true`.
* `minetest.get_server_info()` * `minetest.get_server_info()`
* Returns [server info](#server-info). * Returns [server info](#server-info).
* `minetest.send_respawn()`
* Sends a respawn request to the server.
### Storage API ### Storage API
* `minetest.get_mod_storage()`: * `minetest.get_mod_storage()`:

@ -5869,6 +5869,7 @@ Call these functions only at load time!
* `minetest.register_on_dieplayer(function(ObjectRef, reason))` * `minetest.register_on_dieplayer(function(ObjectRef, reason))`
* Called when a player dies * Called when a player dies
* `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange * `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange
* For customizing the death screen, see `minetest.show_death_screen`.
* `minetest.register_on_respawnplayer(function(ObjectRef))` * `minetest.register_on_respawnplayer(function(ObjectRef))`
* Called when player is to be respawned * Called when player is to be respawned
* Called _before_ repositioning of player occurs * Called _before_ repositioning of player occurs
@ -6573,6 +6574,13 @@ Formspec
* `"INV"`: something failed * `"INV"`: something failed
* `"CHG"`: has been changed * `"CHG"`: has been changed
* `"VAL"`: not changed * `"VAL"`: not changed
* `minetest.show_death_screen(player, reason)`
* Called when the death screen should be shown.
* `player` is an ObjectRef, `reason` is a PlayerHPChangeReason table or nil.
* By default, this shows a simple formspec with the option to respawn.
Respawning is done via `ObjectRef:respawn`.
* You can override this to show a custom death screen.
* For general death handling, use `minetest.register_on_dieplayer` instead.
Item handling Item handling
------------- -------------

@ -1359,9 +1359,9 @@ void Client::sendDamage(u16 damage)
Send(&pkt); Send(&pkt);
} }
void Client::sendRespawn() void Client::sendRespawnLegacy()
{ {
NetworkPacket pkt(TOSERVER_RESPAWN, 0); NetworkPacket pkt(TOSERVER_RESPAWN_LEGACY, 0);
Send(&pkt); Send(&pkt);
} }

@ -194,7 +194,7 @@ public:
void handleCommand_Breath(NetworkPacket* pkt); void handleCommand_Breath(NetworkPacket* pkt);
void handleCommand_MovePlayer(NetworkPacket* pkt); void handleCommand_MovePlayer(NetworkPacket* pkt);
void handleCommand_MovePlayerRel(NetworkPacket* pkt); void handleCommand_MovePlayerRel(NetworkPacket* pkt);
void handleCommand_DeathScreen(NetworkPacket* pkt); void handleCommand_DeathScreenLegacy(NetworkPacket* pkt);
void handleCommand_AnnounceMedia(NetworkPacket* pkt); void handleCommand_AnnounceMedia(NetworkPacket* pkt);
void handleCommand_Media(NetworkPacket* pkt); void handleCommand_Media(NetworkPacket* pkt);
void handleCommand_NodeDef(NetworkPacket* pkt); void handleCommand_NodeDef(NetworkPacket* pkt);
@ -249,7 +249,7 @@ public:
void sendChangePassword(const std::string &oldpassword, void sendChangePassword(const std::string &oldpassword,
const std::string &newpassword); const std::string &newpassword);
void sendDamage(u16 damage); void sendDamage(u16 damage);
void sendRespawn(); void sendRespawnLegacy();
void sendReady(); void sendReady();
void sendHaveMedia(const std::vector<u32> &tokens); void sendHaveMedia(const std::vector<u32> &tokens);
void sendUpdateClientInfo(const ClientDynamicInfo &info); void sendUpdateClientInfo(const ClientDynamicInfo &info);

@ -35,7 +35,7 @@ enum ClientEventType : u8
CE_NONE, CE_NONE,
CE_PLAYER_DAMAGE, CE_PLAYER_DAMAGE,
CE_PLAYER_FORCE_MOVE, CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN, CE_DEATHSCREEN_LEGACY,
CE_SHOW_FORMSPEC, CE_SHOW_FORMSPEC,
CE_SHOW_LOCAL_FORMSPEC, CE_SHOW_LOCAL_FORMSPEC,
CE_SPAWN_PARTICLE, CE_SPAWN_PARTICLE,
@ -96,13 +96,6 @@ struct ClientEvent
f32 yaw; f32 yaw;
} player_force_move; } player_force_move;
struct struct
{
bool set_camera_point_target;
f32 camera_point_target_x;
f32 camera_point_target_y;
f32 camera_point_target_z;
} deathscreen;
struct
{ {
std::string *formspec; std::string *formspec;
std::string *formname; std::string *formname;

@ -186,7 +186,7 @@ struct LocalFormspecHandler : public TextDest
assert(m_client != nullptr); assert(m_client != nullptr);
if (fields.find("quit") != fields.end()) if (fields.find("quit") != fields.end())
m_client->sendRespawn(); m_client->sendRespawnLegacy();
return; return;
} }
@ -837,7 +837,7 @@ private:
bool disable_camera_update = false; bool disable_camera_update = false;
}; };
void showDeathFormspec(); void showDeathFormspecLegacy();
void showPauseMenu(); void showPauseMenu();
void pauseAnimation(); void pauseAnimation();
@ -847,7 +847,7 @@ private:
void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_HandleParticleEvent(ClientEvent *event, void handleClientEvent_HandleParticleEvent(ClientEvent *event,
@ -2854,7 +2854,7 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = {
{&Game::handleClientEvent_None}, {&Game::handleClientEvent_None},
{&Game::handleClientEvent_PlayerDamage}, {&Game::handleClientEvent_PlayerDamage},
{&Game::handleClientEvent_PlayerForceMove}, {&Game::handleClientEvent_PlayerForceMove},
{&Game::handleClientEvent_Deathscreen}, {&Game::handleClientEvent_DeathscreenLegacy},
{&Game::handleClientEvent_ShowFormSpec}, {&Game::handleClientEvent_ShowFormSpec},
{&Game::handleClientEvent_ShowLocalFormSpec}, {&Game::handleClientEvent_ShowLocalFormSpec},
{&Game::handleClientEvent_HandleParticleEvent}, {&Game::handleClientEvent_HandleParticleEvent},
@ -2910,20 +2910,9 @@ void Game::handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientati
cam->camera_pitch = event->player_force_move.pitch; cam->camera_pitch = event->player_force_move.pitch;
} }
void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam) void Game::handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam)
{ {
// If client scripting is enabled, deathscreen is handled by CSM code in showDeathFormspecLegacy();
// builtin/client/init.lua
if (client->modsLoaded())
client->getScript()->on_death();
else
showDeathFormspec();
/* Handle visualization */
LocalPlayer *player = client->getEnv().getLocalPlayer();
runData.damage_flash = 0;
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
} }
void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam) void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam)
@ -4468,7 +4457,7 @@ void Game::readSettings()
****************************************************************************/ ****************************************************************************/
/****************************************************************************/ /****************************************************************************/
void Game::showDeathFormspec() void Game::showDeathFormspecLegacy()
{ {
static std::string formspec_str = static std::string formspec_str =
std::string("formspec_version[1]") + std::string("formspec_version[1]") +

@ -81,7 +81,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_MOVE_PLAYER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayer }, // 0x34 { "TOCLIENT_MOVE_PLAYER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayer }, // 0x34
{ "TOCLIENT_ACCESS_DENIED_LEGACY", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AccessDenied }, // 0x35 { "TOCLIENT_ACCESS_DENIED_LEGACY", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AccessDenied }, // 0x35
{ "TOCLIENT_FOV", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Fov }, // 0x36 { "TOCLIENT_FOV", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Fov }, // 0x36
{ "TOCLIENT_DEATHSCREEN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreen }, // 0x37 { "TOCLIENT_DEATHSCREEN_LEGACY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreenLegacy }, // 0x37
{ "TOCLIENT_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Media }, // 0x38 { "TOCLIENT_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Media }, // 0x38
null_command_handler, null_command_handler,
{ "TOCLIENT_NODEDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_NodeDef }, // 0x3a { "TOCLIENT_NODEDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_NodeDef }, // 0x3a
@ -198,7 +198,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
{ "TOSERVER_DAMAGE", 0, true }, // 0x35 { "TOSERVER_DAMAGE", 0, true }, // 0x35
null_command_factory, // 0x36 null_command_factory, // 0x36
{ "TOSERVER_PLAYERITEM", 0, true }, // 0x37 { "TOSERVER_PLAYERITEM", 0, true }, // 0x37
{ "TOSERVER_RESPAWN", 0, true }, // 0x38 { "TOSERVER_RESPAWN_LEGACY", 0, true }, // 0x38
{ "TOSERVER_INTERACT", 0, true }, // 0x39 { "TOSERVER_INTERACT", 0, true }, // 0x39
{ "TOSERVER_REMOVED_SOUNDS", 2, true }, // 0x3a { "TOSERVER_REMOVED_SOUNDS", 2, true }, // 0x3a
{ "TOSERVER_NODEMETA_FIELDS", 0, true }, // 0x3b { "TOSERVER_NODEMETA_FIELDS", 0, true }, // 0x3b

@ -653,20 +653,10 @@ void Client::handleCommand_MovePlayerRel(NetworkPacket *pkt)
player->addPosition(added_pos); player->addPosition(added_pos);
} }
void Client::handleCommand_DeathScreen(NetworkPacket* pkt) void Client::handleCommand_DeathScreenLegacy(NetworkPacket* pkt)
{ {
bool set_camera_point_target;
v3f camera_point_target;
*pkt >> set_camera_point_target;
*pkt >> camera_point_target;
ClientEvent *event = new ClientEvent(); ClientEvent *event = new ClientEvent();
event->type = CE_DEATHSCREEN; event->type = CE_DEATHSCREEN_LEGACY;
event->deathscreen.set_camera_point_target = set_camera_point_target;
event->deathscreen.camera_point_target_x = camera_point_target.X;
event->deathscreen.camera_point_target_y = camera_point_target.Y;
event->deathscreen.camera_point_target_z = camera_point_target.Z;
m_client_event_queue.push(event); m_client_event_queue.push(event);
} }

@ -231,6 +231,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Move default hotbar from client-side C++ to server-side builtin Lua Move default hotbar from client-side C++ to server-side builtin Lua
Add shadow tint to Lighting packets Add shadow tint to Lighting packets
Add shadow color to CloudParam packets Add shadow color to CloudParam packets
Move death screen to server and make it a regular formspec
The server no longer triggers the hardcoded client-side death
formspec, but the client still supports it for compatibility with
old servers.
Rename TOCLIENT_DEATHSCREEN to TOCLIENT_DEATHSCREEN_LEGACY
Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY
[scheduled bump for 5.10.0] [scheduled bump for 5.10.0]
*/ */
@ -391,10 +397,10 @@ enum ToClientCommand : u16
f32 transition_time f32 transition_time
*/ */
TOCLIENT_DEATHSCREEN = 0x37, TOCLIENT_DEATHSCREEN_LEGACY = 0x37,
/* /*
u8 bool set camera point target u8 bool unused
v3f1000 camera point target (to point the death cause or whatever) v3f1000 unused
*/ */
TOCLIENT_MEDIA = 0x38, TOCLIENT_MEDIA = 0x38,
@ -1002,10 +1008,7 @@ enum ToServerCommand : u16
[2] u16 item [2] u16 item
*/ */
TOSERVER_RESPAWN = 0x38, TOSERVER_RESPAWN_LEGACY = 0x38,
/*
u16 TOSERVER_RESPAWN
*/
TOSERVER_INTERACT = 0x39, TOSERVER_INTERACT = 0x39,
/* /*

@ -82,7 +82,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
{ "TOSERVER_DAMAGE", TOSERVER_STATE_INGAME, &Server::handleCommand_Damage }, // 0x35 { "TOSERVER_DAMAGE", TOSERVER_STATE_INGAME, &Server::handleCommand_Damage }, // 0x35
null_command_handler, // 0x36 null_command_handler, // 0x36
{ "TOSERVER_PLAYERITEM", TOSERVER_STATE_INGAME, &Server::handleCommand_PlayerItem }, // 0x37 { "TOSERVER_PLAYERITEM", TOSERVER_STATE_INGAME, &Server::handleCommand_PlayerItem }, // 0x37
{ "TOSERVER_RESPAWN", TOSERVER_STATE_INGAME, &Server::handleCommand_Respawn }, // 0x38 null_command_handler, // 0x38
{ "TOSERVER_INTERACT", TOSERVER_STATE_INGAME, &Server::handleCommand_Interact }, // 0x39 { "TOSERVER_INTERACT", TOSERVER_STATE_INGAME, &Server::handleCommand_Interact }, // 0x39
{ "TOSERVER_REMOVED_SOUNDS", TOSERVER_STATE_INGAME, &Server::handleCommand_RemovedSounds }, // 0x3a { "TOSERVER_REMOVED_SOUNDS", TOSERVER_STATE_INGAME, &Server::handleCommand_RemovedSounds }, // 0x3a
{ "TOSERVER_NODEMETA_FIELDS", TOSERVER_STATE_INGAME, &Server::handleCommand_NodeMetaFields }, // 0x3b { "TOSERVER_NODEMETA_FIELDS", TOSERVER_STATE_INGAME, &Server::handleCommand_NodeMetaFields }, // 0x3b
@ -181,7 +181,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_MOVE_PLAYER", 0, true }, // 0x34 { "TOCLIENT_MOVE_PLAYER", 0, true }, // 0x34
null_command_factory, // 0x35 null_command_factory, // 0x35
{ "TOCLIENT_FOV", 0, true }, // 0x36 { "TOCLIENT_FOV", 0, true }, // 0x36
{ "TOCLIENT_DEATHSCREEN", 0, true }, // 0x37 null_command_factory, // 0x37
{ "TOCLIENT_MEDIA", 2, true }, // 0x38 { "TOCLIENT_MEDIA", 2, true }, // 0x38
null_command_factory, // 0x39 null_command_factory, // 0x39
{ "TOCLIENT_NODEDEF", 0, true }, // 0x3A { "TOCLIENT_NODEDEF", 0, true }, // 0x3A

@ -858,33 +858,6 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
playersao->getPlayer()->setWieldIndex(item); playersao->getPlayer()->setWieldIndex(item);
} }
void Server::handleCommand_Respawn(NetworkPacket* pkt)
{
session_t peer_id = pkt->getPeerId();
RemotePlayer *player = m_env->getPlayer(peer_id);
if (player == NULL) {
errorstream <<
"Server::ProcessData(): Canceling: No player for peer_id=" <<
peer_id << " disconnecting peer!" << std::endl;
DisconnectPeer(peer_id);
return;
}
PlayerSAO *playersao = player->getPlayerSAO();
assert(playersao);
if (!playersao->isDead())
return;
RespawnPlayer(peer_id);
actionstream << player->getName() << " respawns at "
<< (playersao->getBasePosition() / BS) << std::endl;
// ActiveObject is added to environment in AsyncRunStep after
// the previous addition has been successfully removed
}
bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what) bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what)
{ {
ItemStack selected_item, hand_item; ItemStack selected_item, hand_item;

@ -125,21 +125,6 @@ void ScriptApiClient::on_hp_modification(int32_t newhp)
} }
} }
void ScriptApiClient::on_death()
{
SCRIPTAPI_PRECHECKHEADER
// Get registered shutdown hooks
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_death");
// Call callbacks
try {
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
getClient()->setFatalError(e);
}
}
void ScriptApiClient::environment_step(float dtime) void ScriptApiClient::environment_step(float dtime)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER

@ -49,7 +49,6 @@ public:
void on_damage_taken(int32_t damage_amount); void on_damage_taken(int32_t damage_amount);
void on_hp_modification(int32_t newhp); void on_hp_modification(int32_t newhp);
void on_death();
void environment_step(float dtime); void environment_step(float dtime);
void on_formspec_input(const std::string &formname, const StringMap &fields); void on_formspec_input(const std::string &formname, const StringMap &fields);

@ -157,13 +157,6 @@ int ModApiClient::l_show_formspec(lua_State *L)
return 1; return 1;
} }
// send_respawn()
int ModApiClient::l_send_respawn(lua_State *L)
{
getClient(L)->sendRespawn();
return 0;
}
// disconnect() // disconnect()
int ModApiClient::l_disconnect(lua_State *L) int ModApiClient::l_disconnect(lua_State *L)
{ {
@ -348,7 +341,6 @@ void ModApiClient::Initialize(lua_State *L, int top)
API_FCT(clear_out_chat_queue); API_FCT(clear_out_chat_queue);
API_FCT(get_player_names); API_FCT(get_player_names);
API_FCT(show_formspec); API_FCT(show_formspec);
API_FCT(send_respawn);
API_FCT(gettext); API_FCT(gettext);
API_FCT(get_node_or_nil); API_FCT(get_node_or_nil);
API_FCT(disconnect); API_FCT(disconnect);

@ -51,9 +51,6 @@ private:
// show_formspec(name, formspec) // show_formspec(name, formspec)
static int l_show_formspec(lua_State *L); static int l_show_formspec(lua_State *L);
// send_respawn()
static int l_send_respawn(lua_State *L);
// disconnect() // disconnect()
static int l_disconnect(lua_State *L); static int l_disconnect(lua_State *L);

@ -2693,11 +2693,11 @@ int ObjectRef::l_respawn(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkObject<ObjectRef>(L, 1); ObjectRef *ref = checkObject<ObjectRef>(L, 1);
RemotePlayer *player = getplayer(ref); auto *psao = getplayersao(ref);
if (player == nullptr) if (psao == nullptr)
return 0; return 0;
getServer(L)->RespawnPlayer(player->getPeerId()); psao->respawn();
lua_pushboolean(L, true); lua_pushboolean(L, true);
return 1; return 1;
} }

@ -1159,10 +1159,6 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
// Send HP // Send HP
SendPlayerHP(playersao, false); SendPlayerHP(playersao, false);
// Send death screen
if (playersao->isDead())
SendDeathscreen(peer_id, false, v3f(0,0,0));
// Send Breath // Send Breath
SendPlayerBreath(playersao); SendPlayerBreath(playersao);
@ -1405,14 +1401,6 @@ void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
Send(&pkt); Send(&pkt);
} }
void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
v3f camera_point_target)
{
NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
pkt << set_camera_point_target << camera_point_target;
Send(&pkt);
}
void Server::SendItemDef(session_t peer_id, void Server::SendItemDef(session_t peer_id,
IItemDefManager *itemdef, u16 protocol_version) IItemDefManager *itemdef, u16 protocol_version)
{ {
@ -2803,32 +2791,8 @@ void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason
// Trigger scripted stuff // Trigger scripted stuff
m_script->on_dieplayer(playersao, reason); m_script->on_dieplayer(playersao, reason);
SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
} }
void Server::RespawnPlayer(session_t peer_id)
{
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
infostream << "Server::RespawnPlayer(): Player "
<< playersao->getPlayer()->getName()
<< " respawns" << std::endl;
const auto *prop = playersao->accessObjectProperties();
playersao->setHP(prop->hp_max,
PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
playersao->setBreath(prop->breath_max);
bool repositioned = m_script->on_respawnplayer(playersao);
if (!repositioned) {
// setPos will send the new position to client
playersao->setPos(findSpawnPos());
}
}
void Server::DenySudoAccess(session_t peer_id) void Server::DenySudoAccess(session_t peer_id)
{ {
NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id); NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);

@ -193,7 +193,6 @@ public:
void handleCommand_ChatMessage(NetworkPacket* pkt); void handleCommand_ChatMessage(NetworkPacket* pkt);
void handleCommand_Damage(NetworkPacket* pkt); void handleCommand_Damage(NetworkPacket* pkt);
void handleCommand_PlayerItem(NetworkPacket* pkt); void handleCommand_PlayerItem(NetworkPacket* pkt);
void handleCommand_Respawn(NetworkPacket* pkt);
void handleCommand_Interact(NetworkPacket* pkt); void handleCommand_Interact(NetworkPacket* pkt);
void handleCommand_RemovedSounds(NetworkPacket* pkt); void handleCommand_RemovedSounds(NetworkPacket* pkt);
void handleCommand_NodeMetaFields(NetworkPacket* pkt); void handleCommand_NodeMetaFields(NetworkPacket* pkt);
@ -356,8 +355,6 @@ public:
void setLighting(RemotePlayer *player, const Lighting &lighting); void setLighting(RemotePlayer *player, const Lighting &lighting);
void RespawnPlayer(session_t peer_id);
/* con::PeerHandler implementation. */ /* con::PeerHandler implementation. */
void peerAdded(con::IPeer *peer); void peerAdded(con::IPeer *peer);
void deletingPeer(con::IPeer *peer, bool timeout); void deletingPeer(con::IPeer *peer, bool timeout);
@ -486,8 +483,6 @@ private:
void SendBreath(session_t peer_id, u16 breath); void SendBreath(session_t peer_id, u16 breath);
void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, void SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
std::string_view custom_reason, bool reconnect = false); std::string_view custom_reason, bool reconnect = false);
void SendDeathscreen(session_t peer_id, bool set_camera_point_target,
v3f camera_point_target);
void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version); void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version);
void SendNodeDef(session_t peer_id, const NodeDefManager *nodedef, void SendNodeDef(session_t peer_id, const NodeDefManager *nodedef,
u16 protocol_version); u16 protocol_version);

@ -126,7 +126,7 @@ class EmergeManager;
| TOCLIENT_INVENTORY | | | | | TOCLIENT_INVENTORY | | | |
| TOCLIENT_HP (opt) | \-----------------/ | | TOCLIENT_HP (opt) | \-----------------/ |
| TOCLIENT_BREATH | | | TOCLIENT_BREATH | |
| TOCLIENT_DEATHSCREEN | | | TOCLIENT_DEATHSCREEN_LEGACY | |
+-----------------------------+ | +-----------------------------+ |
| | | |
v | v |

@ -558,6 +558,21 @@ void PlayerSAO::setBreath(const u16 breath, bool send)
m_env->getGameDef()->SendPlayerBreath(this); m_env->getGameDef()->SendPlayerBreath(this);
} }
void PlayerSAO::respawn()
{
infostream << "PlayerSAO::respawn(): Player " << m_player->getName()
<< " respawns" << std::endl;
setHP(m_prop.hp_max, PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
setBreath(m_prop.breath_max);
bool repositioned = m_env->getScriptIface()->on_respawnplayer(this);
if (!repositioned) {
// setPos will send the new position to client
setPos(m_env->getGameDef()->findSpawnPos());
}
}
Inventory *PlayerSAO::getInventory() const Inventory *PlayerSAO::getInventory() const
{ {
return m_player ? &m_player->inventory : nullptr; return m_player ? &m_player->inventory : nullptr;

@ -124,6 +124,7 @@ public:
void setHPRaw(u16 hp) { m_hp = hp; } void setHPRaw(u16 hp) { m_hp = hp; }
u16 getBreath() const { return m_breath; } u16 getBreath() const { return m_breath; }
void setBreath(const u16 breath, bool send = true); void setBreath(const u16 breath, bool send = true);
void respawn();
/* /*
Inventory interface Inventory interface