The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
replay_controller.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2015 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15#include "replay_controller.hpp"
16
17#include "log.hpp"
18#include "replay.hpp"
19#include "resources.hpp"
21
22static lg::log_domain log_engine("engine");
23#define DBG_NG LOG_STREAM(debug, log_engine)
24
25static lg::log_domain log_replay("replay");
26#define DBG_REPLAY LOG_STREAM(debug, log_replay)
27#define LOG_REPLAY LOG_STREAM(info, log_replay)
28#define ERR_REPLAY LOG_STREAM(err, log_replay)
29
30namespace
31{
32struct replay_play_nostop : public replay_controller::replay_stop_condition
33{
34 replay_play_nostop() {}
35 virtual bool should_stop() { return false; }
36};
37
38struct replay_play_moves : public replay_controller::replay_stop_condition
39{
40 int moves_todo_;
41 replay_play_moves(int moves_todo) : moves_todo_(moves_todo) {}
42 virtual void move_done() { --moves_todo_; }
43 virtual bool should_stop() { return moves_todo_ == 0; }
44};
45
46struct replay_play_turn : public replay_controller::replay_stop_condition
47{
48 int turn_begin_;
49 int turn_current_;
50 replay_play_turn(int turn_begin) : turn_begin_(turn_begin), turn_current_(turn_begin) {}
51 virtual void new_side_turn(int , int turn) { turn_current_ = turn; }
52 virtual bool should_stop() { return turn_begin_ != turn_current_; }
53};
54
55struct replay_play_side : public replay_controller::replay_stop_condition
56{
57 bool next_side_;
58 replay_play_side() : next_side_(false) {}
59 virtual void new_side_turn(int , int) { next_side_ = true; }
60 virtual bool should_stop() { return next_side_; }
61};
62}
63
64replay_controller::replay_controller(play_controller& controller, bool control_view, const std::shared_ptr<config>& reset_state, const std::function<void()>& on_end_replay)
65 : controller_(controller)
66 , stop_condition_(new replay_stop_condition())
67 , disabler_()
68 , vision_()
69 , reset_state_(reset_state)
70 , on_end_replay_(on_end_replay)
71 , return_to_play_side_(false)
72{
73 if(control_view) {
75 }
78}
88{
89 const config& theme_cfg = theme::get_theme_config(controller_.theme());
90 if (const auto res = theme_cfg.optional_child("resolution"))
91 {
92 if (const auto replay_theme_cfg = res->optional_child("replay")) {
93 controller_.get_display().get_theme().modify(replay_theme_cfg.value());
94 }
95 }
96}
97
103
109
111{
112 stop_condition_.reset(new replay_play_side());
114}
115
117{
118 stop_condition_.reset(new replay_play_moves(1));
120}
121
122//move all sides till stop/end
124{
125 stop_condition_.reset(new replay_play_nostop());
127}
128
133
138
139void replay_controller::handle_generic_event(const std::string& name)
140{
141 // this is only attached to one event - the theme_reset_event
142 if(name == "theme_reset") {
144 }
145 if(std::shared_ptr<gui::button> skip_animation_button = controller_.get_display().find_action_button("skip-animation")) {
146 skip_animation_button->set_check(controller_.is_skipping_replay());
147 }
148}
149
154
156{
158 while(!return_to_play_side_ && !static_cast<playsingle_controller&>(controller_).get_player_type_changed())
159 {
160 if(!stop_condition_->should_stop())
161 {
162 if(resources::recorder->at_end()) {
163 //Gather more replay data
165 }
166 else {
167 REPLAY_RETURN res = do_replay(true);
169 return;
170 }
171 if(res == REPLAY_FOUND_END_TURN) {
172 return;
173 }
174 stop_condition_->move_done();
175 if(res == REPLAY_FOUND_INIT_TURN)
176 {
178 }
179 }
181
182 // Update the buttons once, on the transition from not-stopped to stopped.
183 if(stop_condition_->should_stop()) {
185 }
186 }
187 else
188 {
189 // Don't move the update_enabled_buttons() call here. This play_slice() should block
190 // until the next event occurs, but on X11/Linux update_enabled_buttons() seems to put
191 // an event in the queue, turning this into a busy loop.
193 }
194 }
195 return;
196}
198{
199 switch(cmd.hotkey_command) {
201 return true;
205 return is_controlling_view();
206 //commands we only can do before the end of the replay
208 return !recorder_at_end();
213 //we have one events_disabler when starting the replay_controller and a second when entering the synced context.
214 return should_stop() && (events::commands_disabled <= 1 ) && !recorder_at_end();
217 default:
218 assert(false);
219 return false;
220 }
221}
222
228
234
240
247
249{
250 assert(vision_);
252 if(viewing_side_num != 0) {
253 controller_.update_gui_to_player(viewing_side_num - 1, *vision_ == SHOW_ALL);
254 }
255}
256
258{
259 return vision_ == SHOW_ALL;
260}
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
virtual void play_slice()
std::shared_ptr< gui::button > find_action_button(const std::string &id)
Retrieves a pointer to a theme UI button.
Definition display.cpp:768
void invalidate_all()
Function to invalidate all tiles.
Definition display.cpp:2920
theme & get_theme()
Definition display.hpp:382
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition display.cpp:2105
virtual bool attach_handler(observer *obs)
virtual bool detach_handler(observer *obs)
tod_manager tod_manager_
virtual int find_viewing_side() const =0
returns 0 if no such team was found.
bool is_regular_game_end() const
game_display & get_display() override
Get a reference to a display member a derived class uses.
std::string theme() const
int current_side() const
Returns the number of the side whose turn it is.
bool is_skipping_replay() const
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
game_state & gamestate()
replay_controller(play_controller &controller, bool control_view, const std::shared_ptr< config > &reset_state, const std::function< void()> &on_end_replay=nop)
play_controller & controller_
void handle_generic_event(const std::string &name) override
bool is_controlling_view() const
utils::optional< REPLAY_VISION > vision_
std::function< void()> on_end_replay_
Called when there are no more moves in the [replay] to process.
std::unique_ptr< replay_stop_condition > stop_condition_
bool can_execute_command(const hotkey::ui_command &cmd) const
bool allow_reset_replay() const
bool return_to_play_side_
Used by unit tests.
void update_enabled_buttons()
Refresh the states of the replay-control buttons, this will cause the hotkey framework to query can_e...
bool at_end() const
Definition replay.cpp:631
static NOT_DANGLING const config & get_theme_config(const std::string &id)
Returns the saved config for the theme with the given ID.
Definition theme.cpp:1017
void modify(const config &cfg)
Definition theme.cpp:833
events::generic_event & theme_reset_event()
Definition theme.hpp:284
int turn() const
Standard logging facilities (interface).
@ HOTKEY_REPLAY_NEXT_TURN
@ HOTKEY_REPLAY_SHOW_EVERYTHING
@ HOTKEY_REPLAY_SHOW_TEAM1
@ HOTKEY_REPLAY_NEXT_SIDE
@ HOTKEY_REPLAY_NEXT_MOVE
@ HOTKEY_REPLAY_RESET
@ HOTKEY_REPLAY_SKIP_ANIMATION
@ HOTKEY_REPLAY_SHOW_EACH
replay * recorder
Definition resources.cpp:28
REPLAY_RETURN do_replay(bool one_move)
Definition replay.cpp:692
Replay control code.
REPLAY_RETURN
Definition replay.hpp:172
@ REPLAY_FOUND_INIT_TURN
Definition replay.hpp:176
@ REPLAY_FOUND_END_TURN
Definition replay.hpp:175
static lg::log_domain log_engine("engine")
static lg::log_domain log_replay("replay")
Used as the main parameter for can_execute_command/do_execute_command These functions are used to exe...
hotkey::HOTKEY_COMMAND hotkey_command
The hotkey::HOTKEY_COMMAND associated with this action, HOTKEY_NULL for actions that don't allow hotk...