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}
15
16
17using namespace QGBA;
18
19MultiplayerController::MultiplayerController() {
20 GBASIOLockstepInit(&m_lockstep);
21 m_lockstep.context = this;
22 m_lockstep.signal = [](GBASIOLockstep* lockstep, unsigned mask) {
23 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
24 Player* player = &controller->m_players[0];
25 bool woke = false;
26 controller->m_lock.lock();
27 player->waitMask &= ~mask;
28 if (!player->waitMask && player->awake < 1) {
29 mCoreThreadStopWaiting(player->controller->thread());
30 player->awake = 1;
31 woke = true;
32 }
33 controller->m_lock.unlock();
34 return woke;
35 };
36 m_lockstep.wait = [](GBASIOLockstep* lockstep, unsigned mask) {
37 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
38 controller->m_lock.lock();
39 Player* player = &controller->m_players[0];
40 bool slept = false;
41 player->waitMask |= mask;
42 if (player->awake > 0) {
43 mCoreThreadWaitFromThread(player->controller->thread());
44 player->awake = 0;
45 slept = true;
46 }
47 controller->m_lock.unlock();
48 return slept;
49 };
50 m_lockstep.addCycles = [](GBASIOLockstep* lockstep, int id, int32_t cycles) {
51 if (cycles < 0) {
52 abort();
53 }
54 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
55 controller->m_lock.lock();
56 if (!id) {
57 for (int i = 1; i < controller->m_players.count(); ++i) {
58 Player* player = &controller->m_players[i];
59 if (player->node->d.p->mode != controller->m_players[0].node->d.p->mode) {
60 player->controller->setSync(true);
61 continue;
62 }
63 player->controller->setSync(false);
64 player->cyclesPosted += cycles;
65 if (player->awake < 1) {
66 player->node->nextEvent += player->cyclesPosted;
67 mCoreThreadStopWaiting(player->controller->thread());
68 player->awake = 1;
69 }
70 }
71 } else {
72 controller->m_players[id].controller->setSync(true);
73 controller->m_players[id].cyclesPosted += cycles;
74 }
75 controller->m_lock.unlock();
76 };
77 m_lockstep.useCycles = [](GBASIOLockstep* lockstep, int id, int32_t cycles) {
78 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
79 controller->m_lock.lock();
80 Player* player = &controller->m_players[id];
81 player->cyclesPosted -= cycles;
82 if (player->cyclesPosted <= 0) {
83 mCoreThreadWaitFromThread(player->controller->thread());
84 player->awake = 0;
85 }
86 cycles = player->cyclesPosted;
87 controller->m_lock.unlock();
88 return cycles;
89 };
90 m_lockstep.unload = [](GBASIOLockstep* lockstep, int id) {
91 MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
92 controller->m_lock.lock();
93 Player* player = &controller->m_players[id];
94 if (id) {
95 player->controller->setSync(true);
96 player->waitMask &= ~(1 << id);
97 if (!player->waitMask && player->awake < 1) {
98 mCoreThreadStopWaiting(player->controller->thread());
99 player->awake = 1;
100 }
101 } else {
102 for (int i = 1; i < controller->m_players.count(); ++i) {
103 Player* player = &controller->m_players[i];
104 player->controller->setSync(true);
105 player->cyclesPosted += lockstep->players[0]->eventDiff;
106 if (player->awake < 1) {
107 player->node->nextEvent += player->cyclesPosted;
108 mCoreThreadStopWaiting(player->controller->thread());
109 player->awake = 1;
110 }
111 }
112 }
113 controller->m_lock.unlock();
114 };
115}
116
117MultiplayerController::~MultiplayerController() {
118 GBASIOLockstepDeinit(&m_lockstep);
119}
120
121bool MultiplayerController::attachGame(GameController* controller) {
122 if (m_lockstep.attached == MAX_GBAS) {
123 return false;
124 }
125
126 mCoreThread* thread = controller->thread();
127 if (!thread) {
128 return false;
129 }
130
131#ifdef M_CORE_GBA
132 if (controller->platform() == PLATFORM_GBA) {
133 GBA* gba = static_cast<GBA*>(thread->core->board);
134
135 GBASIOLockstepNode* node = new GBASIOLockstepNode;
136 GBASIOLockstepNodeCreate(node);
137 GBASIOLockstepAttachNode(&m_lockstep, node);
138 m_players.append({
139 controller,
140 node,
141 1,
142 0,
143 0
144 });
145
146 GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
147 GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32);
148
149 emit gameAttached();
150 return true;
151 }
152#endif
153
154 return false;
155}
156
157void MultiplayerController::detachGame(GameController* controller) {
158 mCoreThread* thread = controller->thread();
159 if (!thread) {
160 return;
161 }
162 for (int i = 0; i < m_players.count(); ++i) {
163 m_players[i].controller->threadInterrupt();
164 }
165#ifdef M_CORE_GBA
166 if (controller->platform() == PLATFORM_GBA) {
167 GBA* gba = static_cast<GBA*>(thread->core->board);
168 GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
169 GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
170 GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32);
171 if (node) {
172 GBASIOLockstepDetachNode(&m_lockstep, node);
173 delete node;
174 }
175 }
176#endif
177
178 controller->threadContinue();
179 for (int i = 0; i < m_players.count(); ++i) {
180 if (m_players[i].controller == controller) {
181 m_players.removeAt(i);
182 break;
183 }
184 }
185 for (int i = 0; i < m_players.count(); ++i) {
186 m_players[i].controller->threadContinue();
187 }
188 emit gameDetached();
189}
190
191int MultiplayerController::playerId(GameController* controller) {
192 for (int i = 0; i < m_players.count(); ++i) {
193 if (m_players[i].controller == controller) {
194 return i;
195 }
196 }
197 return -1;
198}
199
200int MultiplayerController::attached() {
201 int num;
202 num = m_lockstep.attached;
203 return num;
204}