Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #11546 from deReeperJosh/disneyinfinitybase
Feature: Emulate Infinity Base
  • Loading branch information
leoetlino committed Apr 30, 2023
2 parents eb30aba + 529d0a1 commit f36e05a
Show file tree
Hide file tree
Showing 18 changed files with 1,479 additions and 17 deletions.
2 changes: 2 additions & 0 deletions Source/Core/Core/CMakeLists.txt
Expand Up @@ -405,6 +405,8 @@ add_library(core
IOS/USB/Bluetooth/WiimoteHIDAttr.h
IOS/USB/Common.cpp
IOS/USB/Common.h
IOS/USB/Emulated/Infinity.cpp
IOS/USB/Emulated/Infinity.h
IOS/USB/Emulated/Skylander.cpp
IOS/USB/Emulated/Skylander.h
IOS/USB/Host.cpp
Expand Down
3 changes: 3 additions & 0 deletions Source/Core/Core/Config/MainSettings.cpp
Expand Up @@ -555,6 +555,9 @@ void SetUSBDeviceWhitelist(const std::set<std::pair<u16, u16>>& devices)
const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL{
{System::Main, "EmulatedUSBDevices", "EmulateSkylanderPortal"}, false};

const Info<bool> MAIN_EMULATE_INFINITY_BASE{
{System::Main, "EmulatedUSBDevices", "EmulateInfinityBase"}, false};

// The reason we need this function is because some memory card code
// expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii.
DiscIO::Region ToGameCubeRegion(DiscIO::Region region)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Config/MainSettings.h
Expand Up @@ -344,6 +344,7 @@ void SetUSBDeviceWhitelist(const std::set<std::pair<u16, u16>>& devices);
// Main.EmulatedUSBDevices

extern const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL;
extern const Info<bool> MAIN_EMULATE_INFINITY_BASE;

// GameCube path utility functions

Expand Down
924 changes: 924 additions & 0 deletions Source/Core/Core/IOS/USB/Emulated/Infinity.cpp

Large diffs are not rendered by default.

115 changes: 115 additions & 0 deletions Source/Core/Core/IOS/USB/Emulated/Infinity.h
@@ -0,0 +1,115 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <map>
#include <mutex>
#include <queue>
#include <span>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/IOFile.h"
#include "Core/IOS/USB/Common.h"

namespace IOS::HLE::USB
{
constexpr u8 INFINITY_NUM_BLOCKS = 0x14;
constexpr u8 INFINITY_BLOCK_SIZE = 0x10;

struct InfinityFigure final
{
void Save();

File::IOFile inf_file;
std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE> data{};
bool present = false;
u8 order_added = 255;
};

class InfinityUSB final : public Device
{
public:
InfinityUSB(EmulationKernel& ios, const std::string& device_name);
~InfinityUSB() override;
DeviceDescriptor GetDeviceDescriptor() const override;
std::vector<ConfigDescriptor> GetConfigurations() const override;
std::vector<InterfaceDescriptor> GetInterfaces(u8 config) const override;
std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const override;
bool Attach() override;
bool AttachAndChangeInterface(u8 interface) override;
int CancelTransfer(u8 endpoint) override;
int ChangeInterface(u8 interface) override;
int GetNumberOfAltSettings(u8 interface) override;
int SetAltSetting(u8 alt_setting) override;
int SubmitTransfer(std::unique_ptr<CtrlMessage> message) override;
int SubmitTransfer(std::unique_ptr<BulkMessage> message) override;
int SubmitTransfer(std::unique_ptr<IntrMessage> message) override;
int SubmitTransfer(std::unique_ptr<IsoMessage> message) override;

private:
void ScheduleTransfer(std::unique_ptr<TransferCommand> command, const std::array<u8, 32>& data,
u64 expected_time_us);

EmulationKernel& m_ios;
u16 m_vid = 0;
u16 m_pid = 0;
u8 m_active_interface = 0;
bool m_device_attached = false;
DeviceDescriptor m_device_descriptor;
std::vector<ConfigDescriptor> m_config_descriptor;
std::vector<InterfaceDescriptor> m_interface_descriptor;
std::vector<EndpointDescriptor> m_endpoint_descriptor;
std::queue<std::array<u8, 32>> m_queries;
std::queue<std::unique_ptr<IntrMessage>> m_response_list;
};

class InfinityBase final
{
public:
bool HasFigureBeenAddedRemoved() const;
std::array<u8, 32> PopAddedRemovedResponse();
void GetBlankResponse(u8 sequence, std::array<u8, 32>& reply_buf);
void GetPresentFigures(u8 sequence, std::array<u8, 32>& reply_buf);
void GetFigureIdentifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf);
void QueryBlock(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence);
void WriteBlock(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf,
u8 sequence);
void DescrambleAndSeed(u8* buf, u8 sequence, std::array<u8, 32>& reply_buf);
void GetNextAndScramble(u8 sequence, std::array<u8, 32>& reply_buf);
void RemoveFigure(u8 position);
// Returns Infinity Figure name based on data from in_file param
std::string LoadFigure(const std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE>& buf,
File::IOFile in_file, u8 position);
bool CreateFigure(const std::string& file_path, u32 character);
static std::span<const std::pair<const char*, const u32>> GetFigureList();
std::string FindFigure(u32 character) const;

protected:
std::mutex m_infinity_mutex;
std::array<InfinityFigure, 7> m_figures;

private:
InfinityFigure& GetFigureByOrder(u8 order_added);
std::array<u8, 16> GenerateInfinityFigureKey(const std::vector<u8>& sha1_data);
std::array<u8, 16> GenerateBlankFigureData(u32 figure_num);
u8 DeriveFigurePosition(u8 position);
void GenerateSeed(u32 seed);
u32 GetNext();
u64 Scramble(u32 num_to_scramble, u32 garbage);
u32 Descramble(u64 num_to_descramble);
u8 GenerateChecksum(const std::array<u8, 32>& data, int num_of_bytes) const;

// These 4 variables are state variables used during the seeding and use of the random number
// generator.
u32 m_random_a;
u32 m_random_b;
u32 m_random_c;
u32 m_random_d;

u8 m_figure_order = 0;
std::queue<std::array<u8, 32>> m_figure_added_removed_response;
};
} // namespace IOS::HLE::USB
34 changes: 20 additions & 14 deletions Source/Core/Core/IOS/USB/Host.cpp
Expand Up @@ -22,6 +22,7 @@
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/IOS/USB/Common.h"
#include "Core/IOS/USB/Emulated/Infinity.h"
#include "Core/IOS/USB/Emulated/Skylander.h"
#include "Core/IOS/USB/LibusbDevice.h"
#include "Core/NetPlayProto.h"
Expand Down Expand Up @@ -140,13 +141,7 @@ bool USBHost::AddNewDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks

auto usb_device =
std::make_unique<USB::LibusbDevice>(GetEmulationKernel(), device, descriptor);
if (!ShouldAddDevice(*usb_device))
return true;

const u64 id = usb_device->GetId();
new_devices.insert(id);
if (AddDevice(std::move(usb_device)) || always_add_hooks)
hooks.emplace(GetDeviceById(id), ChangeEvent::Inserted);
CheckAndAddDevice(std::move(usb_device), new_devices, hooks, always_add_hooks);
return true;
});
if (ret != LIBUSB_SUCCESS)
Expand Down Expand Up @@ -194,14 +189,25 @@ void USBHost::AddEmulatedDevices(std::set<u64>& new_devices, DeviceChangeHooks&
{
auto skylanderportal =
std::make_unique<USB::SkylanderUSB>(GetEmulationKernel(), "Skylander Portal");
if (ShouldAddDevice(*skylanderportal))
CheckAndAddDevice(std::move(skylanderportal), new_devices, hooks, always_add_hooks);
}
if (Config::Get(Config::MAIN_EMULATE_INFINITY_BASE) && !NetPlay::IsNetPlayRunning())
{
auto infinity_base = std::make_unique<USB::InfinityUSB>(GetEmulationKernel(), "Infinity Base");
CheckAndAddDevice(std::move(infinity_base), new_devices, hooks, always_add_hooks);
}
}

void USBHost::CheckAndAddDevice(std::unique_ptr<USB::Device> device, std::set<u64>& new_devices,
DeviceChangeHooks& hooks, bool always_add_hooks)
{
if (ShouldAddDevice(*device))
{
const u64 deviceid = device->GetId();
new_devices.insert(deviceid);
if (AddDevice(std::move(device)) || always_add_hooks)
{
const u64 skyid = skylanderportal->GetId();
new_devices.insert(skyid);
if (AddDevice(std::move(skylanderportal)) || always_add_hooks)
{
hooks.emplace(GetDeviceById(skyid), ChangeEvent::Inserted);
}
hooks.emplace(GetDeviceById(deviceid), ChangeEvent::Inserted);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/IOS/USB/Host.h
Expand Up @@ -83,6 +83,8 @@ class USBHost : public EmulationDevice
void DispatchHooks(const DeviceChangeHooks& hooks);
void AddEmulatedDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks,
bool always_add_hooks);
void CheckAndAddDevice(std::unique_ptr<USB::Device> device, std::set<u64>& new_devices,
DeviceChangeHooks& hooks, bool always_add_hooks);

bool m_has_initialised = false;
LibusbUtils::Context m_context;
Expand Down
7 changes: 7 additions & 0 deletions Source/Core/Core/System.cpp
Expand Up @@ -25,6 +25,7 @@
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h"
#include "IOS/USB/Emulated/Infinity.h"
#include "IOS/USB/Emulated/Skylander.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
Expand Down Expand Up @@ -63,6 +64,7 @@ struct System::Impl
GeometryShaderManager m_geometry_shader_manager;
GPFifo::GPFifoManager m_gp_fifo;
HSP::HSPManager m_hsp;
IOS::HLE::USB::InfinityBase m_infinity_base;
IOS::HLE::USB::SkylanderPortal m_skylander_portal;
Memory::MemoryManager m_memory;
MemoryInterface::MemoryInterfaceManager m_memory_interface;
Expand Down Expand Up @@ -197,6 +199,11 @@ IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const
return m_impl->m_skylander_portal;
}

IOS::HLE::USB::InfinityBase& System::GetInfinityBase() const
{
return m_impl->m_infinity_base;
}

Memory::MemoryManager& System::GetMemory() const
{
return m_impl->m_memory;
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/Core/System.h
Expand Up @@ -57,7 +57,8 @@ class HSPManager;
namespace IOS::HLE::USB
{
class SkylanderPortal;
};
class InfinityBase;
}; // namespace IOS::HLE::USB
namespace Memory
{
class MemoryManager;
Expand Down Expand Up @@ -138,6 +139,7 @@ class System
Interpreter& GetInterpreter() const;
JitInterface& GetJitInterface() const;
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
IOS::HLE::USB::InfinityBase& GetInfinityBase() const;
Memory::MemoryManager& GetMemory() const;
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;
PowerPC::MMU& GetMMU() const;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinLib.props
Expand Up @@ -377,6 +377,7 @@
<ClInclude Include="Core\IOS\USB\Bluetooth\WiimoteDevice.h" />
<ClInclude Include="Core\IOS\USB\Bluetooth\WiimoteHIDAttr.h" />
<ClInclude Include="Core\IOS\USB\Common.h" />
<ClInclude Include="Core\IOS\USB\Emulated\Infinity.h" />
<ClInclude Include="Core\IOS\USB\Emulated\Skylander.h" />
<ClInclude Include="Core\IOS\USB\Host.h" />
<ClInclude Include="Core\IOS\USB\LibusbDevice.h" />
Expand Down Expand Up @@ -1005,6 +1006,7 @@
<ClCompile Include="Core\IOS\USB\Bluetooth\WiimoteDevice.cpp" />
<ClCompile Include="Core\IOS\USB\Bluetooth\WiimoteHIDAttr.cpp" />
<ClCompile Include="Core\IOS\USB\Common.cpp" />
<ClCompile Include="Core\IOS\USB\Emulated\Infinity.cpp" />
<ClCompile Include="Core\IOS\USB\Emulated\Skylander.cpp" />
<ClCompile Include="Core\IOS\USB\Host.cpp" />
<ClCompile Include="Core\IOS\USB\LibusbDevice.cpp" />
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/CMakeLists.txt
Expand Up @@ -234,6 +234,8 @@ add_executable(dolphin-emu
Host.h
HotkeyScheduler.cpp
HotkeyScheduler.h
InfinityBase/InfinityBaseWindow.cpp
InfinityBase/InfinityBaseWindow.h
Main.cpp
MainWindow.cpp
MainWindow.h
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/DolphinQt.vcxproj
Expand Up @@ -155,6 +155,7 @@
<ClCompile Include="GCMemcardManager.cpp" />
<ClCompile Include="Host.cpp" />
<ClCompile Include="HotkeyScheduler.cpp" />
<ClCompile Include="InfinityBase/InfinityBaseWindow.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MainWindow.cpp" />
<ClCompile Include="MenuBar.cpp" />
Expand Down Expand Up @@ -348,6 +349,7 @@
<QtMoc Include="GCMemcardManager.h" />
<QtMoc Include="Host.h" />
<QtMoc Include="HotkeyScheduler.h" />
<QtMoc Include="InfinityBase/InfinityBaseWindow.h" />
<QtMoc Include="MainWindow.h" />
<QtMoc Include="MenuBar.h" />
<QtMoc Include="NetPlay\ChunkedProgressDialog.h" />
Expand Down

0 comments on commit f36e05a

Please sign in to comment.