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
148 emit gameAttached();
149 return true;
150 }
151#endif
152
153 return false;
154}
155
156void MultiplayerController::detachGame(GameController* controller) {
157 mCoreThread* thread = controller->thread();
158 if (!thread) {
159 return;
160 }
161 for (int i = 0; i < m_players.count(); ++i) {
162 m_players[i].controller->threadInterrupt();
163 }
164#ifdef M_CORE_GBA
165 if (controller->platform() == PLATFORM_GBA) {
166 GBA* gba = static_cast<GBA*>(thread->core->board);
167 GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
168 GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
169 if (node) {
170 GBASIOLockstepDetachNode(&m_lockstep, node);
171 delete node;
172 }
173 }
174#endif
175
176 controller->threadContinue();
177 for (int i = 0; i < m_players.count(); ++i) {
178 if (m_players[i].controller == controller) {
179 m_players.removeAt(i);
180 break;
181 }
182 }
183 for (int i = 0; i < m_players.count(); ++i) {
184 m_players[i].controller->threadContinue();
185 }
186 emit gameDetached();
187}
188
189int MultiplayerController::playerId(GameController* controller) {
190 for (int i = 0; i < m_players.count(); ++i) {
191 if (m_players[i].controller == controller) {
192 return i;
193 }
194 }
195 return -1;
196}
197
198int MultiplayerController::attached() {
199 int num;
200 num = m_lockstep.attached;
201 return num;
202}