all repos — mgba @ ee3edbbd19a9bff0b7e3428dd0c09ca37b452291

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 "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}