all repos — mgba @ 2ddc08e8b409cae1fecb5c46201ace43391ef691

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, int id) {
 23		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 24		GameController* game = controller->m_players[id];
 25		controller->m_lock.lock();
 26		if (--controller->m_asleep[id] == 0) {
 27			mCoreThreadStopWaiting(game->thread());
 28		}
 29		controller->m_lock.unlock();
 30	};
 31	m_lockstep.wait = [](GBASIOLockstep* lockstep, int id) {
 32		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 33		controller->m_lock.lock();
 34		GameController* game = controller->m_players[id];
 35		if (++controller->m_asleep[id] == 1) {
 36			mCoreThreadWaitFromThread(game->thread());
 37		} else if (controller->m_asleep[id] == 0) {
 38			mCoreThreadStopWaiting(game->thread());
 39		}
 40		if (controller->m_asleep[id] > 1) {
 41			//abort();
 42		}
 43		controller->m_lock.unlock();
 44	};
 45}
 46
 47MultiplayerController::~MultiplayerController() {
 48	GBASIOLockstepDeinit(&m_lockstep);
 49}
 50
 51bool MultiplayerController::attachGame(GameController* controller) {
 52	if (m_lockstep.attached == MAX_GBAS) {
 53		return false;
 54	}
 55
 56	mCoreThread* thread = controller->thread();
 57	if (!thread) {
 58		return false;
 59	}
 60
 61#ifdef M_CORE_GBA
 62	if (controller->platform() == PLATFORM_GBA) {
 63		GBA* gba = static_cast<GBA*>(thread->core->board);
 64
 65		GBASIOLockstepNode* node = new GBASIOLockstepNode;
 66		GBASIOLockstepNodeCreate(node);
 67		GBASIOLockstepAttachNode(&m_lockstep, node);
 68		m_players.append(controller);
 69		m_asleep.append(0);
 70
 71		GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
 72		GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32);
 73
 74		emit gameAttached();
 75		return true;
 76	}
 77#endif
 78
 79	return false;
 80}
 81
 82void MultiplayerController::detachGame(GameController* controller) {
 83	if (!m_players.contains(controller)) {
 84		return;
 85	}
 86	mCoreThread* thread = controller->thread();
 87	if (!thread) {
 88		return;
 89	}
 90#ifdef M_CORE_GBA
 91	if (controller->platform() == PLATFORM_GBA) {
 92		GBA* gba = static_cast<GBA*>(thread->core->board);
 93		GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
 94		GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
 95		GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32);
 96		if (node) {
 97			GBASIOLockstepDetachNode(&m_lockstep, node);
 98			delete node;
 99		}
100	}
101#endif
102	int i = m_players.indexOf(controller);
103	m_players.removeAt(i);
104	m_players.removeAt(i);
105	emit gameDetached();
106}
107
108int MultiplayerController::playerId(GameController* controller) {
109	return m_players.indexOf(controller);
110}
111
112int MultiplayerController::attached() {
113	int num;
114	num = m_lockstep.attached;
115	return num;
116}