Skip to content

Commit f0f574c

Browse files
authored
Multiplayer: Fix various sync issues (#4866)
1 parent b3bab10 commit f0f574c

5 files changed

Lines changed: 110 additions & 35 deletions

File tree

src/custom_sprites.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ unsigned char base_pal[PALETTE_SIZE];
9797

9898
int total_sprite_zip_count = 0;
9999
uint32_t sprite_zip_combined_checksum = 0;
100+
struct SpriteZipEntry sprite_zip_entries[SPRITE_ZIP_ENTRY_COUNT];
101+
uint8_t sprite_zip_entry_count = 0;
100102

101103
// Used to cheaply detect mismatched custom sprites between players; makes file order matter when combining checksums, without this XOR alone gives the same result regardless of order.
102104
#define ROL32_5(x) (((uint32_t)(x) << 5) | ((uint32_t)(x) >> 27))
@@ -333,7 +335,20 @@ static int load_file_sprites(const char *path, const char *file_desc)
333335
}
334336
}
335337

336-
sprite_zip_combined_checksum = ROL32_5(sprite_zip_combined_checksum) ^ compute_zip_checksum(path);
338+
uint32_t zip_checksum = compute_zip_checksum(path);
339+
sprite_zip_combined_checksum = ROL32_5(sprite_zip_combined_checksum) ^ zip_checksum;
340+
if (sprite_zip_entry_count < SPRITE_ZIP_ENTRY_COUNT) {
341+
const char *filename = strrchr(path, '/');
342+
if (filename == NULL) {
343+
filename = path;
344+
} else {
345+
filename++;
346+
}
347+
struct SpriteZipEntry *entry = &sprite_zip_entries[sprite_zip_entry_count];
348+
snprintf(entry->filename, sizeof(entry->filename), "%s", filename);
349+
entry->checksum = zip_checksum;
350+
sprite_zip_entry_count++;
351+
}
337352
total_sprite_zip_count++;
338353

339354
return add_flag;
@@ -430,6 +445,7 @@ void init_custom_sprites(LevelNumber lvnum)
430445
custom_sprites = create_spritesheet();
431446
total_sprite_zip_count = 0;
432447
sprite_zip_combined_checksum = 0;
448+
sprite_zip_entry_count = 0;
433449
// This is a workaround because get_selected_level_number is zeroed on res change
434450
if (lvnum == SPRITE_LAST_LEVEL)
435451
{

src/custom_sprites.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,20 @@ extern "C" {
2828
struct ObjectConfigStats;
2929

3030
#define SPRITE_LAST_LEVEL -1
31+
#define SPRITE_ZIP_ENTRY_COUNT 48
32+
#define SPRITE_ZIP_ENTRY_NAME_LEN 64
33+
34+
struct SpriteZipEntry {
35+
char filename[SPRITE_ZIP_ENTRY_NAME_LEN];
36+
uint32_t checksum;
37+
};
38+
3139
void init_custom_sprites(LevelNumber level_no);
3240

3341
extern int total_sprite_zip_count;
3442
extern uint32_t sprite_zip_combined_checksum;
43+
extern struct SpriteZipEntry sprite_zip_entries[SPRITE_ZIP_ENTRY_COUNT];
44+
extern uint8_t sprite_zip_entry_count;
3545

3646
short get_anim_id(const char *name, struct ObjectConfigStats* objst);
3747
short get_anim_id_(const char* name);

src/net_checksums.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
/******************************************************************************/
1919
#include "pre_inc.h"
2020
#include "net_checksums.h"
21+
#include "bflib_dernc.h"
22+
#include "config.h"
2123
#include "game_legacy.h"
24+
#include "game_merge.h"
2225
#include "net_game.h"
2326
#include "packets.h"
2427
#include "player_data.h"
2528
#include "thing_data.h"
2629
#include "room_list.h"
30+
#include "slab_data.h"
2731
#include "creature_control.h"
2832
#include "thing_creature.h"
2933
#include "thing_list.h"
@@ -217,15 +221,37 @@ short checksums_different(void) {
217221
return mismatch;
218222
}
219223

220-
TbBigChecksum calculate_network_startup_map_checksum(void) {
224+
TbBigChecksum calculate_network_startup_map_checksum(void)
225+
{
221226
TbBigChecksum checksum_mem = 0;
222227
for (int i = 1; i < THINGS_COUNT; i++) {
223228
struct Thing* thing = thing_get(i);
224-
if (thing_exists(thing)) {
225-
checksum_mem += thing->mappos.z.val + thing->mappos.y.val + thing->mappos.x.val;
229+
if (thing_exists(thing) && !is_non_synchronized_thing_class(thing->class_id)) {
230+
CHECKSUM_ADD(checksum_mem, get_thing_checksum(thing));
226231
}
227232
}
228-
return checksum_mem + game.action_random_seed;
233+
for (int32_t y = 0; y < game.map_tiles_y; y++) {
234+
for (int32_t x = 0; x < game.map_tiles_x; x++) {
235+
struct SlabMap* slb = get_slabmap_block(x, y);
236+
CHECKSUM_ADD(checksum_mem, slb->kind);
237+
CHECKSUM_ADD(checksum_mem, slb->owner);
238+
}
239+
}
240+
LevelNumber lvnum = get_loaded_level_number();
241+
short fgroup = get_level_fgroup(lvnum);
242+
const char* script_exts[] = {"txt", "lua"};
243+
for (int i = 0; i < sizeof(script_exts) / sizeof(script_exts[0]); i++) {
244+
char* fname = prepare_file_fmtpath(fgroup, "map%05u.%s", lvnum, script_exts[i]);
245+
int32_t file_size = (int32_t)LbFileLengthRnc(fname);
246+
if (file_size > 0) {
247+
unsigned char *file_buf = malloc(file_size);
248+
if (file_buf != NULL && LbFileLoadAt(fname, file_buf) == file_size) {
249+
CHECKSUM_ADD(checksum_mem, rnc_crc(file_buf, file_size));
250+
}
251+
free(file_buf);
252+
}
253+
}
254+
return checksum_mem;
229255
}
230256

231257
void update_turn_checksums(void) {

src/net_game.c

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ struct StartupSyncPacket {
6363
int32_t input_lag_turns;
6464
TbBigChecksum map_checksum;
6565
uint32_t sprite_zip_checksum;
66+
uint8_t sprite_zip_entry_count;
67+
struct SpriteZipEntry sprite_zip_entries[SPRITE_ZIP_ENTRY_COUNT];
6668
uint16_t initial_tendencies;
6769
uint32_t isometric_view_zoom_level;
6870
uint32_t frontview_zoom_level;
@@ -157,10 +159,54 @@ static TbBool verify_map_checksums(const struct StartupSyncPacket startup_sync_p
157159

158160
static void verify_startup_sprite_zip_checksums(const struct StartupSyncPacket startup_sync_packets[MAX_NET_USERS])
159161
{
162+
int host_player_id = get_host_player_id();
163+
const struct StartupSyncPacket *host_sync = &startup_sync_packets[host_player_id];
160164
for (int i = 0; i < MAX_NET_USERS; i++) {
161-
if (net_player_info[i].network_user_active && startup_sync_packets[i].sprite_zip_checksum != sprite_zip_combined_checksum) {
162-
message_add(MsgType_Player, 0, get_string(GUIStr_NetVerifyFxdataSame));
163-
message_add_fmt(MsgType_Player, 0, get_string(GUIStr_NetCustomSpriteMismatch), network_player_name(i));
165+
if (!net_player_info[i].network_user_active || i == host_player_id) {
166+
continue;
167+
}
168+
const struct StartupSyncPacket *client_sync = &startup_sync_packets[i];
169+
if (client_sync->sprite_zip_checksum == host_sync->sprite_zip_checksum) {
170+
continue;
171+
}
172+
TbBool reported = false;
173+
for (int pass = 0; pass < 2; pass++) {
174+
const struct StartupSyncPacket *source_sync = host_sync;
175+
const struct StartupSyncPacket *target_sync = client_sync;
176+
int target_player_id = i;
177+
if (pass == 1) {
178+
source_sync = client_sync;
179+
target_sync = host_sync;
180+
target_player_id = host_player_id;
181+
}
182+
for (int source_idx = 0; source_idx < source_sync->sprite_zip_entry_count; source_idx++) {
183+
const struct SpriteZipEntry *source_entry = &source_sync->sprite_zip_entries[source_idx];
184+
TbBool found = false;
185+
for (int target_idx = 0; target_idx < target_sync->sprite_zip_entry_count; target_idx++) {
186+
const struct SpriteZipEntry *target_entry = &target_sync->sprite_zip_entries[target_idx];
187+
if (strcasecmp(source_entry->filename, target_entry->filename) != 0) {
188+
continue;
189+
}
190+
found = true;
191+
if (pass == 0 && source_entry->checksum != target_entry->checksum) {
192+
WARNLOG("Custom sprite zip differs for %s: %s", network_player_name(host_player_id), source_entry->filename);
193+
message_add_fmt(MsgType_Blank, 0, "/fxdata/%.30s differs for %.12s", source_entry->filename, network_player_name(host_player_id));
194+
WARNLOG("Custom sprite zip differs for %s: %s", network_player_name(i), source_entry->filename);
195+
message_add_fmt(MsgType_Blank, 0, "/fxdata/%.30s differs for %.12s", source_entry->filename, network_player_name(i));
196+
reported = true;
197+
}
198+
break;
199+
}
200+
if (!found) {
201+
WARNLOG("Custom sprite zip missing for %s: %s", network_player_name(target_player_id), source_entry->filename);
202+
message_add_fmt(MsgType_Blank, 0, "/fxdata/%.30s missing for %.12s", source_entry->filename, network_player_name(target_player_id));
203+
reported = true;
204+
}
205+
}
206+
}
207+
if (!reported) {
208+
WARNLOG("Custom sprite zip order or overflow mismatch for %s", network_player_name(i));
209+
message_add_fmt(MsgType_Blank, 0, "/fxdata/ zip order error");
164210
}
165211
}
166212
}
@@ -177,6 +223,8 @@ static void build_local_startup_sync(void)
177223
s_local_startup_sync.input_lag_turns = game.input_lag_turns;
178224
s_local_startup_sync.map_checksum = calculate_network_startup_map_checksum();
179225
s_local_startup_sync.sprite_zip_checksum = sprite_zip_combined_checksum;
226+
s_local_startup_sync.sprite_zip_entry_count = sprite_zip_entry_count;
227+
memcpy(s_local_startup_sync.sprite_zip_entries, sprite_zip_entries, sizeof(s_local_startup_sync.sprite_zip_entries));
180228
uint16_t initial_tendencies = 0;
181229
if (IMPRISON_BUTTON_DEFAULT) {initial_tendencies |= CrTend_Imprison;}
182230
if (FLEE_BUTTON_DEFAULT) {initial_tendencies |= CrTend_Flee;}

src/roomspace.c

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,14 @@ struct RoomSpace create_box_roomspace_from_drag(struct RoomSpace roomspace, MapS
180180
roomspace.drag_start_y = start_y;
181181
roomspace.drag_end_x = end_x;
182182
roomspace.drag_end_y = end_y;
183+
detect_roomspace_direction(&roomspace);
183184
return roomspace;
184185
}
185186

186187
static struct RoomSpace create_dig_highlight_roomspace(struct RoomSpace roomspace, unsigned char highlight_mode, int width, MapSlabCoord drag_start_x, MapSlabCoord drag_start_y, MapSlabCoord slb_x, MapSlabCoord slb_y)
187188
{
188189
if (highlight_mode == drag_placement_mode) {
189190
roomspace = create_box_roomspace_from_drag(roomspace, drag_start_x, drag_start_y, slb_x, slb_y);
190-
detect_roomspace_direction(&roomspace);
191191
return roomspace;
192192
}
193193
if (highlight_mode == roomspace_detection_mode) {
@@ -219,6 +219,7 @@ struct RoomSpace create_box_roomspace(struct RoomSpace roomspace, int width, int
219219
roomspace.untag_mode = false;
220220
roomspace.one_click_mode_exclusive = false;
221221
roomspace.drag_mode = false;
222+
roomspace.drag_direction = top_left_to_bottom_right;
222223
return roomspace;
223224
}
224225

@@ -740,28 +741,6 @@ void get_dungeon_sell_user_roomspace(struct RoomSpace *roomspace, PlayerNumber p
740741
current_roomspace.is_roomspace_a_box = true;
741742
current_roomspace.render_roomspace_as_box = true;
742743
current_roomspace = create_box_roomspace_from_drag(current_roomspace, drag_start_x, drag_start_y, slb_x, slb_y);
743-
if (roomspace->drag_start_y > roomspace->drag_end_y)
744-
{
745-
if (roomspace->drag_start_x > roomspace->drag_end_x)
746-
{
747-
current_roomspace.drag_direction = bottom_right_to_top_left;
748-
}
749-
else
750-
{
751-
current_roomspace.drag_direction = bottom_left_to_top_right;
752-
}
753-
}
754-
else
755-
{
756-
if (roomspace->drag_start_x > roomspace->drag_end_x)
757-
{
758-
current_roomspace.drag_direction = top_right_to_bottom_left;
759-
}
760-
else
761-
{
762-
current_roomspace.drag_direction = top_left_to_bottom_right;
763-
}
764-
}
765744
current_roomspace = check_roomspace_for_sellable_slabs(current_roomspace, plyr_idx);
766745
player->roomspace_width = current_roomspace.width;
767746
player->roomspace_height = current_roomspace.height;
@@ -858,10 +837,6 @@ void get_dungeon_build_user_roomspace(struct RoomSpace *roomspace, PlayerNumber
858837
{
859838
temp_best_room = create_box_roomspace(best_roomspace, 1, 1, slb_x, slb_y);
860839
}
861-
if (!player->roomspace.is_active)
862-
{
863-
detect_roomspace_direction(&temp_best_room);
864-
}
865840
if (room_role_matches(rkind,RoRoF_PassWater|RoRoF_PassLava))
866841
{
867842
detect_bridge_shape(plyr_idx);

0 commit comments

Comments
 (0)