1 /*
2 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3 * It is copyright by its individual contributors, as recorded in the
4 * project's Git history. See COPYING.txt at the top level for license
5 * terms and a link to the Git history.
6 */
7 #pragma once
8
9 #include <type_traits>
10 #include "dxxerror.h"
11 #include "object.h"
12 #include "powerup.h"
13 #include "serial.h"
14 #include "fwd-player.h"
15
16 #define _UNPACK_MULTIPLAYER_SERIAL_MESSAGE(A,...) A, ## __VA_ARGS__
17 #define DEFINE_MULTIPLAYER_SERIAL_MESSAGE(C,T,V,A) \
18 DEFINE_SERIAL_UDT_TO_MESSAGE(T,V, (multiplayer_command<C>(), _UNPACK_MULTIPLAYER_SERIAL_MESSAGE A)); \
19 ASSERT_SERIAL_UDT_MESSAGE_SIZE(T, command_length<C>::value)
20
21 #define define_multiplayer_command(NAME,SIZE) NAME,
22
23 #if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
24 #define for_each_multiplayer_command(VALUE) \
25 VALUE(MULTI_POSITION , 1 + quaternionpos::packed_size::value) \
26 VALUE(MULTI_REAPPEAR , 4) \
27 VALUE(MULTI_FIRE , 18) \
28 VALUE(MULTI_FIRE_TRACK , 21) \
29 VALUE(MULTI_FIRE_BOMB , 20) \
30 VALUE(MULTI_REMOVE_OBJECT , 4) \
31 VALUE(MULTI_MESSAGE , 37) /* (MAX_MESSAGE_LENGTH = 40) */ \
32 VALUE(MULTI_QUIT , 2) \
33 VALUE(MULTI_PLAY_SOUND , 8) \
34 VALUE(MULTI_CONTROLCEN , 4) \
35 VALUE(MULTI_ROBOT_CLAIM , 5) \
36 VALUE(MULTI_CLOAK , 2) \
37 VALUE(MULTI_ENDLEVEL_START , DXX_MP_SIZE_ENDLEVEL_START) \
38 VALUE(MULTI_CREATE_EXPLOSION , 2) \
39 VALUE(MULTI_CONTROLCEN_FIRE , 16) \
40 VALUE(MULTI_CREATE_POWERUP , 19) \
41 VALUE(MULTI_DECLOAK , 2) \
42 VALUE(MULTI_ROBOT_POSITION , 5 + quaternionpos::packed_size::value) \
43 VALUE(MULTI_PLAYER_DERES , DXX_MP_SIZE_PLAYER_RELATED) \
44 VALUE(MULTI_DOOR_OPEN , DXX_MP_SIZE_DOOR_OPEN) \
45 VALUE(MULTI_ROBOT_EXPLODE , 7) \
46 VALUE(MULTI_ROBOT_RELEASE , 5) \
47 VALUE(MULTI_ROBOT_FIRE , 18) \
48 VALUE(MULTI_SCORE , 6) \
49 VALUE(MULTI_CREATE_ROBOT , 6) \
50 VALUE(MULTI_TRIGGER , 3) \
51 VALUE(MULTI_BOSS_TELEPORT , 5) \
52 VALUE(MULTI_BOSS_CLOAK , 3) \
53 VALUE(MULTI_BOSS_START_GATE , 3) \
54 VALUE(MULTI_BOSS_STOP_GATE , 3) \
55 VALUE(MULTI_BOSS_CREATE_ROBOT , 8) \
56 VALUE(MULTI_CREATE_ROBOT_POWERUPS, 27) \
57 VALUE(MULTI_HOSTAGE_DOOR , 7) \
58 VALUE(MULTI_SAVE_GAME , 2+24) /* (ubyte slot, uint id, char name[20]) */ \
59 VALUE(MULTI_RESTORE_GAME , 2+4) /* (ubyte slot, uint id) */ \
60 VALUE(MULTI_HEARTBEAT , 5) \
61 VALUE(MULTI_KILLGOALS , 1 + MAX_PLAYERS) \
62 VALUE(MULTI_DO_BOUNTY , 2) \
63 VALUE(MULTI_TYPING_STATE , 3) \
64 VALUE(MULTI_GMODE_UPDATE , 3) \
65 VALUE(MULTI_KILL_HOST , 7) \
66 VALUE(MULTI_KILL_CLIENT , 5) \
67 VALUE(MULTI_RANK , 3) \
68 VALUE(MULTI_DROP_WEAPON , 10) \
69 VALUE(MULTI_PLAYER_INV , DXX_MP_SIZE_PLAYER_INVENTORY) \
70 D2X_MP_COMMANDS(VALUE) \
71
72 #if defined(DXX_BUILD_DESCENT_I)
73 #define DXX_MP_SIZE_ENDLEVEL_START 3
74 #define DXX_MP_SIZE_PLAYER_RELATED 58
75 #define DXX_MP_SIZE_PLAYER_INVENTORY 15
76 #define DXX_MP_SIZE_BEGIN_SYNC 37
77 #define DXX_MP_SIZE_DOOR_OPEN 4
78 #define D2X_MP_COMMANDS(VALUE)
79 #elif defined(DXX_BUILD_DESCENT_II)
80 #define DXX_MP_SIZE_ENDLEVEL_START 2
81 #define DXX_MP_SIZE_PLAYER_RELATED (98+10)
82 #define DXX_MP_SIZE_PLAYER_INVENTORY 21
83 #define DXX_MP_SIZE_BEGIN_SYNC 41
84 #define DXX_MP_SIZE_DOOR_OPEN 5
85 #define D2X_MP_COMMANDS(VALUE) \
86 VALUE(MULTI_MARKER , 55) \
87 VALUE(MULTI_GUIDED , 26) \
88 VALUE(MULTI_STOLEN_ITEMS , 1 + std::tuple_size<decltype(d_thief_unique_state::Stolen_items)>::value) \
89 VALUE(MULTI_WALL_STATUS , 6) /* send to new players */ \
90 VALUE(MULTI_SEISMIC , 5) \
91 VALUE(MULTI_LIGHT , 16) \
92 VALUE(MULTI_START_TRIGGER , 2) \
93 VALUE(MULTI_FLAGS , 6) \
94 VALUE(MULTI_DROP_BLOB , 2) \
95 VALUE(MULTI_SOUND_FUNCTION , 4) \
96 VALUE(MULTI_CAPTURE_BONUS , 2) \
97 VALUE(MULTI_GOT_FLAG , 2) \
98 VALUE(MULTI_DROP_FLAG , 8) \
99 VALUE(MULTI_FINISH_GAME , 2) \
100 VALUE(MULTI_ORB_BONUS , 3) \
101 VALUE(MULTI_GOT_ORB , 2) \
102 VALUE(MULTI_EFFECT_BLOWUP , 17) \
103 VALUE(MULTI_VULWPN_AMMO_ADJ , 6) \
104 VALUE(MULTI_UPDATE_BUDDY_STATE, 7) \
105
106 #endif
107
108 #include "dxxsconf.h"
109
110 enum multiplayer_command_t : uint8_t
111 {
112 for_each_multiplayer_command(define_multiplayer_command)
113 };
114
115 template <multiplayer_command_t>
116 struct command_length;
117 #define define_command_length(NAME,SIZE) \
118 template <> \
119 struct command_length<NAME> : public std::integral_constant<unsigned, SIZE> {};
120 for_each_multiplayer_command(define_command_length);
121
122 template <multiplayer_command_t C>
123 struct multi_command : public std::array<uint8_t, command_length<C>::value>
124 {
125 };
126
127 void _multi_send_data(const uint8_t *buf, unsigned len, int priority);
128
129 template <multiplayer_command_t C>
multi_send_data(uint8_t * const buf,const unsigned len,const int priority)130 static inline void multi_send_data(uint8_t *const buf, const unsigned len, const int priority)
131 {
132 buf[0] = C;
133 constexpr unsigned expected = command_length<C>::value;
134 #ifdef DXX_CONSTANT_TRUE
135 if (DXX_CONSTANT_TRUE(len != expected))
136 DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_multi_send_data, "wrong packet size");
137 #endif
138 if (len != expected)
139 {
140 Error("multi_send_data: Packet type %i length: %i, expected: %i\n", C, len, expected);
141 }
142 _multi_send_data(buf, len, priority);
143 }
144
145 template <multiplayer_command_t C>
multi_send_data(multi_command<C> & buf,const int priority)146 static inline void multi_send_data(multi_command<C> &buf, const int priority)
147 {
148 buf[0] = C;
149 _multi_send_data(buf.data(), buf.size(), priority);
150 }
151
152 template <typename T>
multi_serialize_read(const uint8_t * const buf,T & t)153 static inline void multi_serialize_read(const uint8_t *const buf, T &t)
154 {
155 serial::reader::bytebuffer_t b(buf);
156 serial::process_buffer(b, t);
157 }
158
159 template <typename T>
multi_serialize_write(int priority,const T & t)160 static inline void multi_serialize_write(int priority, const T &t)
161 {
162 constexpr size_t maximum_size = serial::message_type<T>::maximum_size;
163 uint8_t buf[maximum_size];
164 serial::writer::bytebuffer_t b(buf);
165 serial::process_buffer(b, t);
166 _multi_send_data(buf, maximum_size, priority);
167 }
168
169 template <multiplayer_command_t C>
170 using multiplayer_command = serial::pad<1, static_cast<uint8_t>(C)>;
171
172 #endif
173