Browse Source

more multiplayer preparations, packet tx rx

Thomas B 1 month ago
parent
commit
082923aca8
5 changed files with 160 additions and 53 deletions
  1. 2
    2
      Makefile
  2. 14
    4
      src/game.c
  3. 5
    0
      src/game.h
  4. 138
    46
      src/multiplayer.c
  5. 1
    1
      src/multiplayer.h

+ 2
- 2
Makefile View File

48
 ROMU := $(GBDK_HOME)/bin/romusage
48
 ROMU := $(GBDK_HOME)/bin/romusage
49
 GB_EMU := gearboy
49
 GB_EMU := gearboy
50
 SGB_EMU := sameboy
50
 SGB_EMU := sameboy
51
-BGB_EMU := wine ~/bin/bgb/bgb.exe
52
-GBE_EMU := wine ~/bin/gbe/gbe_plus_qt.exe
51
+BGB_EMU := ~/bin/bgb/bgb.exe
52
+GBE_EMU := ~/bin/gbe/gbe_plus_qt.exe
53
 FLASHER := flashgbx
53
 FLASHER := flashgbx
54
 
54
 
55
 LCCFLAGS := -Wa-l -Wl-m -Wp-MMD -Wf--opt-code-speed
55
 LCCFLAGS := -Wa-l -Wl-m -Wp-MMD -Wf--opt-code-speed

+ 14
- 4
src/game.c View File

138
     }
138
     }
139
 }
139
 }
140
 
140
 
141
+void game_get_mp_state(void) NONBANKED {
142
+    // TODO pass own pos to mp
143
+    //mp_new_state();
144
+}
145
+
146
+void game_set_mp_player2(struct mp_player_state *state) NONBANKED {
147
+    // TODO update p2 pos
148
+}
149
+
150
+void game_set_mp_shot(struct mp_shot_state *state) NONBANKED {
151
+    // TODO add shot
152
+}
153
+
141
 int32_t game(enum GAME_MODE mode) NONBANKED {
154
 int32_t game(enum GAME_MODE mode) NONBANKED {
142
     snd_music_off();
155
     snd_music_off();
143
     snd_note_off();
156
     snd_note_off();
180
         key_read();
193
         key_read();
181
 
194
 
182
         if (mode != GM_SINGLE) {
195
         if (mode != GM_SINGLE) {
183
-            if (mp_handle()) {
184
-                // TODO
185
-                //mp_new_state();
186
-            }
196
+            mp_handle();
187
         }
197
         }
188
 
198
 
189
         enum ACCELERATION acc = 0;
199
         enum ACCELERATION acc = 0;

+ 5
- 0
src/game.h View File

21
 #define __GAME_H__
21
 #define __GAME_H__
22
 
22
 
23
 #include <stdint.h>
23
 #include <stdint.h>
24
+#include "multiplayer.h"
24
 
25
 
25
 #define HEALTH_MAX 0x1FF
26
 #define HEALTH_MAX 0x1FF
26
 #define HEALTH_SHIFT 1
27
 #define HEALTH_SHIFT 1
33
     GM_MULTI,
34
     GM_MULTI,
34
 };
35
 };
35
 
36
 
37
+void game_get_mp_state(void);
38
+void game_set_mp_player2(struct mp_player_state *state);
39
+void game_set_mp_shot(struct mp_shot_state *state);
40
+
36
 int32_t game(enum GAME_MODE mode);
41
 int32_t game(enum GAME_MODE mode);
37
 
42
 
38
 #endif // __GAME_H__
43
 #endif // __GAME_H__

+ 138
- 46
src/multiplayer.c View File

17
  * See <http://www.gnu.org/licenses/>.
17
  * See <http://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
+#include <gbdk/emu_debug.h>
21
+
20
 #include "game.h"
22
 #include "game.h"
21
 #include "timer.h"
23
 #include "timer.h"
22
 #include "multiplayer.h"
24
 #include "multiplayer.h"
24
 #define MASTER_HELLO 0x42
26
 #define MASTER_HELLO 0x42
25
 #define SLAVE_HELLO 0x23
27
 #define SLAVE_HELLO 0x23
26
 
28
 
27
-#define RETRANSMIT_TIME 200
29
+#define RETRANSMIT_TIME_HELLO 200
30
+#define RETRANSMIT_TIME_GAME 10
28
 
31
 
29
 #define PKT_TYPE_PLAYER 0x00
32
 #define PKT_TYPE_PLAYER 0x00
30
 #define PKT_TYPE_SHOT 0x01
33
 #define PKT_TYPE_SHOT 0x01
38
     union {
41
     union {
39
         struct mp_player_state player;
42
         struct mp_player_state player;
40
         struct mp_shot_state shot;
43
         struct mp_shot_state shot;
41
-    } data;
44
+    };
42
 };
45
 };
43
 
46
 
44
-#define PKT_SIZE_PLAYER (sizeof(struct mp_player_state) + sizeof(struct mp_header))
45
-#define PKT_SIZE_SHOT (sizeof(struct mp_shot_state) + sizeof(struct mp_header))
46
-
47
 enum mp_state {
47
 enum mp_state {
48
     MP_M_SEND = 0,
48
     MP_M_SEND = 0,
49
     MP_M_WAIT = 1,
49
     MP_M_WAIT = 1,
58
 static uint16_t next_t = 0;
58
 static uint16_t next_t = 0;
59
 static uint8_t our_turn = 0;
59
 static uint8_t our_turn = 0;
60
 
60
 
61
-static uint8_t *data = NULL;
62
-static uint8_t remaining = 0;
63
-
64
-static uint8_t rx_buff[sizeof(struct mp_packet)] = {0};
65
-static uint8_t rx_len = 0;
66
-
67
 uint8_t mp_connection_status = 0;
61
 uint8_t mp_connection_status = 0;
68
 
62
 
63
+static void mp_game_init(void);
64
+
69
 static inline void Tx(uint8_t x) {
65
 static inline void Tx(uint8_t x) {
70
     SB_REG = x;
66
     SB_REG = x;
71
     SC_REG = SIOF_XFER_START | SIOF_CLOCK_INT;
67
     SC_REG = SIOF_XFER_START | SIOF_CLOCK_INT;
76
     SC_REG = SIOF_XFER_START | SIOF_CLOCK_EXT;
72
     SC_REG = SIOF_XFER_START | SIOF_CLOCK_EXT;
77
 }
73
 }
78
 
74
 
79
-static inline void tx_rx(uint8_t x) {
80
-    our_turn ? Tx(x) : Rx(x);
81
-}
82
-
83
-static inline void transmit(struct mp_packet *pkt) {
84
-
85
-}
86
-
87
 static inline uint8_t transmitting(void) {
75
 static inline uint8_t transmitting(void) {
88
     return SC_REG & SIOF_XFER_START;
76
     return SC_REG & SIOF_XFER_START;
89
 }
77
 }
90
 
78
 
79
+// ----------------------------------------------------------------------------
80
+// Initial Handshake
81
+// ----------------------------------------------------------------------------
82
+
91
 uint8_t mp_master_ready(void) BANKED {
83
 uint8_t mp_master_ready(void) BANKED {
92
     switch (state) {
84
     switch (state) {
93
         case MP_M_SEND:
85
         case MP_M_SEND:
94
             Tx(MASTER_HELLO);
86
             Tx(MASTER_HELLO);
95
-            next_t = timer_get() + RETRANSMIT_TIME;
87
+            next_t = timer_get() + RETRANSMIT_TIME_HELLO;
96
             mp_connection_status++;
88
             mp_connection_status++;
97
             state = MP_M_WAIT;
89
             state = MP_M_WAIT;
98
             break;
90
             break;
101
             if (!transmitting()) {
93
             if (!transmitting()) {
102
                 if (SB_REG == SLAVE_HELLO) {
94
                 if (SB_REG == SLAVE_HELLO) {
103
                     Rx(SLAVE_HELLO);
95
                     Rx(SLAVE_HELLO);
104
-                    next_t = timer_get() + RETRANSMIT_TIME;
96
+                    next_t = timer_get() + RETRANSMIT_TIME_HELLO;
105
                     mp_connection_status++;
97
                     mp_connection_status++;
106
                     state = MP_M_REPLY;
98
                     state = MP_M_REPLY;
107
                 }
99
                 }
134
 
126
 
135
 void mp_master_start(void) BANKED {
127
 void mp_master_start(void) BANKED {
136
     our_turn = 1;
128
     our_turn = 1;
137
-    remaining = 0;
138
-    next_t = timer_get() + RETRANSMIT_TIME;
139
-
129
+    mp_game_init();
140
     game(GM_MULTI);
130
     game(GM_MULTI);
141
-
142
     state = 0;
131
     state = 0;
143
 }
132
 }
144
 
133
 
146
     switch (state) {
135
     switch (state) {
147
         case MP_S_START:
136
         case MP_S_START:
148
             Rx(SLAVE_HELLO);
137
             Rx(SLAVE_HELLO);
149
-            next_t = timer_get() + RETRANSMIT_TIME;
138
+            next_t = timer_get() + RETRANSMIT_TIME_HELLO;
150
             mp_connection_status++;
139
             mp_connection_status++;
151
             state = MP_S_WAIT;
140
             state = MP_S_WAIT;
152
             break;
141
             break;
155
             if (!transmitting()) {
144
             if (!transmitting()) {
156
                 if (SB_REG == MASTER_HELLO) {
145
                 if (SB_REG == MASTER_HELLO) {
157
                     Tx(MASTER_HELLO);
146
                     Tx(MASTER_HELLO);
158
-                    next_t = timer_get() + RETRANSMIT_TIME;
147
+                    next_t = timer_get() + RETRANSMIT_TIME_HELLO;
159
                     mp_connection_status++;
148
                     mp_connection_status++;
160
                     state = MP_S_REPLY;
149
                     state = MP_S_REPLY;
161
                 } else {
150
                 } else {
188
 
177
 
189
 void mp_slave_start(void) BANKED {
178
 void mp_slave_start(void) BANKED {
190
     our_turn = 0;
179
     our_turn = 0;
191
-    remaining = 0;
192
-    next_t = timer_get() + RETRANSMIT_TIME;
193
-
180
+    mp_game_init();
194
     game(GM_MULTI);
181
     game(GM_MULTI);
195
-
196
     state = 0;
182
     state = 0;
197
 }
183
 }
198
 
184
 
199
-uint8_t mp_handle(void) BANKED {
200
-    if ((our_turn) && (timer_get() >= next_t) && data && (remaining > 0)) {
201
-        if (rx_len < sizeof(struct mp_packet)) {
202
-            rx_buff[rx_len++] = SB_REG;
203
-        }
204
-        tx_rx(*(data++));
205
-        remaining--;
206
-    } else if ((!our_turn) && (!transmitting()) && data && (remaining > 0)) {
207
-        if (rx_len < sizeof(struct mp_packet)) {
208
-            rx_buff[rx_len++] = SB_REG;
185
+// ----------------------------------------------------------------------------
186
+// Game Runtime
187
+// ----------------------------------------------------------------------------
188
+
189
+#define QUEUE_LEN 5
190
+
191
+static struct mp_packet queue[QUEUE_LEN];
192
+static uint8_t q_head = 0;
193
+static uint8_t q_tail = 0;
194
+static uint8_t q_full = 0;
195
+static uint8_t byte_pos = 0;
196
+
197
+static uint8_t q_len(void) {
198
+    if (q_head == q_tail) {
199
+        if (q_full) {
200
+            return QUEUE_LEN;
201
+        } else {
202
+            return 0;
209
         }
203
         }
210
-        tx_rx(*(data++));
211
-        remaining--;
204
+    } else if (q_head > q_tail) {
205
+        return q_head - q_tail;
206
+    } else {
207
+        return QUEUE_LEN - q_tail + q_head;
212
     }
208
     }
209
+}
213
 
210
 
214
-    return our_turn && (remaining == 0);
211
+static inline void q_inc_head(void) {
212
+    if (q_full && (++q_tail == QUEUE_LEN)) {
213
+        q_tail = 0;
214
+    }
215
+    if (++q_head == QUEUE_LEN) {
216
+        q_head = 0;
217
+    }
218
+    q_full = (q_head == q_tail);
219
+}
220
+
221
+static inline void q_inc_tail(void) {
222
+    q_tail++;
223
+    if (q_tail >= QUEUE_LEN) {
224
+        q_tail = 0;
225
+    }
226
+}
227
+
228
+static void mp_game_init(void) {
229
+    q_head = 0;
230
+    q_tail = 0;
231
+    q_full = 0;
232
+    byte_pos = sizeof(struct mp_packet); // immediately query packet from game
233
+    next_t = timer_get() + RETRANSMIT_TIME_GAME;
234
+}
235
+
236
+static inline void handle_rx(struct mp_packet *pkt) {
237
+    switch (pkt->header.type) {
238
+        case PKT_TYPE_PLAYER:
239
+            game_set_mp_player2(&pkt->player);
240
+            break;
241
+
242
+        case PKT_TYPE_SHOT:
243
+            game_set_mp_shot(&pkt->shot);
244
+            break;
245
+
246
+        default:
247
+#ifdef DEBUG
248
+            EMU_printf("%s: unknown type %hx\n", __func__, (uint8_t)pkt->header.type);
249
+#endif // DEBUG
250
+            break;
251
+    }
252
+}
253
+
254
+static inline void tx_rx(uint8_t x) {
255
+    our_turn ? Tx(x) : Rx(x);
256
+    next_t = timer_get() + RETRANSMIT_TIME_GAME;
257
+}
258
+
259
+void mp_handle(void) BANKED {
260
+    // ensure we always have something in the queue
261
+    if ((q_len() == 0) && (byte_pos >= sizeof(struct mp_packet))) {
262
+        game_get_mp_state();
263
+    }
264
+
265
+    if (byte_pos < sizeof(struct mp_packet)) {
266
+        if ((our_turn && (timer_get() >= next_t)) || ((!our_turn) && (!transmitting()))) {
267
+            uint8_t to_send = ((uint8_t *)(&queue[q_tail]))[byte_pos];
268
+            ((uint8_t *)(&queue[q_tail]))[byte_pos] = SB_REG;
269
+            tx_rx(to_send);
270
+
271
+            byte_pos++;
272
+            if (byte_pos >= sizeof(struct mp_packet)) {
273
+                handle_rx(&queue[q_tail]);
274
+                q_inc_tail();
275
+                if (q_len() > 0) {
276
+                    byte_pos = 0; // keep going
277
+                }
278
+            }
279
+
280
+            our_turn = our_turn ? 0 : 1;
281
+        }
282
+    }
215
 }
283
 }
216
 
284
 
217
 void mp_new_state(struct mp_player_state *state) BANKED {
285
 void mp_new_state(struct mp_player_state *state) BANKED {
218
-    // TODO
286
+#ifdef DEBUG
287
+    if (q_full) {
288
+        EMU_printf("%s: queue overflow\n", __func__);
289
+    }
290
+#endif // DEBUG
291
+
292
+    queue[q_head].header.type = PKT_TYPE_PLAYER;
293
+    queue[q_head].player = *state;
294
+    q_inc_head();
295
+
296
+    if ((q_len() == 1) && (byte_pos >= sizeof(struct mp_packet))) {
297
+        byte_pos = 0; // start transmitting
298
+    }
219
 }
299
 }
220
 
300
 
221
 void mp_add_shot(struct mp_shot_state *state) BANKED {
301
 void mp_add_shot(struct mp_shot_state *state) BANKED {
222
-    // TODO
302
+#ifdef DEBUG
303
+    if (q_full) {
304
+        EMU_printf("%s: queue overflow\n", __func__);
305
+    }
306
+#endif // DEBUG
307
+
308
+    queue[q_head].header.type = PKT_TYPE_SHOT;
309
+    queue[q_head].shot = *state;
310
+    q_inc_head();
311
+
312
+    if ((q_len() == 1) && (byte_pos >= sizeof(struct mp_packet))) {
313
+        byte_pos = 0; // start transmitting
314
+    }
223
 }
315
 }

+ 1
- 1
src/multiplayer.h View File

42
 uint8_t mp_slave_ready(void) BANKED;
42
 uint8_t mp_slave_ready(void) BANKED;
43
 void mp_slave_start(void) BANKED;
43
 void mp_slave_start(void) BANKED;
44
 
44
 
45
-uint8_t mp_handle(void) BANKED;
45
+void mp_handle(void) BANKED;
46
 
46
 
47
 void mp_new_state(struct mp_player_state *state) BANKED;
47
 void mp_new_state(struct mp_player_state *state) BANKED;
48
 void mp_add_shot(struct mp_shot_state *state) BANKED;
48
 void mp_add_shot(struct mp_shot_state *state) BANKED;

Loading…
Cancel
Save