diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0048a089a6..7b78109770 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,8 +48,8 @@ set(TITLE_SEQUENCE_SHA1 "304d13a126c15bf2c86ff13b81a2f2cc1856ac8d")
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip")
set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5")
-set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.35/replays.zip")
-set(REPLAYS_SHA1 "5875A182E2828B8E0234F496B5D5E84CFE25EFCB")
+set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.36/replays.zip")
+set(REPLAYS_SHA1 "F539E5BD4F5062C2972C6E0DA974318DB01A0308")
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
option(WITH_TESTS "Build tests")
diff --git a/openrct2.proj b/openrct2.proj
index 514df8c008..00eddedcdb 100644
--- a/openrct2.proj
+++ b/openrct2.proj
@@ -48,8 +48,8 @@
304d13a126c15bf2c86ff13b81a2f2cc1856ac8d
https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip
c38af45d51a6e440386180feacf76c64720b6ac5
- https://github.com/OpenRCT2/replays/releases/download/v0.0.35/replays.zip
- 5875A182E2828B8E0234F496B5D5E84CFE25EFCB
+ https://github.com/OpenRCT2/replays/releases/download/v0.0.36/replays.zip
+ F539E5BD4F5062C2972C6E0DA974318DB01A0308
diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp
index cfd420b216..bea96f556c 100644
--- a/src/openrct2/network/NetworkBase.cpp
+++ b/src/openrct2/network/NetworkBase.cpp
@@ -36,7 +36,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
-#define NETWORK_STREAM_VERSION "6"
+#define NETWORK_STREAM_VERSION "7"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr;
diff --git a/src/openrct2/world/Sprite.cpp b/src/openrct2/world/Sprite.cpp
index 593b605d41..7d6f5e40b7 100644
--- a/src/openrct2/world/Sprite.cpp
+++ b/src/openrct2/world/Sprite.cpp
@@ -275,6 +275,36 @@ void reset_sprite_spatial_index()
#ifndef DISABLE_NETWORK
+template void ComputeChecksumForEntityType(Crypt::HashAlgorithm<20>* _entityHashAlg)
+{
+ for (auto* ent : EntityList())
+ {
+ T copy = *ent;
+
+ // Only required for rendering/invalidation, has no meaning to the game state.
+ copy.sprite_left = copy.sprite_right = copy.sprite_top = copy.sprite_bottom = 0;
+ copy.sprite_width = copy.sprite_height_negative = copy.sprite_height_positive = 0;
+
+ if constexpr (std::is_base_of_v)
+ {
+ // Name is pointer and will not be the same across clients
+ copy.Name = {};
+
+ // We set this to 0 because as soon the client selects a guest the window will remove the
+ // invalidation flags causing the sprite checksum to be different than on server, the flag does not
+ // affect game state.
+ copy.WindowInvalidateFlags = 0;
+ }
+
+ _entityHashAlg->Update(©, sizeof(copy));
+ }
+}
+
+template void ComputeChecksumForEntityTypes(Crypt::HashAlgorithm<20>* _entityHashAlg)
+{
+ (ComputeChecksumForEntityType(_entityHashAlg), ...);
+}
+
rct_sprite_checksum sprite_checksum()
{
using namespace Crypt;
@@ -293,33 +323,8 @@ rct_sprite_checksum sprite_checksum()
}
_spriteHashAlg->Clear();
- for (size_t i = 0; i < MAX_ENTITIES; i++)
- {
- // TODO create a way to copy only the specific type
- auto sprite = GetEntity(i);
- if (sprite != nullptr && sprite->Type != EntityType::Null && !sprite->Is())
- {
- // Upconvert it to rct_sprite so that the full size is copied.
- auto copy = *reinterpret_cast(sprite);
- // Only required for rendering/invalidation, has no meaning to the game state.
- copy.misc.sprite_left = copy.misc.sprite_right = copy.misc.sprite_top = copy.misc.sprite_bottom = 0;
- copy.misc.sprite_width = copy.misc.sprite_height_negative = copy.misc.sprite_height_positive = 0;
-
- if (copy.misc.Is())
- {
- // Name is pointer and will not be the same across clients
- copy.peep.Name = {};
-
- // We set this to 0 because as soon the client selects a guest the window will remove the
- // invalidation flags causing the sprite checksum to be different than on server, the flag does not
- // affect game state.
- copy.peep.WindowInvalidateFlags = 0;
- }
-
- _spriteHashAlg->Update(©, sizeof(copy));
- }
- }
+ ComputeChecksumForEntityTypes(_spriteHashAlg.get());
checksum.raw = _spriteHashAlg->Finish();
}