Split part of MessageManager into non-static NotificationManager

+ Fixed movie recording/playback (for .mmo files)
This commit is contained in:
Sour 2018-07-02 14:49:19 -04:00
parent 04310eddb4
commit c877f73891
36 changed files with 727 additions and 590 deletions

View file

@ -6,6 +6,7 @@
#include "PPU.h"
#include "VideoDecoder.h"
#include "StandardController.h"
#include "NotificationManager.h"
AutomaticRomTest::AutomaticRomTest()
{
@ -104,6 +105,7 @@ int32_t AutomaticRomTest::Run(string filename)
{
EmulationSettings::SetMasterVolume(0);
_console.reset(new Console());
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
if(_console->Initialize(filename)) {
_console->GetControlManager()->RegisterInputProvider(this);

View file

@ -6,7 +6,7 @@
class Console;
class AutomaticRomTest : public INotificationListener, public IInputProvider
class AutomaticRomTest : public INotificationListener, public IInputProvider, public std::enable_shared_from_this<AutomaticRomTest>
{
private:
shared_ptr<Console> _console;

View file

@ -3,6 +3,7 @@
#include "CheatManager.h"
#include "Console.h"
#include "MessageManager.h"
#include "NotificationManager.h"
CheatManager::CheatManager(shared_ptr<Console> console)
{
@ -97,7 +98,7 @@ void CheatManager::AddCode(CodeInfo &code)
} else {
_absoluteCheatCodes.push_back(code);
}
MessageManager::SendNotification(ConsoleNotificationType::CheatAdded);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatAdded);
}
void CheatManager::AddGameGenieCode(string code)
@ -138,7 +139,7 @@ void CheatManager::ClearCodes()
_absoluteCheatCodes.clear();
if(cheatRemoved) {
MessageManager::SendNotification(ConsoleNotificationType::CheatRemoved);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatRemoved);
}
}

View file

@ -43,6 +43,7 @@
#include "VideoDecoder.h"
#include "VideoRenderer.h"
#include "DebugHud.h"
#include "NotificationManager.h"
Console::Console()
{
@ -57,6 +58,7 @@ Console::~Console()
void Console::Init()
{
_notificationManager.reset(new NotificationManager());
_saveStateManager.reset(new SaveStateManager(shared_from_this()));
_videoRenderer.reset(new VideoRenderer(shared_from_this()));
_videoDecoder.reset(new VideoDecoder(shared_from_this()));
@ -235,7 +237,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
}
//Send notification only if a game was already running and we successfully loaded the new one
MessageManager::SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
_notificationManager->SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
}
if(isDifferentGame) {
@ -321,7 +323,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
ResetComponents(false);
_rewindManager.reset(new RewindManager(shared_from_this()));
MessageManager::RegisterNotificationListener(_rewindManager);
_notificationManager->RegisterNotificationListener(_rewindManager);
_videoDecoder->StartThread();
@ -377,6 +379,11 @@ shared_ptr<SoundMixer> Console::GetSoundMixer()
return _soundMixer;
}
shared_ptr<NotificationManager> Console::GetNotificationManager()
{
return _notificationManager;
}
BaseMapper* Console::GetMapper()
{
return _mapper.get();
@ -473,7 +480,8 @@ void Console::ResetComponents(bool softReset)
KeyManager::UpdateDevices();
MessageManager::SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
//This notification MUST be sent before the UpdateInputState() below to allow MovieRecorder to grab the first frame's worth of inputs
_notificationManager->SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
if(softReset) {
shared_ptr<Debugger> debugger = _debugger;
@ -603,7 +611,7 @@ void Console::Run()
bool paused = EmulationSettings::IsPaused();
if(paused && !_stop) {
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
_notificationManager->SendNotification(ConsoleNotificationType::GamePaused);
//Prevent audio from looping endlessly while game is paused
_soundMixer->StopAudio();
@ -625,7 +633,7 @@ void Console::Run()
PlatformUtilities::DisableScreensaver();
_runLock.Acquire();
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
_notificationManager->SendNotification(ConsoleNotificationType::GameResumed);
lastFrameTimer.Reset();
}
@ -668,7 +676,7 @@ void Console::Run()
_running = false;
MessageManager::SendNotification(ConsoleNotificationType::BeforeEmulationStop);
_notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop);
if(!crashed) {
_saveStateManager->SaveRecentGame(GetMapperInfo().RomName, _romFilepath, _patchFilename);
@ -703,8 +711,8 @@ void Console::Run()
_emulationThreadId = std::thread::id();
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
MessageManager::SendNotification(ConsoleNotificationType::EmulationStopped);
_notificationManager->SendNotification(ConsoleNotificationType::GameStopped);
_notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped);
}
bool Console::IsRunning()
@ -747,7 +755,7 @@ void Console::UpdateNesModel(bool sendNotification)
_apu->SetNesModel(model);
if(configChanged && sendNotification) {
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
_notificationManager->SendNotification(ConsoleNotificationType::ConfigChanged);
}
}
@ -813,7 +821,7 @@ void Console::LoadState(istream &loadStream, uint32_t stateVersion)
debugger->ResetCounters();
}
MessageManager::SendNotification(ConsoleNotificationType::StateLoaded);
_notificationManager->SendNotification(ConsoleNotificationType::StateLoaded);
}
}

View file

@ -25,6 +25,7 @@ class VideoDecoder;
class VideoRenderer;
class DebugHud;
class SoundMixer;
class NotificationManager;
struct HdPackData;
enum class NesModel;
@ -59,6 +60,7 @@ private:
shared_ptr<CheatManager> _cheatManager;
shared_ptr<DebugHud> _debugHud;
shared_ptr<SoundMixer> _soundMixer;
shared_ptr<NotificationManager> _notificationManager;
shared_ptr<HdPackBuilder> _hdPackBuilder;
shared_ptr<HdPackData> _hdData;
@ -96,6 +98,7 @@ public:
shared_ptr<VideoRenderer> GetVideoRenderer();
shared_ptr<DebugHud> GetDebugHud();
shared_ptr<SoundMixer> GetSoundMixer();
shared_ptr<NotificationManager> GetNotificationManager();
void ProcessCpuClock();
CPU* GetCpu();

View file

@ -546,6 +546,7 @@
<ClInclude Include="MMC3_224.h" />
<ClInclude Include="MovieRecorder.h" />
<ClInclude Include="AsciiTurboFile.h" />
<ClInclude Include="NotificationManager.h" />
<ClInclude Include="OpenBusHandler.h" />
<ClInclude Include="RawVideoFilter.h" />
<ClInclude Include="Sachen9602.h" />
@ -959,15 +960,20 @@
<ClCompile Include="DebugHud.cpp" />
<ClCompile Include="DrawRectangleCommand.h" />
<ClCompile Include="FceuxMovie.cpp" />
<ClCompile Include="FdsLoader.cpp" />
<ClCompile Include="HdAudioDevice.cpp" />
<ClCompile Include="HdNesPack.cpp" />
<ClCompile Include="HdPackBuilder.cpp" />
<ClCompile Include="HdPackLoader.cpp" />
<ClCompile Include="HdPpu.cpp" />
<ClCompile Include="KeyManager.cpp" />
<ClCompile Include="LuaApi.cpp" />
<ClCompile Include="LuaCallHelper.cpp" />
<ClCompile Include="LuaScriptingContext.cpp" />
<ClCompile Include="MovieRecorder.cpp" />
<ClCompile Include="NotificationManager.cpp" />
<ClCompile Include="NsfLoader.cpp" />
<ClCompile Include="NsfPpu.cpp" />
<ClCompile Include="OggMixer.cpp" />
<ClCompile Include="OggReader.cpp" />
<ClCompile Include="RawVideoFilter.cpp" />

View file

@ -1453,6 +1453,9 @@
<ClInclude Include="Bmc60311C.h">
<Filter>Nes\Mappers\Unif</Filter>
</ClInclude>
<ClInclude Include="NotificationManager.h">
<Filter>Misc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -1722,5 +1725,20 @@
<ClCompile Include="BaseExpansionAudio.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="NotificationManager.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="NsfPpu.cpp">
<Filter>Nes</Filter>
</ClCompile>
<ClCompile Include="HdPpu.cpp">
<Filter>HdPacks</Filter>
</ClCompile>
<ClCompile Include="NsfLoader.cpp">
<Filter>Nes\RomLoader</Filter>
</ClCompile>
<ClCompile Include="FdsLoader.cpp">
<Filter>Nes\RomLoader</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -27,6 +27,7 @@
#include "TraceLogger.h"
#include "Breakpoint.h"
#include "CodeDataLogger.h"
#include "NotificationManager.h"
#ifndef UINT32_MAX
#define UINT32_MAX ((uint32_t)-1)
@ -445,7 +446,7 @@ void Debugger::ProcessPpuCycle()
int32_t currentCycle = (_ppu->GetCurrentCycle() << 9) + _ppu->GetCurrentScanline();
for(auto updateCycle : _ppuViewerUpdateCycle) {
if(updateCycle.second == currentCycle) {
MessageManager::SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
}
}
@ -691,7 +692,7 @@ bool Debugger::SleepUntilResume(BreakSource source)
if(_preventResume == 0) {
_console->GetSoundMixer()->StopAudio();
MessageManager::SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)source);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)source);
ProcessEvent(EventType::CodeBreak);
_stepOverAddr = -1;
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
@ -1340,7 +1341,7 @@ void Debugger::ProcessEvent(EventType type)
_memoryDumper->GatherChrPaletteInfo();
} else if(type == EventType::StartFrame) {
//Update the event viewer
MessageManager::SendNotification(ConsoleNotificationType::EventViewerDisplayFrame);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerDisplayFrame);
//Clear the current frame/event log
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {

View file

@ -1039,7 +1039,8 @@ public:
UpdateEffectiveOverclockRate();
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
//TODOCONSOLE
//MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
MessageManager::DisplayMessage("ClockRate", std::to_string((uint32_t)EmulationSettings::GetOverclockRate()) + "%");
}

160
Core/FdsLoader.cpp Normal file
View file

@ -0,0 +1,160 @@
#include "stdafx.h"
#include "FdsLoader.h"
#include <algorithm>
#include "../Utilities/FolderUtilities.h"
#include "../Utilities/CRC32.h"
#include "../Utilities/sha1.h"
#include "RomData.h"
#include "MessageManager.h"
#include "MapperFactory.h"
#include "GameDatabase.h"
#include "EmulationSettings.h"
void FdsLoader::AddGaps(vector<uint8_t>& diskSide, uint8_t * readBuffer)
{
//Start image with 28300 bits of gap
diskSide.insert(diskSide.end(), 28300 / 8, 0);
for(size_t j = 0; j < FdsDiskSideCapacity;) {
uint8_t blockType = readBuffer[j];
uint32_t blockLength = 1;
switch(blockType) {
case 1: blockLength = 56; break; //Disk header
case 2: blockLength = 2; break; //File count
case 3: blockLength = 16; break; //File header
case 4: blockLength = 1 + readBuffer[j - 3] + readBuffer[j - 2] * 0x100; break;
default: return; //End parsing when we encounter an invalid block type (This is what Nestopia apppears to do)
}
if(blockType == 0) {
diskSide.push_back(blockType);
} else {
diskSide.push_back(0x80);
diskSide.insert(diskSide.end(), &readBuffer[j], &readBuffer[j] + blockLength);
//Fake CRC value
diskSide.push_back(0x4D);
diskSide.push_back(0x62);
//Insert 976 bits of gap after a block
diskSide.insert(diskSide.end(), 976 / 8, 0);
}
j += blockLength;
}
}
vector<uint8_t> FdsLoader::LoadBios()
{
//For FDS, the PRG ROM is the FDS BIOS (8k)
vector<uint8_t> biosData;
ifstream biosFile(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "FdsBios.bin"), ios::in | ios::binary);
if(biosFile) {
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
} else {
biosFile.open(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "disksys.rom"), ios::in | ios::binary);
if(biosFile) {
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
}
}
return {};
}
vector<uint8_t> FdsLoader::RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader)
{
vector<uint8_t> output;
output.reserve(diskData.size() * FdsDiskSideCapacity + 16);
if(needHeader) {
uint8_t header[16] = { 'F', 'D', 'S', '\x1a', (uint8_t)diskData.size(), '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
output.insert(output.end(), header, header + sizeof(header));
}
for(vector<uint8_t> &diskSide : diskData) {
bool inGap = true;
size_t i = 0, len = diskSide.size();
size_t gapNeeded = FdsDiskSideCapacity;
uint32_t fileSize = 0;
while(i < len) {
if(inGap) {
if(diskSide[i] == 0x80) {
inGap = false;
}
i++;
} else {
uint32_t blockLength = 1;
switch(diskSide[i]) {
case 1: blockLength = 56; break; //Disk header
case 2: blockLength = 2; break; //File count
case 3: blockLength = 16; fileSize = diskSide[i + 13] + diskSide[i + 14] * 0x100; break; //File header
case 4: blockLength = 1 + fileSize; break;
}
output.insert(output.end(), &diskSide[i], &diskSide[i] + blockLength);
gapNeeded -= blockLength;
i += blockLength;
i += 2; //Skip CRC after block
inGap = true;
}
}
output.insert(output.end(), gapNeeded, 0);
}
return output;
}
void FdsLoader::LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>>& diskData, vector<vector<uint8_t>>& diskHeaders)
{
uint8_t numberOfSides = 0;
size_t fileOffset = 0;
bool hasHeader = memcmp(romFile.data(), "FDS\x1a", 4) == 0;
if(hasHeader) {
numberOfSides = romFile[4];
fileOffset = 16;
} else {
numberOfSides = (uint8_t)(romFile.size() / 65500);
}
for(uint32_t i = 0; i < numberOfSides; i++) {
diskData.push_back(vector<uint8_t>());
vector<uint8_t> &fdsDiskImage = diskData.back();
diskHeaders.push_back(vector<uint8_t>(romFile.data() + fileOffset + 1, romFile.data() + fileOffset + 57));
AddGaps(fdsDiskImage, &romFile[fileOffset]);
fileOffset += FdsDiskSideCapacity;
//Ensure the image is 65500 bytes
if(fdsDiskImage.size() < FdsDiskSideCapacity) {
fdsDiskImage.resize(FdsDiskSideCapacity);
}
}
}
RomData FdsLoader::LoadRom(vector<uint8_t>& romFile, string filename)
{
RomData romData;
romData.Sha1 = SHA1::GetHash(romFile);
romData.Crc32 = CRC32::GetCRC(romFile.data(), romFile.size());
romData.PrgCrc32 = CRC32::GetCRC(romFile.data(), romFile.size());
romData.Format = RomFormat::Fds;
romData.MapperID = MapperFactory::FdsMapperID;
romData.Mirroring = MirroringType::Vertical;
romData.PrgRom = LoadBios();
romData.System = GameSystem::FDS;
if(romData.PrgRom.size() != 0x2000) {
romData.Error = true;
romData.BiosMissing = true;
}
//Setup default controllers
if(!_checkOnly && EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
GameDatabase::InitializeInputDevices("", GameSystem::FDS);
}
return romData;
}

View file

@ -1,173 +1,22 @@
#pragma once
#include "stdafx.h"
#include <algorithm>
#include "../Utilities/FolderUtilities.h"
#include "../Utilities/CRC32.h"
#include "../Utilities/sha1.h"
#include "RomData.h"
#include "MessageManager.h"
#include "MapperFactory.h"
#include "GameDatabase.h"
#include "BaseLoader.h"
struct RomData;
class FdsLoader : public BaseLoader
{
private:
const size_t FdsDiskSideCapacity = 65500;
static constexpr size_t FdsDiskSideCapacity = 65500;
private:
void AddGaps(vector<uint8_t>& diskSide, uint8_t* readBuffer)
{
//Start image with 28300 bits of gap
diskSide.insert(diskSide.end(), 28300 / 8, 0);
for(size_t j = 0; j < FdsDiskSideCapacity;) {
uint8_t blockType = readBuffer[j];
uint32_t blockLength = 1;
switch(blockType) {
case 1: blockLength = 56; break; //Disk header
case 2: blockLength = 2; break; //File count
case 3: blockLength = 16; break; //File header
case 4: blockLength = 1 + readBuffer[j - 3] + readBuffer[j - 2] * 0x100; break;
default: return; //End parsing when we encounter an invalid block type (This is what Nestopia apppears to do)
}
if(blockType == 0) {
diskSide.push_back(blockType);
} else {
diskSide.push_back(0x80);
diskSide.insert(diskSide.end(), &readBuffer[j], &readBuffer[j] + blockLength);
//Fake CRC value
diskSide.push_back(0x4D);
diskSide.push_back(0x62);
//Insert 976 bits of gap after a block
diskSide.insert(diskSide.end(), 976 / 8, 0);
}
j += blockLength;
}
}
vector<uint8_t> LoadBios()
{
//For FDS, the PRG ROM is the FDS BIOS (8k)
vector<uint8_t> biosData;
ifstream biosFile(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "FdsBios.bin"), ios::in | ios::binary);
if(biosFile) {
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
} else {
biosFile.open(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "disksys.rom"), ios::in | ios::binary);
if(biosFile) {
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
} else {
if(!_checkOnly) {
MessageManager::SendNotification(ConsoleNotificationType::FdsBiosNotFound);
}
}
}
return {};
}
void AddGaps(vector<uint8_t>& diskSide, uint8_t* readBuffer);
vector<uint8_t> LoadBios();
public:
using BaseLoader::BaseLoader;
vector<uint8_t> RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader)
{
vector<uint8_t> output;
output.reserve(diskData.size() * FdsDiskSideCapacity + 16);
if(needHeader) {
uint8_t header[16] = { 'F', 'D', 'S', '\x1a', (uint8_t)diskData.size(), '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
output.insert(output.end(), header, header + sizeof(header));
}
for(vector<uint8_t> &diskSide : diskData) {
bool inGap = true;
size_t i = 0, len = diskSide.size();
size_t gapNeeded = FdsDiskSideCapacity;
uint32_t fileSize = 0;
while(i < len) {
if(inGap) {
if(diskSide[i] == 0x80) {
inGap = false;
}
i++;
} else {
uint32_t blockLength = 1;
switch(diskSide[i]) {
case 1: blockLength = 56; break; //Disk header
case 2: blockLength = 2; break; //File count
case 3: blockLength = 16; fileSize = diskSide[i + 13] + diskSide[i + 14] * 0x100; break; //File header
case 4: blockLength = 1 + fileSize; break;
}
output.insert(output.end(), &diskSide[i], &diskSide[i] + blockLength);
gapNeeded -= blockLength;
i += blockLength;
i += 2; //Skip CRC after block
inGap = true;
}
}
output.insert(output.end(), gapNeeded, 0);
}
return output;
}
void LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>> &diskData, vector<vector<uint8_t>> &diskHeaders)
{
uint8_t numberOfSides = 0;
size_t fileOffset = 0;
bool hasHeader = memcmp(romFile.data(), "FDS\x1a", 4) == 0;
if(hasHeader) {
numberOfSides = romFile[4];
fileOffset = 16;
} else {
numberOfSides = (uint8_t)(romFile.size() / 65500);
}
for(uint32_t i = 0; i < numberOfSides; i++) {
diskData.push_back(vector<uint8_t>());
vector<uint8_t> &fdsDiskImage = diskData.back();
diskHeaders.push_back(vector<uint8_t>(romFile.data() + fileOffset + 1, romFile.data() + fileOffset + 57));
AddGaps(fdsDiskImage, &romFile[fileOffset]);
fileOffset += FdsDiskSideCapacity;
//Ensure the image is 65500 bytes
if(fdsDiskImage.size() < FdsDiskSideCapacity) {
fdsDiskImage.resize(FdsDiskSideCapacity);
}
}
}
RomData LoadRom(vector<uint8_t> &romFile, string filename)
{
RomData romData;
romData.Sha1 = SHA1::GetHash(romFile);
romData.Crc32 = CRC32::GetCRC(romFile.data(), romFile.size());
romData.PrgCrc32 = CRC32::GetCRC(romFile.data(), romFile.size());
romData.Format = RomFormat::Fds;
romData.MapperID = MapperFactory::FdsMapperID;
romData.Mirroring = MirroringType::Vertical;
romData.PrgRom = LoadBios();
romData.System = GameSystem::FDS;
if(romData.PrgRom.size() != 0x2000) {
romData.Error = true;
}
//Setup default controllers
if(!_checkOnly && EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
GameDatabase::InitializeInputDevices("", GameSystem::FDS);
}
return romData;
}
vector<uint8_t> RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader);
void LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>> &diskData, vector<vector<uint8_t>> &diskHeaders);
RomData LoadRom(vector<uint8_t> &romFile, string filename);
};

View file

@ -5,6 +5,7 @@ using std::thread;
#include "MessageManager.h"
#include "GameClient.h"
#include "Console.h"
#include "NotificationManager.h"
#include "../Utilities/Socket.h"
#include "ClientConnectionData.h"
#include "GameClientConnection.h"
@ -34,7 +35,7 @@ bool GameClient::Connected()
void GameClient::Connect(shared_ptr<Console> console, ClientConnectionData &connectionData)
{
_instance.reset(new GameClient(console));
MessageManager::RegisterNotificationListener(_instance);
console->GetNotificationManager()->RegisterNotificationListener(_instance);
shared_ptr<GameClient> instance = _instance;
if(instance) {
@ -60,7 +61,7 @@ void GameClient::PrivateConnect(ClientConnectionData &connectionData)
shared_ptr<Socket> socket(new Socket());
if(socket->Connect(connectionData.Host.c_str(), connectionData.Port)) {
_connection.reset(new GameClientConnection(_console, socket, connectionData));
MessageManager::RegisterNotificationListener(_connection);
_console->GetNotificationManager()->RegisterNotificationListener(_connection);
_connected = true;
} else {
MessageManager::DisplayMessage("NetPlay", "CouldNotConnect");

View file

@ -17,6 +17,7 @@
#include "PlayerListMessage.h"
#include "ForceDisconnectMessage.h"
#include "ServerInformationMessage.h"
#include "NotificationManager.h"
GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData &connectionData) : GameConnection(console, socket)
{
@ -41,7 +42,7 @@ void GameClientConnection::Shutdown()
DisableControllers();
_console->GetControlManager()->UnregisterInputProvider(this);
MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::DisconnectedFromServer);
MessageManager::DisplayMessage("NetPlay", "ConnectionLost");
EmulationSettings::ClearFlags(EmulationFlags::ForceMaxSpeed);
}

View file

@ -8,6 +8,7 @@ using std::thread;
#include "ControlManager.h"
#include "../Utilities/Socket.h"
#include "PlayerListMessage.h"
#include "NotificationManager.h"
unique_ptr<GameServer> GameServer::Instance;
@ -40,7 +41,7 @@ void GameServer::AcceptConnections()
shared_ptr<Socket> socket = _listener->Accept();
if(!socket->ConnectionError()) {
auto connection = shared_ptr<GameServerConnection>(new GameServerConnection(_console, socket, _password));
MessageManager::RegisterNotificationListener(connection);
_console->GetNotificationManager()->RegisterNotificationListener(connection);
_openConnections.push_back(connection);
} else {
break;

168
Core/HdPpu.cpp Normal file
View file

@ -0,0 +1,168 @@
#include "stdafx.h"
#include "HdPpu.h"
#include "CPU.h"
#include "Console.h"
#include "HdNesPack.h"
#include "VideoDecoder.h"
#include "RewindManager.h"
#include "HdPackConditions.h"
#include "NotificationManager.h"
#include "BaseMapper.h"
#include "MemoryManager.h"
void HdPpu::DrawPixel()
{
uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
_lastSprite = nullptr;
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
bool isChrRam = !_console->GetMapper()->HasChrRom();
BaseMapper *mapper = _console->GetMapper();
uint32_t color = GetPixelColor();
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
uint32_t backgroundColor = 0;
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
}
HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset];
tileInfo.Grayscale = _paletteRamMask == 0x30;
tileInfo.EmphasisBits = _intensifyColorBits >> 6;
tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
tileInfo.Tile.BgColorIndex = backgroundColor;
if(backgroundColor == 0) {
tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
} else {
tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
}
tileInfo.XScroll = _state.XScroll;
tileInfo.TmpVideoRamAddr = _state.TmpVideoRamAddr;
if(_lastSprite && _flags.SpritesEnabled) {
int j = 0;
for(uint8_t i = 0; i < _spriteCount; i++) {
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
SpriteInfo& sprite = _spriteTiles[i];
if(shift >= 0 && shift < 8) {
tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
if(isChrRam) {
mapper->CopyChrRamTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
}
if(_version >= 100) {
tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
} else {
tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
}
if(sprite.OffsetY >= 8) {
tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
} else {
tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
}
tileInfo.Sprite[j].OffsetX = shift;
tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
if(sprite.HorizontalMirror) {
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
} else {
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
}
if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
} else {
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
}
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
j++;
if(j >= 4) {
break;
}
}
}
tileInfo.SpriteCount = j;
} else {
tileInfo.SpriteCount = 0;
}
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
if(isChrRam) {
mapper->CopyChrRamTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
}
if(_version >= 100) {
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
} else {
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
}
tileInfo.Tile.OffsetY = lastTile->OffsetY;
tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
} else {
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
}
} else {
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
_info->ScreenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
_info->ScreenTiles[bufferOffset].SpriteCount = 0;
}
}
HdPpu::HdPpu(shared_ptr<Console> console, HdPackData * hdData) : PPU(console)
{
_hdData = hdData;
_version = _hdData->Version;
_screenInfo[0] = new HdScreenInfo();
_screenInfo[1] = new HdScreenInfo();
_info = _screenInfo[0];
}
HdPpu::~HdPpu()
{
delete _screenInfo[0];
delete _screenInfo[1];
}
void HdPpu::SendFrame()
{
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
_info->FrameNumber = _frameCount;
_info->WatchedAddressValues.clear();
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
if((address & 0x3FFF) >= 0x3F00) {
_info->WatchedAddressValues[address] = ReadPaletteRAM(address);
} else {
_info->WatchedAddressValues[address] = _console->GetMapper()->DebugReadVRAM(address & 0x3FFF, true);
}
} else {
_info->WatchedAddressValues[address] = _console->GetMemoryManager()->DebugRead(address);
}
}
#ifdef LIBRETRO
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
#else
if(_console->GetRewindManager()->IsRewinding()) {
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
} else {
_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer, _info);
}
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
_info = (_info == _screenInfo[0]) ? _screenInfo[1] : _screenInfo[0];
#endif
}

View file

@ -1,13 +1,11 @@
#pragma once
#include "stdafx.h"
#include "PPU.h"
#include "CPU.h"
#include "HdNesPack.h"
#include "VideoDecoder.h"
#include "RewindManager.h"
#include "HdPackConditions.h"
struct HdScreenInfo;
struct HdPackData;
class ControlManager;
class Console;
class HdPpu : public PPU
{
@ -18,161 +16,11 @@ private:
HdPackData *_hdData = nullptr;
protected:
void DrawPixel()
{
uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
_lastSprite = nullptr;
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
bool isChrRam = !_console->GetMapper()->HasChrRom();
BaseMapper *mapper = _console->GetMapper();
uint32_t color = GetPixelColor();
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
uint32_t backgroundColor = 0;
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
}
HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset];
tileInfo.Grayscale = _paletteRamMask == 0x30;
tileInfo.EmphasisBits = _intensifyColorBits >> 6;
tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
tileInfo.Tile.BgColorIndex = backgroundColor;
if(backgroundColor == 0) {
tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
} else {
tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
}
tileInfo.XScroll = _state.XScroll;
tileInfo.TmpVideoRamAddr = _state.TmpVideoRamAddr;
if(_lastSprite && _flags.SpritesEnabled) {
int j = 0;
for(uint8_t i = 0; i < _spriteCount; i++) {
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
SpriteInfo& sprite = _spriteTiles[i];
if(shift >= 0 && shift < 8) {
tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
if(isChrRam) {
mapper->CopyChrRamTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
}
if(_version >= 100) {
tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
} else {
tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
}
if(sprite.OffsetY >= 8) {
tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
} else {
tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
}
tileInfo.Sprite[j].OffsetX = shift;
tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
if(sprite.HorizontalMirror) {
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
} else {
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
}
if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
} else {
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
}
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
j++;
if(j >= 4) {
break;
}
}
}
tileInfo.SpriteCount = j;
} else {
tileInfo.SpriteCount = 0;
}
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
if(isChrRam) {
mapper->CopyChrRamTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
}
if(_version >= 100) {
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
} else {
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
}
tileInfo.Tile.OffsetY = lastTile->OffsetY;
tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
} else {
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
}
} else {
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
_info->ScreenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
_info->ScreenTiles[bufferOffset].SpriteCount = 0;
}
}
void DrawPixel() override;
public:
HdPpu(shared_ptr<Console> console, HdPackData* hdData) : PPU(console)
{
_hdData = hdData;
_version = _hdData->Version;
_screenInfo[0] = new HdScreenInfo();
_screenInfo[1] = new HdScreenInfo();
_info = _screenInfo[0];
}
HdPpu(shared_ptr<Console> console, HdPackData* hdData);
~HdPpu();
~HdPpu()
{
delete _screenInfo[0];
delete _screenInfo[1];
}
void SendFrame()
{
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
_info->FrameNumber = _frameCount;
_info->WatchedAddressValues.clear();
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
if((address & 0x3FFF) >= 0x3F00) {
_info->WatchedAddressValues[address] = ReadPaletteRAM(address);
} else {
_info->WatchedAddressValues[address] = _console->GetMapper()->DebugReadVRAM(address & 0x3FFF, true);
}
} else {
_info->WatchedAddressValues[address] = _console->GetMemoryManager()->DebugRead(address);
}
}
#ifdef LIBRETRO
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
#else
if(_console->GetRewindManager()->IsRewinding()) {
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
} else {
_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer, _info);
}
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
_info = (_info == _screenInfo[0]) ? _screenInfo[1] : _screenInfo[0];
#endif
}
void SendFrame() override;
};

View file

@ -1,8 +1,10 @@
#include "stdafx.h"
#include "MessageManager.h"
#include "NotificationManager.h"
#include "MapperFactory.h"
#include "RomLoader.h"
#include "UnifBoards.h"
#include "BaseMapper.h"
#include "RomData.h"
#include "A65AS.h"
#include "Ac08.h"
@ -624,9 +626,11 @@ shared_ptr<BaseMapper> MapperFactory::InitializeFromFile(shared_ptr<Console> con
if(mapper) {
mapper->SetConsole(console);
mapper->Initialize(romData);
MessageManager::RegisterNotificationListener(mapper);
console->GetNotificationManager()->RegisterNotificationListener(mapper);
return mapper;
}
} else if(loader.GetRomData().BiosMissing) {
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::FdsBiosNotFound);
}
return nullptr;
}

View file

@ -1,8 +1,10 @@
#pragma once
#include "stdafx.h"
#include "BaseMapper.h"
#include "RomData.h"
class MemoryManager;
class Console;
class BaseMapper;
struct RomData;
class MapperFactory
{

View file

@ -12,6 +12,7 @@
#include "MovieRecorder.h"
#include "BatteryManager.h"
#include "VirtualFile.h"
#include "NotificationManager.h"
MesenMovie::MesenMovie(shared_ptr<Console> console)
{
@ -63,6 +64,13 @@ vector<uint8_t> MesenMovie::LoadBattery(string extension)
return batteryData;
}
void MesenMovie::ProcessNotification(ConsoleNotificationType type, void * parameter)
{
if(type == ConsoleNotificationType::GameLoaded) {
_console->GetControlManager()->RegisterInputProvider(this);
}
}
bool MesenMovie::Play(VirtualFile &file)
{
_movieFile = file;
@ -98,7 +106,7 @@ bool MesenMovie::Play(VirtualFile &file)
_console->Pause();
BatteryManager::SetBatteryProvider(shared_from_this());
_console->GetControlManager()->RegisterInputProvider(this);
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
ApplySettings();
//Disable auto-configure input option (otherwise the movie file's input types are ignored)

View file

@ -4,12 +4,13 @@
#include "MovieManager.h"
#include "VirtualFile.h"
#include "BatteryManager.h"
#include "INotificationListener.h"
class ZipReader;
class Console;
struct CodeInfo;
class MesenMovie : public IMovie, public IBatteryProvider, public std::enable_shared_from_this<MesenMovie>
class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, public std::enable_shared_from_this<MesenMovie>
{
private:
shared_ptr<Console> _console;
@ -45,4 +46,7 @@ public:
// Inherited via IBatteryProvider
virtual vector<uint8_t> LoadBattery(string extension) override;
// Inherited via INotificationListener
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
};

View file

@ -607,11 +607,7 @@ std::unordered_map<string, string> MessageManager::_caResources = {
std::list<string> MessageManager::_log;
SimpleLock MessageManager::_logLock;
SimpleLock MessageManager::_notificationLock;
SimpleLock MessageManager::_addListenerLock;
IMessageManager* MessageManager::_messageManager = nullptr;
vector<weak_ptr<INotificationListener>> MessageManager::_listenersToAdd;
vector<weak_ptr<INotificationListener>> MessageManager::_notificationListeners;
void MessageManager::RegisterMessageManager(IMessageManager* messageManager)
{
@ -697,50 +693,3 @@ string MessageManager::GetLog()
}
return ss.str();
}
void MessageManager::RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener)
{
auto lock = _notificationLock.AcquireSafe();
for(weak_ptr<INotificationListener> listener : _notificationListeners) {
if(listener.lock() == notificationListener) {
//This listener is already registered, do nothing
return;
}
}
_notificationListeners.push_back(notificationListener);
}
void MessageManager::CleanupNotificationListeners()
{
auto lock = _notificationLock.AcquireSafe();
//Remove expired listeners
_notificationListeners.erase(
std::remove_if(
_notificationListeners.begin(),
_notificationListeners.end(),
[](weak_ptr<INotificationListener> ptr) { return ptr.expired(); }
),
_notificationListeners.end()
);
}
void MessageManager::SendNotification(ConsoleNotificationType type, void* parameter)
{
vector<weak_ptr<INotificationListener>> listeners;
{
auto lock = _notificationLock.AcquireSafe();
CleanupNotificationListeners();
listeners = _notificationListeners;
}
//Iterate on a copy without using a lock
for(weak_ptr<INotificationListener> notificationListener : listeners) {
shared_ptr<INotificationListener> listener = notificationListener.lock();
if(listener) {
listener->ProcessNotification(type, parameter);
}
}
}

View file

@ -11,8 +11,6 @@ class MessageManager
{
private:
static IMessageManager* _messageManager;
static vector<weak_ptr<INotificationListener>> _listenersToAdd;
static vector<weak_ptr<INotificationListener>> _notificationListeners;
static std::unordered_map<string, string> _enResources;
static std::unordered_map<string, string> _frResources;
static std::unordered_map<string, string> _jaResources;
@ -23,12 +21,8 @@ private:
static std::unordered_map<string, string> _caResources;
static SimpleLock _logLock;
static SimpleLock _notificationLock;
static SimpleLock _addListenerLock;
static std::list<string> _log;
static void CleanupNotificationListeners();
public:
static string Localize(string key);
@ -37,7 +31,4 @@ public:
static void Log(string message = "");
static string GetLog();
static void RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener);
static void SendNotification(ConsoleNotificationType type, void* parameter = nullptr);
};

View file

@ -15,7 +15,10 @@ protected:
void EndMovie()
{
MessageManager::DisplayMessage("Movies", "MovieEnded");
MessageManager::SendNotification(ConsoleNotificationType::MovieEnded);
//TODOCONSOLE
//MessageManager::SendNotification(ConsoleNotificationType::MovieEnded);
if(EmulationSettings::CheckFlag(EmulationFlags::PauseOnMovieEnd)) {
EmulationSettings::SetFlags(EmulationFlags::Paused);
}

View file

@ -9,6 +9,7 @@
#include "CheatManager.h"
#include "VirtualFile.h"
#include "SaveStateManager.h"
#include "NotificationManager.h"
MovieRecorder::MovieRecorder(shared_ptr<Console> console)
{
@ -43,8 +44,10 @@ bool MovieRecorder::Record(RecordMovieOptions options)
if(options.RecordFrom == RecordMovieFrom::StartWithSaveData) {
BatteryManager::SetBatteryRecorder(shared_from_this());
}
_console->GetControlManager()->RegisterInputRecorder(this);
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
if(options.RecordFrom == RecordMovieFrom::CurrentState) {
_console->GetControlManager()->RegisterInputRecorder(this);
_console->GetSaveStateManager()->SaveState(_saveStateData);
_hasSaveState = true;
} else {
@ -217,3 +220,10 @@ vector<uint8_t> MovieRecorder::LoadBattery(string extension)
{
return vector<uint8_t>();
}
void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void *parameter)
{
if(type == ConsoleNotificationType::GameLoaded) {
_console->GetControlManager()->RegisterInputRecorder(this);
}
}

View file

@ -4,12 +4,13 @@
#include "IInputRecorder.h"
#include "BatteryManager.h"
#include "Types.h"
#include "INotificationListener.h"
class ZipWriter;
class Console;
struct CodeInfo;
class MovieRecorder : public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
{
private:
static const uint32_t MovieFormatVersion = 1;
@ -44,6 +45,9 @@ public:
// Inherited via IBatteryProvider
virtual vector<uint8_t> LoadBattery(string extension) override;
// Inherited via INotificationListener
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
};
namespace MovieKeys

View file

@ -0,0 +1,49 @@
#include "stdafx.h"
#include "NotificationManager.h"
void NotificationManager::RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener)
{
auto lock = _lock.AcquireSafe();
for(weak_ptr<INotificationListener> listener : _listeners) {
if(listener.lock() == notificationListener) {
//This listener is already registered, do nothing
return;
}
}
_listeners.push_back(notificationListener);
}
void NotificationManager::CleanupNotificationListeners()
{
auto lock = _lock.AcquireSafe();
//Remove expired listeners
_listeners.erase(
std::remove_if(
_listeners.begin(),
_listeners.end(),
[](weak_ptr<INotificationListener> ptr) { return ptr.expired(); }
),
_listeners.end()
);
}
void NotificationManager::SendNotification(ConsoleNotificationType type, void* parameter)
{
vector<weak_ptr<INotificationListener>> listeners;
{
auto lock = _lock.AcquireSafe();
CleanupNotificationListeners();
listeners = _listeners;
}
//Iterate on a copy without using a lock
for(weak_ptr<INotificationListener> notificationListener : listeners) {
shared_ptr<INotificationListener> listener = notificationListener.lock();
if(listener) {
listener->ProcessNotification(type, parameter);
}
}
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "stdafx.h"
#include "INotificationListener.h"
#include "../Utilities/SimpleLock.h"
class NotificationManager
{
private:
SimpleLock _lock;
vector<weak_ptr<INotificationListener>> _listenersToAdd;
vector<weak_ptr<INotificationListener>> _listeners;
void CleanupNotificationListeners();
public:
void RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener);
void SendNotification(ConsoleNotificationType type, void* parameter = nullptr);
};

169
Core/NsfLoader.cpp Normal file
View file

@ -0,0 +1,169 @@
#include "stdafx.h"
#include "NsfLoader.h"
#include "RomData.h"
#include "MapperFactory.h"
void NsfLoader::Read(uint8_t *& data, uint8_t & dest)
{
dest = data[0];
data++;
}
void NsfLoader::Read(uint8_t *& data, uint16_t & dest)
{
dest = data[0] | (data[1] << 8);
data += 2;
}
void NsfLoader::Read(uint8_t *& data, char * dest, size_t len)
{
memcpy(dest, data, len);
data += len;
}
void NsfLoader::InitializeFromHeader(RomData & romData)
{
NsfHeader &header = romData.NsfInfo;
romData.Format = RomFormat::Nsf;
romData.MapperID = MapperFactory::NsfMapperID;
if(header.LoadAddress < 0x6000 || header.TotalSongs == 0) {
romData.Error = true;
}
if(header.Flags == 0x01) {
romData.System = GameSystem::NesPal;
}
if(header.PlaySpeedNtsc == 0) {
header.PlaySpeedNtsc = 16639;
}
if(header.PlaySpeedPal == 0) {
header.PlaySpeedPal = 19997;
}
if(header.StartingSong > header.TotalSongs || header.StartingSong == 0) {
header.StartingSong = 1;
}
//Log window output
Log("[NSF] Region: " + string(header.Flags == 0x00 ? "NTSC" : (header.Flags == 0x01 ? "PAL" : "NTSC & PAL")));
if(header.PlaySpeedNtsc > 0) {
Log("[NSF] Play speed (NTSC): " + std::to_string(1000000.0 / (double)header.PlaySpeedNtsc) + " Hz");
}
if(header.PlaySpeedPal > 0) {
Log("[NSF] Play speed (PAL): " + std::to_string(1000000.0 / (double)header.PlaySpeedPal) + " Hz");
}
Log("[NSF] Title: " + string(header.SongName));
Log("[NSF] Artist: " + string(header.ArtistName));
Log("[NSF] Copyright: " + string(header.CopyrightHolder));
Log("[NSF] Ripper: " + string(header.RipperName));
stringstream ss;
ss << "[NSF] Load Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.LoadAddress;
Log(ss.str());
ss = stringstream();
ss << "[NSF] Init Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.InitAddress;
Log(ss.str());
ss = stringstream();
ss << "[NSF] Play Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.PlayAddress;
Log(ss.str());
vector<string> chips;
if(header.SoundChips & 0x01) {
chips.push_back("VRC6");
}
if(header.SoundChips & 0x02) {
chips.push_back("VRC7");
}
if(header.SoundChips & 0x04) {
chips.push_back("FDS");
}
if(header.SoundChips & 0x08) {
chips.push_back("MMC5");
}
if(header.SoundChips & 0x10) {
chips.push_back("Namco 163");
}
if(header.SoundChips & 0x20) {
chips.push_back("Sunsoft 5B");
}
if(chips.empty()) {
chips.push_back("<none>");
}
ss = stringstream();
for(size_t i = 0; i < chips.size(); i++) {
if(i > 0) {
ss << ", ";
}
ss << chips[i];
}
Log("[NSF] Sound Chips: " + ss.str());
Log("[NSF] ROM size: " + std::to_string(romData.PrgRom.size() / 1024) + " KB");
}
void NsfLoader::InitHeader(NsfHeader & header)
{
memset(&header, 0, sizeof(NsfHeader));
for(int i = 0; i < 256; i++) {
//Used by NSFE
header.TrackLength[i] = -1;
header.TrackFade[i] = -1;
}
}
RomData NsfLoader::LoadRom(vector<uint8_t>& romFile)
{
RomData romData;
NsfHeader &header = romData.NsfInfo;
InitHeader(header);
uint8_t* data = romFile.data();
Read(data, header.Header, 5);
Read(data, header.Version);
Read(data, header.TotalSongs);
Read(data, header.StartingSong);
Read(data, header.LoadAddress);
Read(data, header.InitAddress);
Read(data, header.PlayAddress);
Read(data, header.SongName, 32);
Read(data, header.ArtistName, 32);
Read(data, header.CopyrightHolder, 32);
Read(data, header.PlaySpeedNtsc);
Read(data, (char*)header.BankSetup, 8);
Read(data, header.PlaySpeedPal);
Read(data, header.Flags);
Read(data, header.SoundChips);
Read(data, (char*)header.Padding, 4);
//Ensure strings are null terminated
header.SongName[31] = 0;
header.ArtistName[31] = 0;
header.CopyrightHolder[31] = 0;
if(header.PlaySpeedNtsc == 16666 || header.PlaySpeedNtsc == 16667) {
header.PlaySpeedNtsc = 16639;
}
if(header.PlaySpeedPal == 20000) {
header.PlaySpeedPal = 19997;
}
//Pad start of file to make the first block start at a multiple of 4k
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
romData.PrgRom.insert(romData.PrgRom.end(), data, data + romFile.size() - 0x80);
//Pad out the last block to be a multiple of 4k
if(romData.PrgRom.size() % 4096 != 0) {
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
}
InitializeFromHeader(romData);
return romData;
}

View file

@ -1,176 +1,23 @@
#pragma once
#include "stdafx.h"
#include "RomData.h"
#include "BaseLoader.h"
struct NsfHeader;
struct RomData;
class NsfLoader : public BaseLoader
{
private:
void Read(uint8_t* &data, uint8_t& dest)
{
dest = data[0];
data++;
}
void Read(uint8_t* &data, uint8_t& dest);
void Read(uint8_t* &data, uint16_t& dest);
void Read(uint8_t* &data, char* dest, size_t len);
void Read(uint8_t* &data, uint16_t& dest)
{
dest = data[0] | (data[1] << 8);
data += 2;
}
void Read(uint8_t* &data, char* dest, size_t len)
{
memcpy(dest, data, len);
data += len;
}
protected:
void InitializeFromHeader(RomData& romData)
{
NsfHeader &header = romData.NsfInfo;
romData.Format = RomFormat::Nsf;
romData.MapperID = MapperFactory::NsfMapperID;
if(header.LoadAddress < 0x6000 || header.TotalSongs == 0) {
romData.Error = true;
}
if(header.Flags == 0x01) {
romData.System = GameSystem::NesPal;
}
if(header.PlaySpeedNtsc == 0) {
header.PlaySpeedNtsc = 16639;
}
if(header.PlaySpeedPal == 0) {
header.PlaySpeedPal = 19997;
}
if(header.StartingSong > header.TotalSongs || header.StartingSong == 0) {
header.StartingSong = 1;
}
//Log window output
Log("[NSF] Region: " + string(header.Flags == 0x00 ? "NTSC" : (header.Flags == 0x01 ? "PAL" : "NTSC & PAL")));
if(header.PlaySpeedNtsc > 0) {
Log("[NSF] Play speed (NTSC): " + std::to_string(1000000.0 / (double)header.PlaySpeedNtsc) + " Hz");
}
if(header.PlaySpeedPal > 0) {
Log("[NSF] Play speed (PAL): " + std::to_string(1000000.0 / (double)header.PlaySpeedPal) + " Hz");
}
Log("[NSF] Title: " + string(header.SongName));
Log("[NSF] Artist: " + string(header.ArtistName));
Log("[NSF] Copyright: " + string(header.CopyrightHolder));
Log("[NSF] Ripper: " + string(header.RipperName));
stringstream ss;
ss << "[NSF] Load Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.LoadAddress;
Log(ss.str());
ss = stringstream();
ss << "[NSF] Init Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.InitAddress;
Log(ss.str());
ss = stringstream();
ss << "[NSF] Play Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.PlayAddress;
Log(ss.str());
vector<string> chips;
if(header.SoundChips & 0x01) {
chips.push_back("VRC6");
}
if(header.SoundChips & 0x02) {
chips.push_back("VRC7");
}
if(header.SoundChips & 0x04) {
chips.push_back("FDS");
}
if(header.SoundChips & 0x08) {
chips.push_back("MMC5");
}
if(header.SoundChips & 0x10) {
chips.push_back("Namco 163");
}
if(header.SoundChips & 0x20) {
chips.push_back("Sunsoft 5B");
}
if(chips.empty()) {
chips.push_back("<none>");
}
ss = stringstream();
for(size_t i = 0; i < chips.size(); i++) {
if(i > 0) {
ss << ", ";
}
ss << chips[i];
}
Log("[NSF] Sound Chips: " + ss.str());
Log("[NSF] ROM size: " + std::to_string(romData.PrgRom.size() / 1024) + " KB");
}
void InitHeader(NsfHeader& header)
{
memset(&header, 0, sizeof(NsfHeader));
for(int i = 0; i < 256; i++) {
//Used by NSFE
header.TrackLength[i] = -1;
header.TrackFade[i] = -1;
}
}
void InitializeFromHeader(RomData& romData);
void InitHeader(NsfHeader& header);
public:
using BaseLoader::BaseLoader;
RomData LoadRom(vector<uint8_t>& romFile)
{
RomData romData;
NsfHeader &header = romData.NsfInfo;
InitHeader(header);
uint8_t* data = romFile.data();
Read(data, header.Header, 5);
Read(data, header.Version);
Read(data, header.TotalSongs);
Read(data, header.StartingSong);
Read(data, header.LoadAddress);
Read(data, header.InitAddress);
Read(data, header.PlayAddress);
Read(data, header.SongName, 32);
Read(data, header.ArtistName, 32);
Read(data, header.CopyrightHolder, 32);
Read(data, header.PlaySpeedNtsc);
Read(data, (char*)header.BankSetup, 8);
Read(data, header.PlaySpeedPal);
Read(data, header.Flags);
Read(data, header.SoundChips);
Read(data, (char*)header.Padding, 4);
//Ensure strings are null terminated
header.SongName[31] = 0;
header.ArtistName[31] = 0;
header.CopyrightHolder[31] = 0;
if(header.PlaySpeedNtsc == 16666 || header.PlaySpeedNtsc == 16667) {
header.PlaySpeedNtsc = 16639;
}
if(header.PlaySpeedPal == 20000) {
header.PlaySpeedPal = 19997;
}
//Pad start of file to make the first block start at a multiple of 4k
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
romData.PrgRom.insert(romData.PrgRom.end(), data, data + romFile.size() - 0x80);
//Pad out the last block to be a multiple of 4k
if(romData.PrgRom.size() % 4096 != 0) {
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
}
InitializeFromHeader(romData);
return romData;
}
RomData LoadRom(vector<uint8_t>& romFile);
};

13
Core/NsfPpu.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "NsfPpu.h"
#include "Console.h"
#include "NotificationManager.h"
void NsfPpu::DrawPixel()
{
}
void NsfPpu::SendFrame()
{
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
}

View file

@ -5,14 +5,8 @@
class NsfPpu : public PPU
{
protected:
void DrawPixel()
{
}
void SendFrame()
{
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone);
}
void DrawPixel() override;
void SendFrame() override;
public:
using PPU::PPU;

View file

@ -10,6 +10,7 @@
#include "ControlManager.h"
#include "MemoryManager.h"
#include "Console.h"
#include "NotificationManager.h"
PPU::PPU(shared_ptr<Console> console)
{
@ -1051,7 +1052,7 @@ void PPU::SendFrame()
{
UpdateGrayscaleAndIntensifyBits();
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
#ifdef LIBRETRO
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer);

View file

@ -285,6 +285,7 @@ struct RomData
uint32_t PrgChrCrc32 = 0;
bool Error = false;
bool BiosMissing = false;
NESHeader NesHeader;
NsfHeader NsfInfo;

View file

@ -12,6 +12,7 @@
#include "MovieManager.h"
#include "ControlManager.h"
#include "Console.h"
#include "NotificationManager.h"
ShortcutKeyHandler::ShortcutKeyHandler(shared_ptr<Console> console)
{
@ -117,7 +118,7 @@ void ShortcutKeyHandler::CheckMappedKeys()
for(uint64_t i = (uint64_t)EmulatorShortcut::SwitchDiskSide; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) {
if(DetectKeyPress((EmulatorShortcut)i)) {
void* param = (void*)i;
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, param);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, param);
}
}
@ -169,11 +170,11 @@ void ShortcutKeyHandler::CheckMappedKeys()
}
if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) {
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats);
}
if(DetectKeyPress(EmulatorShortcut::ToggleAudio)) {
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleAudio);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleAudio);
}
if(DetectKeyPress(EmulatorShortcut::RunSingleFrame)) {

View file

@ -16,6 +16,7 @@
#include "HdNesPack.h"
#include "RotateFilter.h"
#include "DebugHud.h"
#include "NotificationManager.h"
VideoDecoder::VideoDecoder(shared_ptr<Console> console)
{
@ -121,7 +122,7 @@ void VideoDecoder::DecodeFrame(bool synchronous)
ScreenSize screenSize;
GetScreenSize(screenSize, true);
if(_previousScale != EmulationSettings::GetVideoScale() || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) {
MessageManager::SendNotification(ConsoleNotificationType::ResolutionChanged);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged);
}
_previousScale = EmulationSettings::GetVideoScale();
_previousScreenSize = screenSize;

View file

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "../Core/MessageManager.h"
#include "../Core/NotificationManager.h"
#include "../Core/Console.h"
#include "../Core/GameServer.h"
#include "../Core/GameClient.h"
@ -360,7 +361,7 @@ namespace InteropEmu {
auto lock = _externalNotificationListenerLock.AcquireSafe();
auto listener = shared_ptr<INotificationListener>(new InteropNotificationListener(callback));
_externalNotificationListeners.push_back(listener);
MessageManager::RegisterNotificationListener(listener);
_console->GetNotificationManager()->RegisterNotificationListener(listener);
return listener.get();
}
@ -413,35 +414,34 @@ namespace InteropEmu {
DllExport int32_t __stdcall RunRecordedTest(char* filename)
{
_recordedRomTest.reset(new RecordedRomTest(_console));
MessageManager::RegisterNotificationListener(_recordedRomTest);
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
return _recordedRomTest->Run(filename);
}
DllExport int32_t __stdcall RunAutomaticTest(char* filename)
{
shared_ptr<AutomaticRomTest> romTest(new AutomaticRomTest());
MessageManager::RegisterNotificationListener(romTest);
return romTest->Run(filename);
}
DllExport void __stdcall RomTestRecord(char* filename, bool reset)
{
_recordedRomTest.reset(new RecordedRomTest(_console));
MessageManager::RegisterNotificationListener(_recordedRomTest);
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
_recordedRomTest->Record(filename, reset);
}
DllExport void __stdcall RomTestRecordFromMovie(char* testFilename, char* movieFilename)
{
_recordedRomTest.reset(new RecordedRomTest(_console));
MessageManager::RegisterNotificationListener(_recordedRomTest);
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
_recordedRomTest->RecordFromMovie(testFilename, string(movieFilename));
}
DllExport void __stdcall RomTestRecordFromTest(char* newTestFilename, char* existingTestFilename)
{
_recordedRomTest.reset(new RecordedRomTest(_console));
MessageManager::RegisterNotificationListener(_recordedRomTest);
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
_recordedRomTest->RecordFromTest(newTestFilename, existingTestFilename);
}