diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 3cee3ead..fa7fceeb 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -8,14 +8,15 @@ #include #include -#include "Loggers.hh" -#include "Server.hh" -#include "ProxyServer.hh" -#include "Lobby.hh" #include "Client.hh" +#include "Lobby.hh" +#include "Loggers.hh" +#include "ProxyServer.hh" +#include "ReceiveCommands.hh" #include "SendCommands.hh" -#include "Text.hh" +#include "Server.hh" #include "StaticGameData.hh" +#include "Text.hh" using namespace std; @@ -409,7 +410,7 @@ static void server_command_saverec(shared_ptr, shared_ptr l, l->prev_battle_record.reset(); } -static void server_command_playrec(shared_ptr, shared_ptr l, +static void server_command_playrec(shared_ptr s, shared_ptr l, shared_ptr c, const std::u16string& args) { if (!(c->flags & Client::Flag::IS_EPISODE_3)) { send_text_message(c, u"$C4This command can\nonly be used on\nEpisode 3"); @@ -420,19 +421,20 @@ static void server_command_playrec(shared_ptr, shared_ptr l, return; } - if (l->is_game() && (l->flags & Lobby::Flag::EPISODE_3_ONLY) && (l->flags & Lobby::Flag::IS_SPECTATOR_TEAM) && l->battle_player) { - l->flags |= Lobby::Flag::BATTLE_IN_PROGRESS; + if (l->battle_player) { l->battle_player->start(); - - } else if (args.empty()) { - c->next_game_battle_record.reset(); - send_text_message(c, u"$C6Replay state\ncleared"); - } else { - string filename = "system/ep3/battle-records/" + encode_sjis(args) + ".mzrd"; - string data = load_file(filename); - c->next_game_battle_record.reset(new Episode3::BattleRecord(data)); - send_text_message(c, u"$C6Replay state set"); + uint32_t flags = Lobby::Flag::NON_V1_ONLY | Lobby::Flag::EPISODE_3_ONLY | Lobby::Flag::IS_SPECTATOR_TEAM; + string filename = encode_sjis(args); + if (filename[0] == '!') { + flags |= Lobby::Flag::START_BATTLE_PLAYER_IMMEDIATELY; + filename = filename.substr(1); + } + string data = load_file("system/ep3/battle-records/" + filename + ".mzrd"); + shared_ptr record(new Episode3::BattleRecord(data)); + shared_ptr battle_player( + new Episode3::BattleRecordPlayer(record, s->game_server->get_base())); + auto game = create_game_generic(s, c, args.c_str(), u"", 0xFF, 0, flags, battle_player); } } diff --git a/src/Client.hh b/src/Client.hh index e88d4d10..ca3d890c 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -125,7 +125,6 @@ struct Client { bool can_chat; std::string pending_bb_save_username; uint8_t pending_bb_save_player_index; - std::shared_ptr next_game_battle_record; bool proxy_block_events; bool proxy_block_function_calls; diff --git a/src/Episode3/BattleRecord.cc b/src/Episode3/BattleRecord.cc index 759edb76..4d8d2c94 100644 --- a/src/Episode3/BattleRecord.cc +++ b/src/Episode3/BattleRecord.cc @@ -283,22 +283,26 @@ void BattleRecord::set_battle_end_timestamp() { BattleRecordPlayer::BattleRecordPlayer( shared_ptr rec, - shared_ptr base, - shared_ptr l) + shared_ptr base) : record(rec), event_it(this->record->events.begin()), play_start_timestamp(0), base(base), - lobby(l), next_command_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &BattleRecordPlayer::dispatch_schedule_events, this), event_free) { } shared_ptr BattleRecordPlayer::get_record() const { return this->record; } +void BattleRecordPlayer::set_lobby(std::shared_ptr l) { + this->lobby = l; +} + void BattleRecordPlayer::start() { - this->play_start_timestamp = now(); - this->schedule_events(); + if (this->play_start_timestamp == 0) { + this->play_start_timestamp = now(); + this->schedule_events(); + } } void BattleRecordPlayer::dispatch_schedule_events( @@ -348,10 +352,10 @@ void BattleRecordPlayer::schedule_events() { // This should have been handled before the lobby was even created break; case BattleRecord::Event::Type::BATTLE_COMMAND: - send_command(l, 0xC9, 0x00, ev.data); + send_command(l, (ev.data.size() >= 0x400) ? 0x6C : 0xC9, 0x00, ev.data); break; case BattleRecord::Event::Type::GAME_COMMAND: - send_command(l, 0x60, 0x00, ev.data); + send_command(l, (ev.data.size() >= 0x400) ? 0x6C : 0x60, 0x00, ev.data); break; case BattleRecord::Event::Type::EP3_GAME_COMMAND: send_command(l, 0xCB, 0x00, ev.data); diff --git a/src/Episode3/BattleRecord.hh b/src/Episode3/BattleRecord.hh index 5bfafd22..be7aa39b 100644 --- a/src/Episode3/BattleRecord.hh +++ b/src/Episode3/BattleRecord.hh @@ -98,11 +98,12 @@ class BattleRecordPlayer { public: BattleRecordPlayer( std::shared_ptr rec, - std::shared_ptr base, - std::shared_ptr l); + std::shared_ptr base); ~BattleRecordPlayer() = default; std::shared_ptr get_record() const; + + void set_lobby(std::shared_ptr l); void start(); private: diff --git a/src/Lobby.hh b/src/Lobby.hh index e27360f5..154bf49b 100644 --- a/src/Lobby.hh +++ b/src/Lobby.hh @@ -22,26 +22,27 @@ struct Lobby { enum Flag { - GAME = 0x00000001, - EPISODE_3_ONLY = 0x00000002, - NON_V1_ONLY = 0x00000004, // DC NTE and DCv1 not allowed - PERSISTENT = 0x00000008, + GAME = 0x00000001, + EPISODE_3_ONLY = 0x00000002, + NON_V1_ONLY = 0x00000004, // DC NTE and DCv1 not allowed + PERSISTENT = 0x00000008, // Flags used only for games - CHEATS_ENABLED = 0x00000100, - QUEST_IN_PROGRESS = 0x00000200, - BATTLE_IN_PROGRESS = 0x00000400, - JOINABLE_QUEST_IN_PROGRESS = 0x00000800, - ITEM_TRACKING_ENABLED = 0x00001000, - IS_SPECTATOR_TEAM = 0x00002000, // EPISODE_3_ONLY must also be set - SPECTATORS_FORBIDDEN = 0x00004000, - BATTLE_MODE = 0x00008000, - CHALLENGE_MODE = 0x00010000, - SOLO_MODE = 0x00020000, + CHEATS_ENABLED = 0x00000100, + QUEST_IN_PROGRESS = 0x00000200, + BATTLE_IN_PROGRESS = 0x00000400, + JOINABLE_QUEST_IN_PROGRESS = 0x00000800, + ITEM_TRACKING_ENABLED = 0x00001000, + IS_SPECTATOR_TEAM = 0x00002000, // EPISODE_3_ONLY must also be set + SPECTATORS_FORBIDDEN = 0x00004000, + BATTLE_MODE = 0x00008000, + CHALLENGE_MODE = 0x00010000, + SOLO_MODE = 0x00020000, + START_BATTLE_PLAYER_IMMEDIATELY = 0x00040000, // Flags used only for lobbies - PUBLIC = 0x01000000, - DEFAULT = 0x02000000, + PUBLIC = 0x01000000, + DEFAULT = 0x02000000, }; PrefixedLogger log; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 0fdcfae8..76c5a5aa 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1931,9 +1931,7 @@ static void on_chat_generic(shared_ptr s, shared_ptr c, char private_flags = 0; u16string processed_text; - if ((text[0] != '\t') && - (l->flags & Lobby::Flag::EPISODE_3_ONLY) && - l->ep3_server_base) { + if ((text[0] != '\t') && (l->flags & Lobby::Flag::EPISODE_3_ONLY)) { private_flags = text[0]; processed_text = remove_language_marker(text.substr(1)); } else { @@ -2448,13 +2446,15 @@ static void on_set_blocked_senders_list(shared_ptr, shared_ptr create_game_generic(shared_ptr s, +shared_ptr create_game_generic( + shared_ptr s, shared_ptr c, const std::u16string& name, const std::u16string& password, uint8_t episode, uint8_t difficulty, - uint32_t flags) { + uint32_t flags, + shared_ptr battle_player) { // A player's actual level is their displayed level - 1, so the minimums for // Episode 1 (for example) are actually 1, 20, 40, 80. @@ -2504,11 +2504,9 @@ static shared_ptr create_game_generic(shared_ptr s, game->random_seed = c->override_random_seed; game->random->seed(game->random_seed); } - if (c->next_game_battle_record) { - game->battle_player.reset(new Episode3::BattleRecordPlayer( - c->next_game_battle_record, s->game_server->get_base(), game)); - c->next_game_battle_record.reset(); - game->flags |= Lobby::Flag::IS_SPECTATOR_TEAM; + if (battle_player) { + game->battle_player = battle_player; + battle_player->set_lobby(game); } game->common_item_creator.reset(new CommonItemCreator( s->common_item_data, game->random)); @@ -2694,6 +2692,10 @@ static void on_client_ready(shared_ptr s, shared_ptr c, if (c->version() == GameVersion::BB) { send_get_player_info(c); } + + if (l->battle_player && (l->flags & Lobby::Flag::START_BATTLE_PLAYER_IMMEDIATELY)) { + l->battle_player->start(); + } } diff --git a/src/ReceiveCommands.hh b/src/ReceiveCommands.hh index 61ccb6f2..dca4512b 100644 --- a/src/ReceiveCommands.hh +++ b/src/ReceiveCommands.hh @@ -6,6 +6,16 @@ +std::shared_ptr create_game_generic( + std::shared_ptr s, + std::shared_ptr c, + const std::u16string& name, + const std::u16string& password, + uint8_t episode, + uint8_t difficulty, + uint32_t flags, + std::shared_ptr battle_player = nullptr); + void on_connect(std::shared_ptr s, std::shared_ptr c); void on_disconnect(std::shared_ptr s, std::shared_ptr c); diff --git a/system/client-data/V2-SetDataTableOn-LE.rel b/system/client-data/V2-SetDataTableOn-LE.rel deleted file mode 100644 index 460e3a4c..00000000 Binary files a/system/client-data/V2-SetDataTableOn-LE.rel and /dev/null differ diff --git a/system/client-data/V3-SetDataTableOn-BE.rel b/system/client-data/V3-SetDataTableOn-BE.rel deleted file mode 100755 index 79fa03ce..00000000 Binary files a/system/client-data/V3-SetDataTableOn-BE.rel and /dev/null differ