fix client crash when creating spectator team
This commit is contained in:
+5
-1
@@ -593,8 +593,12 @@ static void server_command_playrec(shared_ptr<ServerState> s, shared_ptr<Lobby>
|
||||
shared_ptr<Episode3::BattleRecord> record(new Episode3::BattleRecord(data));
|
||||
shared_ptr<Episode3::BattleRecordPlayer> battle_player(
|
||||
new Episode3::BattleRecordPlayer(record, s->game_server->get_base()));
|
||||
create_game_generic(s, c, args.c_str(), u"", Episode::EP3, GameMode::NORMAL,
|
||||
auto game = create_game_generic(s, c, args.c_str(), u"", Episode::EP3, GameMode::NORMAL,
|
||||
0, flags, nullptr, battle_player);
|
||||
if (game) {
|
||||
s->change_client_lobby(c, game);
|
||||
c->flags |= Client::Flag::LOADING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-32
@@ -3099,46 +3099,51 @@ struct SC_SyncCharacterSaveFile_BB_00E7 {
|
||||
|
||||
// E8 (S->C): Join spectator team (Episode 3)
|
||||
// header.flag = player count (including spectators)
|
||||
// The client will crash if leader_id == client_id. Presumably one of the
|
||||
// primary game's players should be the leader (this is what newserv does).
|
||||
|
||||
struct S_JoinSpectatorTeam_GC_Ep3_E8 {
|
||||
parray<le_uint32_t, 0x20> variations; // 04-84; unused
|
||||
/* 0004 */ parray<le_uint32_t, 0x20> variations; // unused
|
||||
struct PlayerEntry {
|
||||
PlayerLobbyDataDCGC lobby_data; // 0x20 bytes
|
||||
PlayerInventory inventory; // 0x34C bytes
|
||||
PlayerDispDataDCPCV3 disp; // 0xD0 bytes
|
||||
} __packed__; // 0x43C bytes
|
||||
parray<PlayerEntry, 4> players; // 84-1174
|
||||
uint8_t client_id = 0;
|
||||
uint8_t leader_id = 0;
|
||||
uint8_t disable_udp = 1;
|
||||
uint8_t difficulty = 0;
|
||||
uint8_t battle_mode = 0;
|
||||
uint8_t event = 0;
|
||||
uint8_t section_id = 0;
|
||||
uint8_t challenge_mode = 0;
|
||||
le_uint32_t rare_seed = 0;
|
||||
uint8_t episode = 0;
|
||||
uint8_t unused2 = 1;
|
||||
uint8_t solo_mode = 0;
|
||||
uint8_t unused3 = 0;
|
||||
/* 0000 */ PlayerLobbyDataDCGC lobby_data;
|
||||
/* 0020 */ PlayerInventory inventory;
|
||||
/* 036C */ PlayerDispDataDCPCV3 disp;
|
||||
/* 043C */
|
||||
} __packed__;
|
||||
/* 0084 */ parray<PlayerEntry, 4> players;
|
||||
/* 1174 */ uint8_t client_id = 0;
|
||||
/* 1175 */ uint8_t leader_id = 0;
|
||||
/* 1176 */ uint8_t disable_udp = 1;
|
||||
/* 1177 */ uint8_t difficulty = 0;
|
||||
/* 1178 */ uint8_t battle_mode = 0;
|
||||
/* 1179 */ uint8_t event = 0;
|
||||
/* 117A */ uint8_t section_id = 0;
|
||||
/* 117B */ uint8_t challenge_mode = 0;
|
||||
/* 117C */ le_uint32_t rare_seed = 0;
|
||||
/* 1180 */ uint8_t episode = 0;
|
||||
/* 1181 */ uint8_t unused2 = 1;
|
||||
/* 1182 */ uint8_t solo_mode = 0;
|
||||
/* 1183 */ uint8_t unused3 = 0;
|
||||
struct SpectatorEntry {
|
||||
le_uint32_t player_tag = 0;
|
||||
le_uint32_t guild_card_number = 0;
|
||||
ptext<char, 0x20> name;
|
||||
uint8_t present = 0;
|
||||
uint8_t unknown_a3 = 0;
|
||||
le_uint16_t level = 0;
|
||||
parray<le_uint32_t, 2> unknown_a5;
|
||||
parray<le_uint16_t, 2> unknown_a6;
|
||||
} __packed__; // 0x38 bytes
|
||||
/* 00 */ le_uint32_t player_tag = 0;
|
||||
/* 04 */ le_uint32_t guild_card_number = 0;
|
||||
/* 08 */ ptext<char, 0x20> name;
|
||||
/* 28 */ uint8_t present = 0;
|
||||
/* 29 */ uint8_t unknown_a3 = 0;
|
||||
/* 2A */ le_uint16_t level = 0;
|
||||
/* 2C */ parray<le_uint32_t, 2> unknown_a5;
|
||||
/* 34 */ parray<le_uint16_t, 2> unknown_a6;
|
||||
/* 38 */
|
||||
} __packed__;
|
||||
// Somewhat misleadingly, this array also includes the players actually in the
|
||||
// battle - they appear in the first positions. Presumably the first 4 are
|
||||
// always for battlers, and the last 8 are always for spectators.
|
||||
parray<SpectatorEntry, 12> entries; // 1184-1424
|
||||
ptext<char, 0x20> spectator_team_name;
|
||||
/* 1184 */ parray<SpectatorEntry, 12> entries;
|
||||
/* 1424 */ ptext<char, 0x20> spectator_team_name;
|
||||
// This field doesn't appear to be actually used by the game, but some servers
|
||||
// send it anyway (and the game presumably ignores it)
|
||||
parray<PlayerEntry, 8> spectator_players;
|
||||
// send it anyway (and the game ignores it)
|
||||
/* 1444 */ parray<PlayerEntry, 8> spectator_players;
|
||||
/* 3624 */
|
||||
} __packed__;
|
||||
|
||||
// E8 (C->S): Guild card commands (BB)
|
||||
|
||||
+25
-25
@@ -112,12 +112,12 @@ struct PlayerDispDataBB;
|
||||
|
||||
struct PlayerStats {
|
||||
/* 00 */ CharacterStats char_stats;
|
||||
/* 0E */ le_uint16_t unknown_a1;
|
||||
/* 10 */ le_float unknown_a2;
|
||||
/* 14 */ le_float unknown_a3;
|
||||
/* 18 */ le_uint32_t level;
|
||||
/* 1C */ le_uint32_t experience;
|
||||
/* 20 */ le_uint32_t meseta;
|
||||
/* 0E */ le_uint16_t unknown_a1 = 0;
|
||||
/* 10 */ le_float unknown_a2 = 0.0;
|
||||
/* 14 */ le_float unknown_a3 = 0.0;
|
||||
/* 18 */ le_uint32_t level = 0;
|
||||
/* 1C */ le_uint32_t experience = 0;
|
||||
/* 20 */ le_uint32_t meseta = 0;
|
||||
/* 24 */
|
||||
|
||||
PlayerStats() noexcept;
|
||||
@@ -125,26 +125,26 @@ struct PlayerStats {
|
||||
|
||||
struct PlayerVisualConfig {
|
||||
/* 00 */ ptext<char, 0x10> name;
|
||||
/* 10 */ le_uint64_t unknown_a2; // Note: This is probably not actually a 64-bit int.
|
||||
/* 18 */ le_uint32_t name_color; // RGBA
|
||||
/* 1C */ uint8_t extra_model;
|
||||
/* 10 */ le_uint64_t unknown_a2 = 0; // Note: This is probably not actually a 64-bit int.
|
||||
/* 18 */ le_uint32_t name_color = 0xFFFFFFFF; // RGBA
|
||||
/* 1C */ uint8_t extra_model = 0;
|
||||
/* 1D */ parray<uint8_t, 0x0F> unused;
|
||||
/* 2C */ le_uint32_t unknown_a3;
|
||||
/* 30 */ uint8_t section_id;
|
||||
/* 31 */ uint8_t char_class;
|
||||
/* 32 */ uint8_t v2_flags;
|
||||
/* 33 */ uint8_t version;
|
||||
/* 34 */ le_uint32_t v1_flags;
|
||||
/* 38 */ le_uint16_t costume;
|
||||
/* 3A */ le_uint16_t skin;
|
||||
/* 3C */ le_uint16_t face;
|
||||
/* 3E */ le_uint16_t head;
|
||||
/* 40 */ le_uint16_t hair;
|
||||
/* 42 */ le_uint16_t hair_r;
|
||||
/* 44 */ le_uint16_t hair_g;
|
||||
/* 46 */ le_uint16_t hair_b;
|
||||
/* 48 */ le_float proportion_x;
|
||||
/* 4C */ le_float proportion_y;
|
||||
/* 2C */ le_uint32_t unknown_a3 = 0;
|
||||
/* 30 */ uint8_t section_id = 0;
|
||||
/* 31 */ uint8_t char_class = 0;
|
||||
/* 32 */ uint8_t v2_flags = 0;
|
||||
/* 33 */ uint8_t version = 0;
|
||||
/* 34 */ le_uint32_t v1_flags = 0;
|
||||
/* 38 */ le_uint16_t costume = 0;
|
||||
/* 3A */ le_uint16_t skin = 0;
|
||||
/* 3C */ le_uint16_t face = 0;
|
||||
/* 3E */ le_uint16_t head = 0;
|
||||
/* 40 */ le_uint16_t hair = 0;
|
||||
/* 42 */ le_uint16_t hair_r = 0;
|
||||
/* 44 */ le_uint16_t hair_g = 0;
|
||||
/* 46 */ le_uint16_t hair_b = 0;
|
||||
/* 48 */ le_float proportion_x = 0.0;
|
||||
/* 4C */ le_float proportion_y = 0.0;
|
||||
/* 50 */
|
||||
|
||||
PlayerVisualConfig() noexcept;
|
||||
|
||||
+5
-1
@@ -1419,7 +1419,6 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
||||
|
||||
cmd.variations.clear(0);
|
||||
cmd.client_id = c->lobby_client_id;
|
||||
cmd.leader_id = l->leader_id;
|
||||
cmd.event = l->event;
|
||||
cmd.section_id = l->section_id;
|
||||
cmd.rare_seed = l->random_seed;
|
||||
@@ -1428,6 +1427,7 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
||||
uint8_t player_count = 0;
|
||||
auto watched_lobby = l->watched_lobby.lock();
|
||||
if (watched_lobby) {
|
||||
cmd.leader_id = watched_lobby->leader_id;
|
||||
// Live spectating
|
||||
for (size_t z = 0; z < 4; z++) {
|
||||
if (!watched_lobby->clients[z]) {
|
||||
@@ -1466,6 +1466,10 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
||||
if (ev->type != Episode3::BattleRecord::Event::Type::SET_INITIAL_PLAYERS) {
|
||||
throw runtime_error("battle record does not begin with set players event");
|
||||
}
|
||||
if (ev->players.empty()) {
|
||||
throw runtime_error("battle record contains no players");
|
||||
}
|
||||
cmd.leader_id = ev->players[0].lobby_data.client_id;
|
||||
for (const auto& entry : ev->players) {
|
||||
uint8_t client_id = entry.lobby_data.client_id;
|
||||
if (client_id >= 4) {
|
||||
|
||||
Reference in New Issue
Block a user