mirror of https://github.com/OpenRCT2/OpenRCT2.git
Network serialiser for entities (#14541)
* Start a network serialiser for entities will be used only for checksums and replay diffs * Continue work * Use the new serailser for checksums * Use new serialiser for replays * keep compilers happy * Try create checksum stream * Fix compiling * Split off class into seperate file * Update Xcode project * Increment network version * Fix pragma mistake * Fix none network builds * Update replays * Improve ChecksumStream and use FNV internally * Small cleanups * satisfy compilers * Revert change of checksum size to simplfy rerecording * Zero initialise data * Fix serialiser * Update replays again Co-authored-by: Michael Steenbeek <m.o.steenbeek@gmail.com> Co-authored-by: Matt <m.moninger.h@gmail.com>
This commit is contained in:
parent
c63e072974
commit
d46e4a9bb1
|
@ -50,9 +50,9 @@ set(OBJECTS_VERSION "1.0.21")
|
|||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
|
||||
set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5")
|
||||
|
||||
set(REPLAYS_VERSION "0.0.39")
|
||||
set(REPLAYS_VERSION "0.0.42")
|
||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
|
||||
set(REPLAYS_SHA1 "8AF797661D87394FBE1A059375D82632094290FB")
|
||||
set(REPLAYS_SHA1 "C60FC1D6526DB8EDDF4AFBB0EE52A4A0D561646E")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
|
|
|
@ -60,6 +60,8 @@
|
|||
4C8BB68525533DB9005C8830 /* ZoomLevel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C8BB68425533DB9005C8830 /* ZoomLevel.cpp */; };
|
||||
4C91FD5F25AE476700CA5DA4 /* MusicObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C91FD5D25AE476700CA5DA4 /* MusicObject.cpp */; };
|
||||
4C91FD6225AE483700CA5DA4 /* RideAudio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C91FD6025AE483600CA5DA4 /* RideAudio.cpp */; };
|
||||
4CA23D64263C91D800077AA1 /* ChecksumStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA23D62263C91D700077AA1 /* ChecksumStream.cpp */; };
|
||||
4CA23DB2263C920900077AA1 /* Entity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA23DB1263C920900077AA1 /* Entity.cpp */; };
|
||||
4CA39E512513F8A00094066B /* RTL.ICU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA39E4E2513F8A00094066B /* RTL.ICU.cpp */; };
|
||||
4CA39E522513F8A00094066B /* RTL.FriBidi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA39E502513F8A00094066B /* RTL.FriBidi.cpp */; };
|
||||
4CB1375621C2E9F80029FCDA /* SimulateCommands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CB1375521C2E9F80029FCDA /* SimulateCommands.cpp */; };
|
||||
|
@ -1152,6 +1154,11 @@
|
|||
4C93F1B71F8E185600A9330D /* NewsItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewsItem.h; sourceTree = "<group>"; };
|
||||
4C93F1B81F8E185600A9330D /* Research.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Research.cpp; sourceTree = "<group>"; };
|
||||
4C93F1B91F8E185600A9330D /* Research.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Research.h; sourceTree = "<group>"; };
|
||||
4CA23D62263C91D700077AA1 /* ChecksumStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChecksumStream.cpp; sourceTree = "<group>"; };
|
||||
4CA23D63263C91D700077AA1 /* ChecksumStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChecksumStream.h; sourceTree = "<group>"; };
|
||||
4CA23DAF263C920900077AA1 /* Entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Entity.h; sourceTree = "<group>"; };
|
||||
4CA23DB0263C920900077AA1 /* EntityList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EntityList.h; sourceTree = "<group>"; };
|
||||
4CA23DB1263C920900077AA1 /* Entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Entity.cpp; sourceTree = "<group>"; };
|
||||
4CA39E4E2513F8A00094066B /* RTL.ICU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RTL.ICU.cpp; sourceTree = "<group>"; };
|
||||
4CA39E4F2513F8A00094066B /* RTL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTL.h; sourceTree = "<group>"; };
|
||||
4CA39E502513F8A00094066B /* RTL.FriBidi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RTL.FriBidi.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2433,6 +2440,8 @@
|
|||
F76C83781EC4E7CC00FA49E2 /* core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CA23D62263C91D700077AA1 /* ChecksumStream.cpp */,
|
||||
4CA23D63263C91D700077AA1 /* ChecksumStream.h */,
|
||||
2A5354EA22099C7200A5440F /* CircularBuffer.h */,
|
||||
F76C83791EC4E7CC00FA49E2 /* Collections.hpp */,
|
||||
F76C837A1EC4E7CC00FA49E2 /* Console.cpp */,
|
||||
|
@ -3066,6 +3075,9 @@
|
|||
4C7B54202007646A00A52E21 /* Climate.cpp */,
|
||||
4C7B54212007646A00A52E21 /* Climate.h */,
|
||||
4C7B54222007646A00A52E21 /* Duck.cpp */,
|
||||
4CA23DB1263C920900077AA1 /* Entity.cpp */,
|
||||
4CA23DAF263C920900077AA1 /* Entity.h */,
|
||||
4CA23DB0263C920900077AA1 /* EntityList.h */,
|
||||
4C7B54232007646A00A52E21 /* Entrance.cpp */,
|
||||
4C7B54242007646A00A52E21 /* Entrance.h */,
|
||||
4C7B54252007646A00A52E21 /* Footpath.cpp */,
|
||||
|
@ -3774,6 +3786,7 @@
|
|||
4C8BB67925533D4C005C8830 /* FileStream.cpp in Sources */,
|
||||
933CBDBD20CB1BA900134678 /* ViewportInteraction.cpp in Sources */,
|
||||
C685E51B1F8907850090598F /* Guest.cpp in Sources */,
|
||||
4CA23DB2263C920900077AA1 /* Entity.cpp in Sources */,
|
||||
C64644F91F3FA4120026AC2D /* EditorInventionsList.cpp in Sources */,
|
||||
C68878C720289B710084B384 /* OpenGLShaderProgram.cpp in Sources */,
|
||||
4CA39E512513F8A00094066B /* RTL.ICU.cpp in Sources */,
|
||||
|
@ -3839,6 +3852,7 @@
|
|||
4C8BB67C25533D59005C8830 /* JobPool.cpp in Sources */,
|
||||
01C6F0C222FD519E0057E2F7 /* TrackImporter.cpp in Sources */,
|
||||
4C8BB68125533D65005C8830 /* StringBuilder.cpp in Sources */,
|
||||
4CA23D64263C91D800077AA1 /* ChecksumStream.cpp in Sources */,
|
||||
C666EE761F37ACB10061AA04 /* Options.cpp in Sources */,
|
||||
4CB991CC25CEE54500C692B4 /* Shortcuts.cpp in Sources */,
|
||||
C666EE6E1F37ACB10061AA04 /* CustomCurrency.cpp in Sources */,
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>c38af45d51a6e440386180feacf76c64720b6ac5</ObjectsSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.39/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>8AF797661D87394FBE1A059375D82632094290FB</ReplaysSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.42/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>C60FC1D6526DB8EDDF4AFBB0EE52A4A0D561646E</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1795,18 +1795,18 @@ void window_guest_thoughts_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
|||
DrawTextBasic(dpi, screenCoords, STR_GUEST_RECENT_THOUGHTS_LABEL);
|
||||
|
||||
screenCoords.y += 10;
|
||||
for (rct_peep_thought* thought = peep->Thoughts; thought < &peep->Thoughts[PEEP_MAX_THOUGHTS]; ++thought)
|
||||
for (const auto& thought : peep->Thoughts)
|
||||
{
|
||||
if (thought->type == PeepThoughtType::None)
|
||||
if (thought.type == PeepThoughtType::None)
|
||||
return;
|
||||
if (thought->freshness == 0)
|
||||
if (thought.freshness == 0)
|
||||
continue;
|
||||
|
||||
int32_t width = window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].right
|
||||
- window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].left - 8;
|
||||
|
||||
auto ft = Formatter();
|
||||
peep_thought_set_format_args(thought, ft);
|
||||
peep_thought_set_format_args(&thought, ft);
|
||||
screenCoords.y += DrawTextWrapped(dpi, screenCoords, width, STR_BLACK_STRING, ft, { FontSpriteBase::SMALL });
|
||||
|
||||
// If this is the last visible line end drawing.
|
||||
|
|
|
@ -82,30 +82,31 @@ struct GameStateSnapshot_t
|
|||
switch (sprite.misc.Type)
|
||||
{
|
||||
case EntityType::Vehicle:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Vehicle)]>(sprite.vehicle);
|
||||
reinterpret_cast<Vehicle&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::Guest:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Guest)]>(sprite.peep);
|
||||
reinterpret_cast<Guest&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::Staff:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Staff)]>(sprite.peep);
|
||||
reinterpret_cast<Staff&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::Litter:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Litter)]>(sprite.litter);
|
||||
reinterpret_cast<Litter&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::MoneyEffect:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(MoneyEffect)]>(sprite.money_effect);
|
||||
reinterpret_cast<MoneyEffect&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::Balloon:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Balloon)]>(sprite.balloon);
|
||||
reinterpret_cast<Balloon&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::Duck:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(Duck)]>(sprite.duck);
|
||||
reinterpret_cast<Duck&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::JumpingFountain:
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(JumpingFountain)]>(sprite.jumping_fountain);
|
||||
reinterpret_cast<JumpingFountain&>(sprite).Serialise(ds);
|
||||
break;
|
||||
case EntityType::SteamParticle:
|
||||
reinterpret_cast<SteamParticle&>(sprite).Serialise(ds);
|
||||
ds << reinterpret_cast<uint8_t(&)[sizeof(SteamParticle)]>(sprite.steam_particle);
|
||||
break;
|
||||
case EntityType::Null:
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2021 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "ChecksumStream.h"
|
||||
|
||||
#include "Endianness.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
#ifndef DISABLE_NETWORK
|
||||
ChecksumStream::ChecksumStream(std::array<std::byte, 20>& buf)
|
||||
: _checksum(buf)
|
||||
{
|
||||
uint64_t* hash = reinterpret_cast<uint64_t*>(_checksum.data());
|
||||
*hash = Seed;
|
||||
}
|
||||
|
||||
void ChecksumStream::Write(const void* buffer, uint64_t length)
|
||||
{
|
||||
uint64_t* hash = reinterpret_cast<uint64_t*>(_checksum.data());
|
||||
for (size_t i = 0; i < length; i += sizeof(uint64_t))
|
||||
{
|
||||
const auto maxLen = std::min<size_t>(sizeof(uint64_t), length - i);
|
||||
|
||||
uint64_t temp{};
|
||||
std::memcpy(&temp, reinterpret_cast<const std::byte*>(buffer) + i, maxLen);
|
||||
|
||||
// Always use value as little endian, most common systems are little.
|
||||
# if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
temp = ByteSwapBE(temp);
|
||||
# endif
|
||||
|
||||
*hash ^= temp;
|
||||
*hash *= Prime;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace OpenRCT2
|
|
@ -0,0 +1,110 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2021 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
#include "IStream.hpp"
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
/**
|
||||
* A stream for checksumming a stream of data
|
||||
*/
|
||||
class ChecksumStream final : public IStream
|
||||
{
|
||||
// FIXME: Move the checksum implementation out.
|
||||
std::array<std::byte, 20>& _checksum;
|
||||
|
||||
static constexpr uint64_t Seed = 0xcbf29ce484222325ULL;
|
||||
static constexpr uint64_t Prime = 0x00000100000001B3ULL;
|
||||
|
||||
public:
|
||||
ChecksumStream(std::array<std::byte, 20>& buf);
|
||||
|
||||
virtual ~ChecksumStream() = default;
|
||||
|
||||
const void* GetData() const override
|
||||
{
|
||||
return _checksum.data();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ISteam methods
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
bool CanRead() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool CanWrite() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t GetLength() const override
|
||||
{
|
||||
return _checksum.size();
|
||||
}
|
||||
|
||||
uint64_t GetPosition() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetPosition(uint64_t position) override
|
||||
{
|
||||
}
|
||||
|
||||
void Seek(int64_t offset, int32_t origin) override
|
||||
{
|
||||
}
|
||||
|
||||
void Read(void* buffer, uint64_t length) override
|
||||
{
|
||||
}
|
||||
|
||||
void Write(const void* buffer, uint64_t length) override;
|
||||
|
||||
void Write1(const void* buffer) override
|
||||
{
|
||||
Write<1>(buffer);
|
||||
}
|
||||
|
||||
void Write2(const void* buffer) override
|
||||
{
|
||||
Write<2>(buffer);
|
||||
}
|
||||
|
||||
void Write4(const void* buffer) override
|
||||
{
|
||||
Write<4>(buffer);
|
||||
}
|
||||
|
||||
void Write8(const void* buffer) override
|
||||
{
|
||||
Write<8>(buffer);
|
||||
}
|
||||
|
||||
void Write16(const void* buffer) override
|
||||
{
|
||||
Write<16>(buffer);
|
||||
}
|
||||
|
||||
template<size_t N> void Write(const void* buffer)
|
||||
{
|
||||
Write(buffer, N);
|
||||
}
|
||||
|
||||
uint64_t TryRead(void* buffer, uint64_t length) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace OpenRCT2
|
|
@ -302,7 +302,7 @@ template<typename _Ty, size_t _Size> struct DataSerializerTraitsPODArray
|
|||
uint16_t swapped = ByteSwapBE(len);
|
||||
stream->Write(&swapped);
|
||||
|
||||
DataSerializerTraits<uint8_t> s;
|
||||
DataSerializerTraits<_Ty> s;
|
||||
for (auto&& sub : val)
|
||||
{
|
||||
s.encode(stream, sub);
|
||||
|
@ -584,6 +584,34 @@ template<> struct DataSerializerTraits_t<CoordsXYZD>
|
|||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
};
|
||||
template<> struct DataSerializerTraits_t<rct12_xyzd8>
|
||||
{
|
||||
static void encode(OpenRCT2::IStream* stream, const rct12_xyzd8& coord)
|
||||
{
|
||||
stream->WriteValue(ByteSwapBE(coord.x));
|
||||
stream->WriteValue(ByteSwapBE(coord.y));
|
||||
stream->WriteValue(ByteSwapBE(coord.z));
|
||||
stream->WriteValue(ByteSwapBE(coord.direction));
|
||||
}
|
||||
|
||||
static void decode(OpenRCT2::IStream* stream, rct12_xyzd8& coord)
|
||||
{
|
||||
auto x = ByteSwapBE(stream->ReadValue<uint8_t>());
|
||||
auto y = ByteSwapBE(stream->ReadValue<uint8_t>());
|
||||
auto z = ByteSwapBE(stream->ReadValue<uint8_t>());
|
||||
auto d = ByteSwapBE(stream->ReadValue<uint8_t>());
|
||||
coord = rct12_xyzd8{ x, y, z, d };
|
||||
}
|
||||
|
||||
static void log(OpenRCT2::IStream* stream, const rct12_xyzd8& coord)
|
||||
{
|
||||
char msg[128] = {};
|
||||
snprintf(
|
||||
msg, sizeof(msg), "rct12_xyzd8(x = %d, y = %d, z = %d, direction = %d)", coord.x, coord.y, coord.z,
|
||||
coord.direction);
|
||||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct DataSerializerTraits_t<NetworkCheatType_t>
|
||||
{
|
||||
|
@ -793,3 +821,49 @@ template<> struct DataSerializerTraits_t<ObjectEntryDescriptor>
|
|||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct DataSerializerTraits_t<IntensityRange>
|
||||
{
|
||||
static void encode(OpenRCT2::IStream* stream, const IntensityRange& val)
|
||||
{
|
||||
uint8_t temp = uint8_t(val);
|
||||
stream->Write(&temp);
|
||||
}
|
||||
static void decode(OpenRCT2::IStream* stream, IntensityRange& val)
|
||||
{
|
||||
auto temp = stream->ReadValue<uint8_t>();
|
||||
val = IntensityRange(temp);
|
||||
}
|
||||
static void log(OpenRCT2::IStream* stream, const IntensityRange& val)
|
||||
{
|
||||
char msg[128] = {};
|
||||
snprintf(msg, sizeof(msg), "IntensityRange(min = %d, max = %d)", val.GetMinimum(), val.GetMaximum());
|
||||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct DataSerializerTraits_t<rct_peep_thought>
|
||||
{
|
||||
static void encode(OpenRCT2::IStream* stream, const rct_peep_thought& val)
|
||||
{
|
||||
stream->Write(&val.type);
|
||||
stream->Write(&val.item);
|
||||
stream->Write(&val.freshness);
|
||||
stream->Write(&val.fresh_timeout);
|
||||
}
|
||||
static void decode(OpenRCT2::IStream* stream, rct_peep_thought& val)
|
||||
{
|
||||
stream->Read(&val.type);
|
||||
stream->Read(&val.item);
|
||||
stream->Read(&val.freshness);
|
||||
stream->Read(&val.fresh_timeout);
|
||||
}
|
||||
static void log(OpenRCT2::IStream* stream, const rct_peep_thought& val)
|
||||
{
|
||||
char msg[128] = {};
|
||||
snprintf(
|
||||
msg, sizeof(msg), "rct_peep_thought(type = %d, item = %d, freshness = %d, freshtimeout = %d)",
|
||||
static_cast<int32_t>(val.type), val.item, val.freshness, val.fresh_timeout);
|
||||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
<ClInclude Include="config\IniReader.hpp" />
|
||||
<ClInclude Include="config\IniWriter.hpp" />
|
||||
<ClInclude Include="Context.h" />
|
||||
<ClInclude Include="core\ChecksumStream.h" />
|
||||
<ClInclude Include="core\CircularBuffer.h" />
|
||||
<ClInclude Include="core\Collections.hpp" />
|
||||
<ClInclude Include="core\Console.hpp" />
|
||||
|
@ -437,6 +438,8 @@
|
|||
<ClInclude Include="windows\tile_inspector.h" />
|
||||
<ClInclude Include="world\Banner.h" />
|
||||
<ClInclude Include="world\Climate.h" />
|
||||
<ClInclude Include="world\Entity.h" />
|
||||
<ClInclude Include="world\EntityList.h" />
|
||||
<ClInclude Include="world\Entrance.h" />
|
||||
<ClInclude Include="world\Footpath.h" />
|
||||
<ClInclude Include="world\Fountain.h" />
|
||||
|
@ -569,6 +572,7 @@
|
|||
<ClCompile Include="config\IniReader.cpp" />
|
||||
<ClCompile Include="config\IniWriter.cpp" />
|
||||
<ClCompile Include="Context.cpp" />
|
||||
<ClCompile Include="core\ChecksumStream.cpp" />
|
||||
<ClCompile Include="core\Console.cpp" />
|
||||
<ClCompile Include="core\Crypt.CNG.cpp" />
|
||||
<ClCompile Include="core\Crypt.OpenSSL.cpp" />
|
||||
|
@ -854,6 +858,7 @@
|
|||
<ClCompile Include="world\Banner.cpp" />
|
||||
<ClCompile Include="world\Climate.cpp" />
|
||||
<ClCompile Include="world\Duck.cpp" />
|
||||
<ClCompile Include="world\Entity.cpp" />
|
||||
<ClCompile Include="world\Entrance.cpp" />
|
||||
<ClCompile Include="world\Footpath.cpp" />
|
||||
<ClCompile Include="world\Fountain.cpp" />
|
||||
|
@ -875,4 +880,4 @@
|
|||
<ClCompile Include="world\Wall.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
</Project>
|
|
@ -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 "13"
|
||||
#define NETWORK_STREAM_VERSION "14"
|
||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||
|
||||
static Peep* _pickup_peep = nullptr;
|
||||
|
|
|
@ -6950,7 +6950,7 @@ Guest* Guest::Generate(const CoordsXYZ& coords)
|
|||
peep->PathCheckOptimisation = 0;
|
||||
peep->InteractionRideIndex = RIDE_ID_NULL;
|
||||
peep->PreviousRide = RIDE_ID_NULL;
|
||||
peep->Thoughts->type = PeepThoughtType::None;
|
||||
peep->Thoughts[0].type = PeepThoughtType::None;
|
||||
peep->WindowInvalidateFlags = 0;
|
||||
|
||||
uint8_t intensityHighest = (scenario_rand() & 0x7) + 3;
|
||||
|
|
|
@ -1410,7 +1410,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
|
|||
peep->PathfindGoal.direction = 0;
|
||||
|
||||
// Clear pathfinding history
|
||||
std::fill_n(reinterpret_cast<uint8_t*>(peep->PathfindHistory), sizeof(peep->PathfindHistory), 0xFF);
|
||||
std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), rct12_xyzd8{ 0xFF, 0xFF, 0xFF, 0xFF });
|
||||
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
|
||||
if (_pathFindDebug)
|
||||
{
|
||||
|
|
|
@ -50,6 +50,8 @@ constexpr auto PEEP_CLEARANCE_HEIGHT = 4 * COORDS_Z_STEP;
|
|||
class Formatter;
|
||||
struct TileElement;
|
||||
struct Ride;
|
||||
class DataSerialiser;
|
||||
|
||||
namespace GameActions
|
||||
{
|
||||
class Result;
|
||||
|
@ -649,7 +651,7 @@ struct Peep : SpriteBase
|
|||
int8_t RejoinQueueTimeout; // whilst waiting for a free vehicle (or pair) in the entrance
|
||||
ride_id_t PreviousRide;
|
||||
uint16_t PreviousRideTimeOut;
|
||||
rct_peep_thought Thoughts[PEEP_MAX_THOUGHTS];
|
||||
std::array<rct_peep_thought, PEEP_MAX_THOUGHTS> Thoughts;
|
||||
uint8_t PathCheckOptimisation; // see peep.checkForPath
|
||||
union
|
||||
{
|
||||
|
@ -664,7 +666,7 @@ struct Peep : SpriteBase
|
|||
ride_id_t Photo1RideRef;
|
||||
uint32_t PeepFlags;
|
||||
rct12_xyzd8 PathfindGoal;
|
||||
rct12_xyzd8 PathfindHistory[4];
|
||||
std::array<rct12_xyzd8, 4> PathfindHistory;
|
||||
uint8_t WalkingFrameNum;
|
||||
// 0x3F Litter Count split into lots of 3 with time, 0xC0 Time since last recalc
|
||||
uint8_t LitterCount;
|
||||
|
@ -818,6 +820,7 @@ public:
|
|||
void RemoveItem(ShopItem item);
|
||||
void GiveItem(ShopItem item);
|
||||
bool HasItem(ShopItem peepItem) const;
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
private:
|
||||
void UpdateRide();
|
||||
|
@ -885,6 +888,7 @@ public:
|
|||
bool CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) const;
|
||||
|
||||
static void ResetStats();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
private:
|
||||
void UpdatePatrolling();
|
||||
|
|
|
@ -28,6 +28,7 @@ using track_type_t = uint16_t;
|
|||
|
||||
struct Ride;
|
||||
struct rct_ride_entry;
|
||||
class DataSerialiser;
|
||||
|
||||
struct GForces
|
||||
{
|
||||
|
@ -266,6 +267,7 @@ struct Vehicle : SpriteBase
|
|||
update_flags |= flag;
|
||||
}
|
||||
void ApplyMass(int16_t appliedMass);
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
private:
|
||||
bool SoundCanPlay() const;
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2021 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "Entity.h"
|
||||
|
||||
#include "../core/DataSerialiser.h"
|
||||
#include "../peep/Peep.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
static void EntityBaseSerialise(SpriteBase& base, DataSerialiser& stream)
|
||||
{
|
||||
stream << base.Type;
|
||||
stream << base.sprite_index;
|
||||
stream << base.x;
|
||||
stream << base.y;
|
||||
stream << base.z;
|
||||
stream << base.sprite_direction;
|
||||
}
|
||||
|
||||
void Litter::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << SubType;
|
||||
stream << creationTick;
|
||||
}
|
||||
|
||||
void Balloon::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << popped;
|
||||
stream << time_to_move;
|
||||
stream << colour;
|
||||
}
|
||||
|
||||
void Duck::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << target_x;
|
||||
stream << target_y;
|
||||
stream << state;
|
||||
}
|
||||
|
||||
void MoneyEffect::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << MoveDelay;
|
||||
stream << NumMovements;
|
||||
stream << Vertical;
|
||||
stream << Value;
|
||||
stream << OffsetX;
|
||||
stream << Wiggle;
|
||||
}
|
||||
|
||||
void VehicleCrashParticle::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << time_to_live;
|
||||
stream << colour;
|
||||
stream << crashed_sprite_base;
|
||||
stream << velocity_x;
|
||||
stream << velocity_y;
|
||||
stream << velocity_z;
|
||||
stream << acceleration_x;
|
||||
stream << acceleration_y;
|
||||
stream << acceleration_z;
|
||||
}
|
||||
|
||||
void ExplosionFlare::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
}
|
||||
|
||||
void ExplosionCloud::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
}
|
||||
|
||||
void CrashSplashParticle::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
}
|
||||
|
||||
void SteamParticle::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << time_to_move;
|
||||
}
|
||||
|
||||
void JumpingFountain::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << frame;
|
||||
stream << FountainType;
|
||||
stream << NumTicksAlive;
|
||||
stream << FountainFlags;
|
||||
stream << TargetX;
|
||||
stream << TargetY;
|
||||
stream << Iteration;
|
||||
}
|
||||
|
||||
static void PeepBaseSerialise(Peep& base, DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(base, stream);
|
||||
if (stream.IsLoading())
|
||||
{
|
||||
base.Name = nullptr;
|
||||
}
|
||||
stream << base.NextLoc;
|
||||
stream << base.NextFlags;
|
||||
stream << base.State;
|
||||
stream << base.SubState;
|
||||
stream << base.SpriteType;
|
||||
stream << base.TshirtColour;
|
||||
stream << base.TrousersColour;
|
||||
stream << base.DestinationX;
|
||||
stream << base.DestinationY;
|
||||
stream << base.DestinationTolerance;
|
||||
stream << base.Var37;
|
||||
stream << base.Energy;
|
||||
stream << base.EnergyTarget;
|
||||
stream << base.Mass;
|
||||
// stream << base.WindowInvalidateFlags;
|
||||
stream << base.CurrentRide;
|
||||
stream << base.CurrentRideStation;
|
||||
stream << base.CurrentTrain;
|
||||
stream << base.CurrentCar;
|
||||
stream << base.CurrentSeat;
|
||||
stream << base.SpecialSprite;
|
||||
stream << base.ActionSpriteType;
|
||||
stream << base.NextActionSpriteType;
|
||||
stream << base.ActionSpriteImageOffset;
|
||||
stream << base.Action;
|
||||
stream << base.ActionFrame;
|
||||
stream << base.StepProgress;
|
||||
stream << base.PeepDirection;
|
||||
stream << base.InteractionRideIndex;
|
||||
stream << base.Id;
|
||||
stream << base.PathCheckOptimisation;
|
||||
stream << base.PathfindGoal;
|
||||
stream << base.PathfindHistory;
|
||||
stream << base.WalkingFrameNum;
|
||||
stream << base.PeepFlags;
|
||||
}
|
||||
|
||||
void Guest::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
PeepBaseSerialise(*this, stream);
|
||||
stream << GuestNumRides;
|
||||
stream << GuestNextInQueue;
|
||||
stream << ParkEntryTime;
|
||||
stream << GuestHeadingToRideId;
|
||||
stream << GuestIsLostCountdown;
|
||||
stream << GuestTimeOnRide;
|
||||
stream << PaidToEnter;
|
||||
stream << PaidOnRides;
|
||||
stream << PaidOnFood;
|
||||
stream << PaidOnDrink;
|
||||
stream << PaidOnSouvenirs;
|
||||
stream << OutsideOfPark;
|
||||
stream << Happiness;
|
||||
stream << HappinessTarget;
|
||||
stream << Nausea;
|
||||
stream << NauseaTarget;
|
||||
stream << Hunger;
|
||||
stream << Thirst;
|
||||
stream << Toilet;
|
||||
stream << TimeToConsume;
|
||||
stream << Intensity;
|
||||
stream << NauseaTolerance;
|
||||
stream << RideTypesBeenOn;
|
||||
stream << TimeInQueue;
|
||||
stream << RidesBeenOn;
|
||||
stream << CashInPocket;
|
||||
stream << CashSpent;
|
||||
stream << Photo1RideRef;
|
||||
stream << Photo2RideRef;
|
||||
stream << Photo3RideRef;
|
||||
stream << Photo4RideRef;
|
||||
stream << RejoinQueueTimeout;
|
||||
stream << PreviousRide;
|
||||
stream << PreviousRideTimeOut;
|
||||
stream << Thoughts;
|
||||
stream << LitterCount;
|
||||
stream << DisgustingCount;
|
||||
stream << AmountOfFood;
|
||||
stream << AmountOfDrinks;
|
||||
stream << AmountOfSouvenirs;
|
||||
stream << VandalismSeen;
|
||||
stream << VoucherType;
|
||||
stream << VoucherRideId;
|
||||
stream << SurroundingsThoughtTimeout;
|
||||
stream << Angriness;
|
||||
stream << TimeLost;
|
||||
stream << DaysInQueue;
|
||||
stream << BalloonColour;
|
||||
stream << UmbrellaColour;
|
||||
stream << HatColour;
|
||||
stream << FavouriteRide;
|
||||
stream << FavouriteRideRating;
|
||||
stream << ItemFlags;
|
||||
}
|
||||
|
||||
void Staff::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
PeepBaseSerialise(*this, stream);
|
||||
stream << AssignedStaffType;
|
||||
stream << MechanicTimeSinceCall;
|
||||
stream << HireDate;
|
||||
stream << StaffId;
|
||||
stream << StaffOrders;
|
||||
stream << StaffMowingTimeout;
|
||||
stream << StaffLawnsMown;
|
||||
stream << StaffGardensWatered;
|
||||
stream << StaffLitterSwept;
|
||||
stream << StaffBinsEmptied;
|
||||
}
|
||||
|
||||
void Vehicle::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
EntityBaseSerialise(*this, stream);
|
||||
stream << SubType;
|
||||
stream << vehicle_sprite_type;
|
||||
stream << bank_rotation;
|
||||
stream << remaining_distance;
|
||||
stream << velocity;
|
||||
stream << acceleration;
|
||||
stream << ride;
|
||||
stream << vehicle_type;
|
||||
stream << colours;
|
||||
stream << track_progress;
|
||||
stream << TrackTypeAndDirection;
|
||||
stream << TrackLocation;
|
||||
stream << next_vehicle_on_train;
|
||||
stream << prev_vehicle_on_ride;
|
||||
stream << next_vehicle_on_ride;
|
||||
stream << var_44;
|
||||
stream << mass;
|
||||
stream << update_flags;
|
||||
stream << SwingSprite;
|
||||
stream << current_station;
|
||||
stream << SwingPosition;
|
||||
stream << SwingSpeed;
|
||||
stream << status;
|
||||
stream << sub_state;
|
||||
stream << peep;
|
||||
stream << peep_tshirt_colours;
|
||||
stream << num_seats;
|
||||
stream << num_peeps;
|
||||
stream << next_free_seat;
|
||||
stream << restraints_position;
|
||||
stream << spin_speed;
|
||||
stream << sound2_flags;
|
||||
stream << spin_sprite;
|
||||
stream << sound1_id;
|
||||
stream << sound1_volume;
|
||||
stream << sound2_id;
|
||||
stream << sound2_volume;
|
||||
stream << sound_vector_factor;
|
||||
stream << var_C0;
|
||||
stream << speed;
|
||||
stream << powered_acceleration;
|
||||
stream << dodgems_collision_direction;
|
||||
stream << animation_frame;
|
||||
stream << var_C8;
|
||||
stream << var_CA;
|
||||
stream << scream_sound_id;
|
||||
stream << TrackSubposition;
|
||||
stream << var_CE;
|
||||
stream << var_CF;
|
||||
stream << lost_time_out;
|
||||
stream << vertical_drop_countdown;
|
||||
stream << var_D3;
|
||||
stream << mini_golf_current_animation;
|
||||
stream << mini_golf_flags;
|
||||
stream << ride_subtype;
|
||||
stream << colours_extended;
|
||||
stream << seat_rotation;
|
||||
stream << target_seat_rotation;
|
||||
stream << BoatLocation;
|
||||
stream << IsCrashedVehicle;
|
||||
}
|
|
@ -13,6 +13,8 @@
|
|||
#include "Map.h"
|
||||
#include "SpriteBase.h"
|
||||
|
||||
class DataSerialiser;
|
||||
|
||||
enum class JumpingFountainType : uint8_t
|
||||
{
|
||||
Water,
|
||||
|
@ -31,6 +33,7 @@ struct JumpingFountain : MiscEntity
|
|||
uint16_t Iteration;
|
||||
void Update();
|
||||
static void StartAnimation(JumpingFountainType newType, const CoordsXY& newLoc, const TileElement* tileElement);
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
private:
|
||||
JumpingFountainType GetType() const;
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
#include "../Game.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "../audio/audio.h"
|
||||
#include "../core/ChecksumStream.h"
|
||||
#include "../core/Crypt.h"
|
||||
#include "../core/DataSerialiser.h"
|
||||
#include "../core/Guard.hpp"
|
||||
#include "../core/MemoryStream.h"
|
||||
#include "../interface/Viewport.h"
|
||||
#include "../localisation/Date.h"
|
||||
#include "../localisation/Localisation.h"
|
||||
|
@ -136,7 +139,7 @@ std::string rct_sprite_checksum::ToString() const
|
|||
for (auto b : raw)
|
||||
{
|
||||
char buf[3];
|
||||
snprintf(buf, 3, "%02x", b);
|
||||
snprintf(buf, 3, "%02x", static_cast<int32_t>(b));
|
||||
result.append(buf);
|
||||
}
|
||||
|
||||
|
@ -275,64 +278,26 @@ void reset_sprite_spatial_index()
|
|||
|
||||
#ifndef DISABLE_NETWORK
|
||||
|
||||
template<typename T> void ComputeChecksumForEntityType(Crypt::HashAlgorithm<20>* _entityHashAlg)
|
||||
template<typename T> void NetworkSerialseEntityType(DataSerialiser& ds)
|
||||
{
|
||||
for (auto* ent : EntityList<T>())
|
||||
{
|
||||
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<Peep, T>)
|
||||
{
|
||||
// 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));
|
||||
ent->Serialise(ds);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... T> void ComputeChecksumForEntityTypes(Crypt::HashAlgorithm<20>* _entityHashAlg)
|
||||
template<typename... T> void NetworkSerialiseEntityTypes(DataSerialiser& ds)
|
||||
{
|
||||
(ComputeChecksumForEntityType<T>(_entityHashAlg), ...);
|
||||
(NetworkSerialseEntityType<T>(ds), ...);
|
||||
}
|
||||
|
||||
rct_sprite_checksum sprite_checksum()
|
||||
{
|
||||
using namespace Crypt;
|
||||
rct_sprite_checksum checksum{};
|
||||
|
||||
// TODO Remove statics, should be one of these per sprite manager / OpenRCT2 context.
|
||||
// Alternatively, make a new class for this functionality.
|
||||
static std::unique_ptr<HashAlgorithm<20>> _spriteHashAlg;
|
||||
|
||||
rct_sprite_checksum checksum;
|
||||
|
||||
try
|
||||
{
|
||||
if (_spriteHashAlg == nullptr)
|
||||
{
|
||||
_spriteHashAlg = CreateSHA1();
|
||||
}
|
||||
|
||||
_spriteHashAlg->Clear();
|
||||
|
||||
ComputeChecksumForEntityTypes<Guest, Staff, Vehicle, Litter>(_spriteHashAlg.get());
|
||||
|
||||
checksum.raw = _spriteHashAlg->Finish();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
log_error("sprite_checksum failed: %s", e.what());
|
||||
throw;
|
||||
}
|
||||
OpenRCT2::ChecksumStream ms(checksum.raw);
|
||||
DataSerialiser ds(true, ms);
|
||||
NetworkSerialiseEntityTypes<Guest, Staff, Vehicle, Litter>(ds);
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
#include "SpriteBase.h"
|
||||
|
||||
enum LitterType : uint8_t;
|
||||
class DataSerialiser;
|
||||
|
||||
struct Litter : SpriteBase
|
||||
{
|
||||
static constexpr auto cEntityType = EntityType::Litter;
|
||||
LitterType SubType;
|
||||
uint32_t creationTick;
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct Balloon : MiscEntity
|
||||
|
@ -36,6 +38,7 @@ struct Balloon : MiscEntity
|
|||
void Update();
|
||||
void Pop();
|
||||
void Press();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct Duck : MiscEntity
|
||||
|
@ -57,6 +60,7 @@ struct Duck : MiscEntity
|
|||
uint32_t GetFrameImage(int32_t direction) const;
|
||||
bool IsFlying();
|
||||
void Remove();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
private:
|
||||
void UpdateFlyToWater();
|
||||
|
@ -80,6 +84,7 @@ struct MoneyEffect : MiscEntity
|
|||
static void Create(money32 value, const CoordsXYZ& loc);
|
||||
void Update();
|
||||
std::pair<rct_string_id, money32> GetStringId() const;
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct VehicleCrashParticle : MiscEntity
|
||||
|
@ -96,24 +101,28 @@ struct VehicleCrashParticle : MiscEntity
|
|||
int32_t acceleration_z;
|
||||
|
||||
void Update();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct ExplosionFlare : MiscEntity
|
||||
{
|
||||
static constexpr auto cEntityType = EntityType::ExplosionFlare;
|
||||
void Update();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct ExplosionCloud : MiscEntity
|
||||
{
|
||||
static constexpr auto cEntityType = EntityType::ExplosionCloud;
|
||||
void Update();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct CrashSplashParticle : MiscEntity
|
||||
{
|
||||
static constexpr auto cEntityType = EntityType::CrashSplash;
|
||||
void Update();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
struct SteamParticle : MiscEntity
|
||||
|
@ -122,6 +131,7 @@ struct SteamParticle : MiscEntity
|
|||
uint16_t time_to_move;
|
||||
|
||||
void Update();
|
||||
void Serialise(DataSerialiser& stream);
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
@ -154,7 +164,7 @@ assert_struct_size(rct_sprite, 0x200);
|
|||
|
||||
struct rct_sprite_checksum
|
||||
{
|
||||
std::array<uint8_t, 20> raw;
|
||||
std::array<std::byte, 20> raw;
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue