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