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