all repos — mgba @ 9b0393d50ffcd27c487740098c3c0bb72b16529f

mGBA Game Boy Advance Emulator

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::MultiplayerController() {
 20	mLockstepInit(&m_lockstep);
 21	m_lockstep.context = this;
 22	m_lockstep.signal = [](mLockstep* 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 = [](mLockstep* 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 = [](mLockstep* 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->controller->platform() == PLATFORM_GBA && player->gbaNode->d.p->mode != controller->m_players[0].gbaNode->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					switch (player->controller->platform()) {
 67#ifdef M_CORE_GBA
 68					case PLATFORM_GBA:
 69						player->gbaNode->nextEvent += player->cyclesPosted;
 70						break;
 71#endif
 72#ifdef M_CORE_GB
 73					case PLATFORM_GB:
 74						player->gbNode->nextEvent += player->cyclesPosted;
 75						break;
 76#endif
 77					default:
 78						break;
 79					}
 80					mCoreThreadStopWaiting(player->controller->thread());
 81					player->awake = 1;
 82				}
 83			}
 84		} else {
 85			controller->m_players[id].controller->setSync(true);
 86			controller->m_players[id].cyclesPosted += cycles;
 87		}
 88		controller->m_lock.unlock();
 89	};
 90	m_lockstep.useCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
 91		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 92		controller->m_lock.lock();
 93		Player* player = &controller->m_players[id];
 94		player->cyclesPosted -= cycles;
 95		if (player->cyclesPosted <= 0) {
 96			mCoreThreadWaitFromThread(player->controller->thread());
 97			player->awake = 0;
 98		}
 99		cycles = player->cyclesPosted;
100		controller->m_lock.unlock();
101		return cycles;
102	};
103	m_lockstep.unload = [](mLockstep* lockstep, int id) {
104		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
105		controller->m_lock.lock();
106		Player* player = &controller->m_players[id];
107		if (id) {
108			player->controller->setSync(true);
109			player->waitMask &= ~(1 << id);
110			if (!player->waitMask && player->awake < 1) {
111				mCoreThreadStopWaiting(player->controller->thread());
112				player->awake = 1;
113			}
114		} else {
115			for (int i = 1; i < controller->m_players.count(); ++i) {
116				Player* player = &controller->m_players[i];
117				player->controller->setSync(true);
118				switch (player->controller->platform()) {
119#ifdef M_CORE_GBA
120				case PLATFORM_GBA:
121					player->cyclesPosted += reinterpret_cast<GBASIOLockstep*>(lockstep)->players[0]->eventDiff;
122					break;
123#endif
124#ifdef M_CORE_GB
125				case PLATFORM_GB:
126					player->cyclesPosted += reinterpret_cast<GBSIOLockstep*>(lockstep)->players[0]->eventDiff;
127					break;
128#endif
129				default:
130					break;
131				}
132				if (player->awake < 1) {
133					switch (player->controller->platform()) {
134#ifdef M_CORE_GBA
135					case PLATFORM_GBA:
136						player->gbaNode->nextEvent += player->cyclesPosted;
137						break;
138#endif
139#ifdef M_CORE_GB
140					case PLATFORM_GB:
141						player->gbNode->nextEvent += player->cyclesPosted;
142						break;
143#endif
144					default:
145						break;
146					}
147					mCoreThreadStopWaiting(player->controller->thread());
148					player->awake = 1;
149				}
150			}
151		}
152		controller->m_lock.unlock();
153	};
154}
155
156bool MultiplayerController::attachGame(CoreController* controller) {
157	if (m_lockstep.attached == MAX_GBAS) {
158		return false;
159	}
160
161	if (m_lockstep.attached == 0) {
162		switch (controller->platform()) {
163#ifdef M_CORE_GBA
164		case PLATFORM_GBA:
165			GBASIOLockstepInit(&m_gbaLockstep);
166			break;
167#endif
168#ifdef M_CORE_GB
169		case PLATFORM_GB:
170			GBSIOLockstepInit(&m_gbLockstep);
171			break;
172#endif
173		default:
174			return false;
175		}
176	}
177
178	mCoreThread* thread = controller->thread();
179	if (!thread) {
180		return false;
181	}
182
183	switch (controller->platform()) {
184#ifdef M_CORE_GBA
185	case PLATFORM_GBA: {
186		GBA* gba = static_cast<GBA*>(thread->core->board);
187
188		GBASIOLockstepNode* node = new GBASIOLockstepNode;
189		GBASIOLockstepNodeCreate(node);
190		GBASIOLockstepAttachNode(&m_gbaLockstep, node);
191		m_players.append({
192			controller,
193			nullptr,
194			node,
195			1,
196			0,
197			0
198		});
199
200		GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
201
202		emit gameAttached();
203		return true;
204	}
205#endif
206#ifdef M_CORE_GB
207	case PLATFORM_GB: {
208		GB* gb = static_cast<GB*>(thread->core->board);
209
210		GBSIOLockstepNode* node = new GBSIOLockstepNode;
211		GBSIOLockstepNodeCreate(node);
212		GBSIOLockstepAttachNode(&m_gbLockstep, node);
213		m_players.append({
214			controller,
215			node,
216			nullptr,
217			1,
218			0,
219			0
220		});
221
222		GBSIOSetDriver(&gb->sio, &node->d);
223
224		emit gameAttached();
225		return true;
226	}
227#endif
228	default:
229		break;
230	}
231
232	return false;
233}
234
235void MultiplayerController::detachGame(CoreController* controller) {
236	mCoreThread* thread = controller->thread();
237	if (!thread) {
238		return;
239	}
240	QList<CoreController::Interrupter> interrupters;
241
242	for (int i = 0; i < m_players.count(); ++i) {
243		interrupters.append(m_players[i].controller);
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	for (int i = 0; i < m_players.count(); ++i) {
275		if (m_players[i].controller == controller) {
276			m_players.removeAt(i);
277			break;
278		}
279	}
280	emit gameDetached();
281}
282
283int MultiplayerController::playerId(CoreController* controller) {
284	for (int i = 0; i < m_players.count(); ++i) {
285		if (m_players[i].controller == controller) {
286			return i;
287		}
288	}
289	return -1;
290}
291
292int MultiplayerController::attached() {
293	int num;
294	num = m_lockstep.attached;
295	return num;
296}