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