all repos — mgba @ ba4f3ae9c693e29ca504133d8e263d5d439d4af4

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#ifdef M_CORE_GBA
163	if (controller->platform() == PLATFORM_GBA) {
164		GBA* gba = static_cast<GBA*>(thread->core->board);
165		GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
166		GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
167		GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32);
168		if (node) {
169			GBASIOLockstepDetachNode(&m_lockstep, node);
170			delete node;
171		}
172	}
173#endif
174	for (int i = 0; i < m_players.count(); ++i) {
175		if (m_players[i].controller == controller) {
176			m_players.removeAt(i);
177			break;
178		}
179	}
180	emit gameDetached();
181}
182
183int MultiplayerController::playerId(GameController* controller) {
184	for (int i = 0; i < m_players.count(); ++i) {
185		if (m_players[i].controller == controller) {
186			return i;
187		}
188	}
189	return -1;
190}
191
192int MultiplayerController::attached() {
193	int num;
194	num = m_lockstep.attached;
195	return num;
196}