mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-26 16:53:17 +00:00

LUAI_TRY() is an internal part of Lua that may not exist forever, and reliance on overriding it prevents the use of system copies of Lua. Document in lua_jailbreak_exception this requirement to call this->store() in derived class constructors. Also, count the luaW_pcall_internal() recursion depth and store and rethrow jailbreak exceptions until the recursion depth reaches 0, because: 1. luaW_pcall_internal() sometimes runs recursively (C++ calls Lua calls C++ calls Lua calls C++), so the middle C++ layer needs to rethrow exceptions instead of clearing them. LUAI_TRY() previously stored them each time, but now lua_jailbreak_exception::rethrow() needs to know when not to clear(). 2. Jailbreak exceptions can be thrown while no Lua code is running. Now that constructors store() all exceptions instead of LUAI_TRY() storing only those caught by Lua, lua_jailbreak_exception::store() needs to know when not to store them. Otherwise, for example, leaving a game to return to the menu while no Lua code is running throws and needlessly stores an exception that isn't cleared, with two possible effects: a. If another jailbreak exception is thrown and the constructor tries to store it, we abort from assert() because one is already stored. b. Otherwise, if luaW_pcall_internal() runs without a new jailbreak exception being thrown, the stored one is rethrown and handled a second time (e.g. immediately leaving a new game).
113 lines
3.1 KiB
C++
113 lines
3.1 KiB
C++
/*
|
|
Copyright (C) 2006 - 2024
|
|
by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
|
|
Copyright (C) 2003 by David White <dave@whitevine.net>
|
|
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Contains the exception interfaces used to signal
|
|
* completion of a scenario, campaign or turn.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "level_result.hpp"
|
|
#include "lua_jailbreak_exception.hpp"
|
|
|
|
#include <string>
|
|
#include <exception>
|
|
|
|
class config;
|
|
|
|
/**
|
|
* Exception used to escape form the ai or ui code to playsingle_controller::play_side.
|
|
* Never thrown during replays.
|
|
*/
|
|
class return_to_play_side_exception final : public lua_jailbreak_exception, public std::exception
|
|
{
|
|
public:
|
|
|
|
return_to_play_side_exception()
|
|
: lua_jailbreak_exception()
|
|
, std::exception()
|
|
{
|
|
this->store();
|
|
}
|
|
const char * what() const noexcept { return "return_to_play_side_exception"; }
|
|
private:
|
|
|
|
IMPLEMENT_LUA_JAILBREAK_EXCEPTION(return_to_play_side_exception)
|
|
};
|
|
|
|
class quit_game_exception final
|
|
: public lua_jailbreak_exception
|
|
, public std::exception
|
|
{
|
|
public:
|
|
|
|
quit_game_exception()
|
|
: lua_jailbreak_exception()
|
|
, std::exception()
|
|
{
|
|
this->store();
|
|
}
|
|
const char * what() const noexcept { return "quit_game_exception"; }
|
|
private:
|
|
IMPLEMENT_LUA_JAILBREAK_EXCEPTION(quit_game_exception)
|
|
};
|
|
|
|
/**
|
|
* The non-persistent part of end_level_data
|
|
*/
|
|
struct transient_end_level{
|
|
|
|
transient_end_level();
|
|
|
|
bool carryover_report; /**< Should a summary of the scenario outcome be displayed? */
|
|
bool linger_mode; /**< Should linger mode be invoked? */
|
|
bool reveal_map; /**< Should we reveal map when game is ended? (Multiplayer only) */
|
|
|
|
void write(config& cfg) const;
|
|
};
|
|
|
|
/**
|
|
* Additional information on the game outcome which can be provided by WML.
|
|
*/
|
|
struct end_level_data
|
|
{
|
|
end_level_data();
|
|
|
|
|
|
bool prescenario_save; /**< Should a prescenario be created the next game? */
|
|
bool replay_save; /**< Should a replay save be made? */
|
|
bool proceed_to_next_level; /**< whether to proceed to the next scenario, equals is_victory in sp. We need to save this in saves during linger mode. > */
|
|
bool is_victory;
|
|
std::string test_result; /**< result to use if this is a unit test */
|
|
transient_end_level transient;
|
|
void write(config& cfg) const;
|
|
|
|
void read(const config& cfg);
|
|
|
|
config to_config() const;
|
|
/** Includes the transient data */
|
|
config to_config_full() const;
|
|
};
|
|
inline void throw_quit_game_exception()
|
|
{
|
|
// Distinguish 'Quit' from 'Regular' end_level_exceptions to solve the following problem:
|
|
// If a player quits the game during an event after an [endlevel] occurs, the game won't
|
|
// Quit but continue with the [endlevel] instead.
|
|
throw quit_game_exception();
|
|
}
|