all repos — mgba @ e28782900da3915e8c8f63efac7d4b5b3402ded3

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