1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_SHARED_SNAPSHOT_H
4#define ENGINE_SHARED_SNAPSHOT_H
5
6#include <generated/protocol.h>
7#include <generated/protocol7.h>
8
9#include <cstddef>
10#include <cstdint>
11
12// CSnapshot
13
14class CSnapshotItem
15{
16 friend class CSnapshotBuilder;
17
18 int *Data() { return (int *)(this + 1); }
19
20public:
21 int m_TypeAndId;
22
23 const int *Data() const { return (int *)(this + 1); }
24 int Type() const { return m_TypeAndId >> 16; }
25 int Id() const { return m_TypeAndId & 0xffff; }
26 int Key() const { return m_TypeAndId; }
27 void Invalidate() { m_TypeAndId = -1; }
28};
29
30class CSnapshot
31{
32 friend class CSnapshotBuilder;
33 int m_DataSize = 0;
34 int m_NumItems = 0;
35
36 int *Offsets() const { return (int *)(this + 1); }
37 char *DataStart() const { return (char *)(Offsets() + m_NumItems); }
38
39 size_t OffsetSize() const { return sizeof(int) * m_NumItems; }
40 size_t TotalSize() const { return sizeof(CSnapshot) + OffsetSize() + m_DataSize; }
41
42 static const CSnapshot ms_EmptySnapshot;
43
44public:
45 enum
46 {
47 OFFSET_UUID_TYPE = 0x4000,
48 MAX_TYPE = 0x7fff,
49 MAX_ID = 0xffff,
50 MAX_ITEMS = 1024,
51 MAX_PARTS = 64,
52 MAX_SIZE = MAX_PARTS * 1024
53 };
54
55 int NumItems() const { return m_NumItems; }
56 int DataSize() const { return m_DataSize; }
57 const CSnapshotItem *GetItem(int Index) const;
58 int GetItemSize(int Index) const;
59 int GetItemIndex(int Key) const;
60 void InvalidateItem(int Index);
61 int GetItemType(int Index) const;
62 int GetExternalItemType(int InternalType) const;
63 const void *FindItem(int Type, int Id) const;
64
65 unsigned Crc() const;
66 // Prints the raw snapshot data showing item and int boundaries.
67 // See also `CNetObjHandler::DebugDumpSnapshot(const CSnapshot *pSnap)`
68 // For more detailed annotations of the data.
69 void DebugDump() const;
70 bool IsValid(size_t ActualSize) const;
71
72 static const CSnapshot *EmptySnapshot() { return &ms_EmptySnapshot; }
73};
74
75// CSnapshotDelta
76
77class CSnapshotDelta
78{
79public:
80 class CData
81 {
82 public:
83 int m_NumDeletedItems;
84 int m_NumUpdateItems;
85 int m_NumTempItems; // needed?
86 int m_aData[1];
87 };
88
89private:
90 enum
91 {
92 MAX_NETOBJSIZES = 64
93 };
94 short m_aItemSizes[MAX_NETOBJSIZES];
95 short m_aItemSizes7[MAX_NETOBJSIZES];
96 uint64_t m_aSnapshotDataRate[CSnapshot::MAX_TYPE + 1];
97 uint64_t m_aSnapshotDataUpdates[CSnapshot::MAX_TYPE + 1];
98 CData m_Empty;
99
100 static void UndiffItem(const int *pPast, const int *pDiff, int *pOut, int Size, uint64_t *pDataRate);
101
102public:
103 static int DiffItem(const int *pPast, const int *pCurrent, int *pOut, int Size);
104 CSnapshotDelta();
105 CSnapshotDelta(const CSnapshotDelta &Old);
106 uint64_t GetDataRate(int Index) const { return m_aSnapshotDataRate[Index]; }
107 uint64_t GetDataUpdates(int Index) const { return m_aSnapshotDataUpdates[Index]; }
108 void SetStaticsize(int ItemType, size_t Size);
109 void SetStaticsize7(int ItemType, size_t Size);
110 const CData *EmptyDelta() const;
111 int CreateDelta(const CSnapshot *pFrom, const CSnapshot *pTo, void *pDstData);
112 int UnpackDelta(const CSnapshot *pFrom, CSnapshot *pTo, const void *pSrcData, int DataSize, bool Sixup);
113 int DebugDumpDelta(const void *pSrcData, int DataSize);
114};
115
116// CSnapshotStorage
117
118class CSnapshotStorage
119{
120public:
121 class CHolder
122 {
123 public:
124 CHolder *m_pPrev;
125 CHolder *m_pNext;
126
127 int64_t m_Tagtime;
128 int m_Tick;
129
130 int m_SnapSize;
131 int m_AltSnapSize;
132
133 CSnapshot *m_pSnap;
134 CSnapshot *m_pAltSnap;
135 };
136
137 CHolder *m_pFirst;
138 CHolder *m_pLast;
139
140 CSnapshotStorage() { Init(); }
141 ~CSnapshotStorage() { PurgeAll(); }
142 void Init();
143 void PurgeAll();
144 void PurgeUntil(int Tick);
145 void Add(int Tick, int64_t Tagtime, size_t DataSize, const void *pData, size_t AltDataSize, const void *pAltData);
146 int Get(int Tick, int64_t *pTagtime, const CSnapshot **ppData, const CSnapshot **ppAltData) const;
147};
148
149class CSnapshotBuilder
150{
151 enum
152 {
153 MAX_EXTENDED_ITEM_TYPES = 64,
154 };
155
156 char m_aData[CSnapshot::MAX_SIZE];
157 int m_DataSize;
158
159 int m_aOffsets[CSnapshot::MAX_ITEMS];
160 int m_NumItems;
161
162 int m_aExtendedItemTypes[MAX_EXTENDED_ITEM_TYPES];
163 int m_NumExtendedItemTypes;
164
165 bool AddExtendedItemType(int Index);
166 int GetExtendedItemTypeIndex(int TypeId);
167 int GetTypeFromIndex(int Index) const;
168
169 bool m_Sixup = false;
170
171public:
172 CSnapshotBuilder();
173
174 void Init(bool Sixup = false);
175 void Init7(const CSnapshot *pSnapshot);
176
177 void *NewItem(int Type, int Id, int Size);
178
179 CSnapshotItem *GetItem(int Index);
180 int *GetItemData(int Key);
181
182 int Finish(void *pSnapdata);
183};
184
185#endif // ENGINE_SNAPSHOT_H
186