src/platform/qt/MultiplayerController.cpp (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "MultiplayerController.h"
7
8#include "CoreController.h"
9
10#ifdef M_CORE_GBA
11#include <mgba/internal/gba/gba.h>
12#endif
13#ifdef M_CORE_GB
14#include <mgba/internal/gb/gb.h>
15#endif
16
17using namespace QGBA;
18
19#ifdef M_CORE_GB
20MultiplayerController::Player::Player(CoreController* coreController, GBSIOLockstepNode* node)
21 : controller(coreController)
22 , gbNode(node)
23{
24}
25#endif
26
27#ifdef M_CORE_GBA
28MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* node)
29 : controller(coreController)
30 , gbaNode(node)
31{
32}
33#endif
34
35MultiplayerController::MultiplayerController() {
36 mLockstepInit(&m_lockstep);
37 m_lockstep.context = this;
38 m_lockstep.lock = [](mLockstep* lockstep) {
39 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
40 controller->m_lock.lock();
41 };
42 m_lockstep.unlock = [](mLockstep* lockstep) {
43 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
44 controller->m_lock.unlock();
45 };
46 m_lockstep.signal = [](mLockstep* lockstep, unsigned mask) {
47 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
48 Player* player = &controller->m_players[0];
49 bool woke = false;
50 player->waitMask &= ~mask;
51 if (!player->waitMask && player->awake < 1) {
52 mCoreThreadStopWaiting(player->controller->thread());
53 player->awake = 1;
54 woke = true;
55 }
56 return woke;
57 };
58 m_lockstep.wait = [](mLockstep* lockstep, unsigned mask) {
59 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
60 Player* player = &controller->m_players[0];
61 bool slept = false;
62 player->waitMask |= mask;
63 if (player->awake > 0) {
64 mCoreThreadWaitFromThread(player->controller->thread());
65 player->awake = 0;
66 slept = true;
67 }
68 return slept;
69 };
70 m_lockstep.addCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
71 if (cycles < 0) {
72 abort();
73 }
74 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
75 if (!id) {
76 for (int i = 1; i < controller->m_players.count(); ++i) {
77 Player* player = &controller->m_players[i];
78#ifdef M_CORE_GBA
79 if (player->controller->platform() == PLATFORM_GBA && player->gbaNode->d.p->mode != controller->m_players[0].gbaNode->d.p->mode) {
80 player->controller->setSync(true);
81 continue;
82 }
83#endif
84 player->controller->setSync(false);
85 player->cyclesPosted += cycles;
86 if (player->awake < 1) {
87 switch (player->controller->platform()) {
88#ifdef M_CORE_GBA
89 case PLATFORM_GBA:
90 player->gbaNode->nextEvent += player->cyclesPosted;
91 break;
92#endif
93#ifdef M_CORE_GB
94 case PLATFORM_GB:
95 player->gbNode->nextEvent += player->cyclesPosted;
96 break;
97#endif
98 default:
99 break;
100 }
101 mCoreThreadStopWaiting(player->controller->thread());
102 player->awake = 1;
103 }
104 }
105 } else {
106 controller->m_players[id].controller->setSync(true);
107 controller->m_players[id].cyclesPosted += cycles;
108 }
109 };
110 m_lockstep.useCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
111 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
112 Player* player = &controller->m_players[id];
113 player->cyclesPosted -= cycles;
114 if (player->cyclesPosted <= 0) {
115 mCoreThreadWaitFromThread(player->controller->thread());
116 player->awake = 0;
117 }
118 cycles = player->cyclesPosted;
119 return cycles;
120 };
121 m_lockstep.unusedCycles= [](mLockstep* lockstep, int id) {
122 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
123 Player* player = &controller->m_players[id];
124 auto cycles = player->cyclesPosted;
125 return cycles;
126 };
127 m_lockstep.unload = [](mLockstep* lockstep, int id) {
128 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
129 if (id) {
130 Player* player = &controller->m_players[id];
131 player->controller->setSync(true);
132 player->cyclesPosted = 0;
133
134 // release master GBA if it is waiting for this GBA
135 player = &controller->m_players[0];
136 player->waitMask &= ~(1 << id);
137 if (!player->waitMask && player->awake < 1) {
138 mCoreThreadStopWaiting(player->controller->thread());
139 player->awake = 1;
140 }
141 } else {
142 for (int i = 1; i < controller->m_players.count(); ++i) {
143 Player* player = &controller->m_players[i];
144 player->controller->setSync(true);
145 switch (player->controller->platform()) {
146#ifdef M_CORE_GBA
147 case PLATFORM_GBA:
148 player->cyclesPosted += reinterpret_cast<GBASIOLockstep*>(lockstep)->players[0]->eventDiff;
149 break;
150#endif
151#ifdef M_CORE_GB
152 case PLATFORM_GB:
153 player->cyclesPosted += reinterpret_cast<GBSIOLockstep*>(lockstep)->players[0]->eventDiff;
154 break;
155#endif
156 default:
157 break;
158 }
159 if (player->awake < 1) {
160 switch (player->controller->platform()) {
161#ifdef M_CORE_GBA
162 case PLATFORM_GBA:
163 player->gbaNode->nextEvent += player->cyclesPosted;
164 break;
165#endif
166#ifdef M_CORE_GB
167 case PLATFORM_GB:
168 player->gbNode->nextEvent += player->cyclesPosted;
169 break;
170#endif
171 default:
172 break;
173 }
174 mCoreThreadStopWaiting(player->controller->thread());
175 player->awake = 1;
176 }
177 }
178 }
179 };
180}
181
182MultiplayerController::~MultiplayerController() {
183 mLockstepDeinit(&m_lockstep);
184}
185
186bool MultiplayerController::attachGame(CoreController* controller) {
187 if (m_lockstep.attached == MAX_GBAS) {
188 return false;
189 }
190
191 if (m_lockstep.attached == 0) {
192 switch (controller->platform()) {
193#ifdef M_CORE_GBA
194 case PLATFORM_GBA:
195 GBASIOLockstepInit(&m_gbaLockstep);
196 break;
197#endif
198#ifdef M_CORE_GB
199 case PLATFORM_GB:
200 GBSIOLockstepInit(&m_gbLockstep);
201 break;
202#endif
203 default:
204 return false;
205 }
206 }
207
208 mCoreThread* thread = controller->thread();
209 if (!thread) {
210 return false;
211 }
212
213 switch (controller->platform()) {
214#ifdef M_CORE_GBA
215 case PLATFORM_GBA: {
216 GBA* gba = static_cast<GBA*>(thread->core->board);
217
218 GBASIOLockstepNode* node = new GBASIOLockstepNode;
219 GBASIOLockstepNodeCreate(node);
220 GBASIOLockstepAttachNode(&m_gbaLockstep, node);
221 m_players.append({controller, node});
222
223 GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
224 GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32);
225
226 emit gameAttached();
227 return true;
228 }
229#endif
230#ifdef M_CORE_GB
231 case PLATFORM_GB: {
232 GB* gb = static_cast<GB*>(thread->core->board);
233
234 GBSIOLockstepNode* node = new GBSIOLockstepNode;
235 GBSIOLockstepNodeCreate(node);
236 GBSIOLockstepAttachNode(&m_gbLockstep, node);
237 m_players.append({controller, node});
238
239 GBSIOSetDriver(&gb->sio, &node->d);
240
241 emit gameAttached();
242 return true;
243 }
244#endif
245 default:
246 break;
247 }
248
249 return false;
250}
251
252void MultiplayerController::detachGame(CoreController* controller) {
253 if (m_players.empty()) {
254 return;
255 }
256 mCoreThread* thread = controller->thread();
257 if (!thread) {
258 return;
259 }
260 QList<CoreController::Interrupter> interrupters;
261
262 for (int i = 0; i < m_players.count(); ++i) {
263 interrupters.append(m_players[i].controller);
264 }
265 switch (controller->platform()) {
266#ifdef M_CORE_GBA
267 case PLATFORM_GBA: {
268 GBA* gba = static_cast<GBA*>(thread->core->board);
269 GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
270 GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
271 GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32);
272 if (node) {
273 GBASIOLockstepDetachNode(&m_gbaLockstep, node);
274 delete node;
275 }
276 break;
277 }
278#endif
279#ifdef M_CORE_GB
280 case PLATFORM_GB: {
281 GB* gb = static_cast<GB*>(thread->core->board);
282 GBSIOLockstepNode* node = reinterpret_cast<GBSIOLockstepNode*>(gb->sio.driver);
283 GBSIOSetDriver(&gb->sio, nullptr);
284 if (node) {
285 GBSIOLockstepDetachNode(&m_gbLockstep, node);
286 delete node;
287 }
288 break;
289 }
290#endif
291 default:
292 break;
293 }
294
295 for (int i = 0; i < m_players.count(); ++i) {
296 if (m_players[i].controller == controller) {
297 m_players.removeAt(i);
298 break;
299 }
300 }
301 emit gameDetached();
302}
303
304int MultiplayerController::playerId(CoreController* controller) {
305 for (int i = 0; i < m_players.count(); ++i) {
306 if (m_players[i].controller == controller) {
307 return i;
308 }
309 }
310 return -1;
311}
312
313int MultiplayerController::attached() {
314 int num;
315 num = m_lockstep.attached;
316 return num;
317}