Merge branch 'dolphin-mpn' into master

This commit is contained in:
Nayla 2023-04-05 04:10:05 -04:00 committed by GitHub
commit f3669dbbd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
903 changed files with 4243 additions and 386 deletions

View file

@ -99,7 +99,7 @@
#define SHADERCACHE_LEGACY_DIR "ShaderCache"
// The theme directory used by default
#define DEFAULT_THEME_DIR "Clean"
#define DEFAULT_THEME_DIR "Mario Party Netplay"
// Filenames
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)

View file

@ -0,0 +1,318 @@
; Custom game settings
[General]
version=13
[TWINE]
Good_Name=007 - The World Is Not Enough (E)(U)
frameBufferEmulation\N64DepthCompare=1
[40%20WINKS]
Good_Name=40 Winks (E) (M3) (Prototype)
graphics2D\enableNativeResTexrects=1
[BIOFREAKS]
Good_Name=Bio F.R.E.A.K.S. (E)(U)
frameBufferEmulation\copyToRDRAM=1
[BioHazard%20II]
frameBufferEmulation\copyFromRDRAM=1
frameBufferEmulation\copyToRDRAM=0
frameBufferEmulation\copyDepthToRDRAM=0
[52150A67]
Good_Name=Bokujou Monogatari 2 (J)
frameBufferEmulation\N64DepthCompare=1
[67000C2B]
Good_Name=Eikou no Saint Andrews (J)
frameBufferEmulation\forceDepthBufferClear=1
[CAL%20SPEED]
frameBufferEmulation\bufferSwapMode=1
[CASTLEVANIA2]
Good_Name=Castlevania - Legacy Of Darkness (E)(U)
frameBufferEmulation\copyToRDRAM=1
[DMPJ]
Good_Name=Mario Artist Paint Studio (J) (64DD)
frameBufferEmulation\copyAuxToRDRAM=1
frameBufferEmulation\copyFromRDRAM=1
frameBufferEmulation\nativeResFactor=1
generalEmulation\rdramImageDitheringMode=0
[DMTJ]
Good_Name=Mario Artist Talent Studio (J) (64DD)
frameBufferEmulation\copyAuxToRDRAM=1
[DINO%20PLANET]
frameBufferEmulation\copyToRDRAM=1
frameBufferEmulation\copyAuxToRDRAM=1
[DONKEY%20KONG%2064]
Good_Name=Donkey Kong 64 (E)(J)(U)
frameBufferEmulation\copyDepthToRDRAM=1
frameBufferEmulation\N64DepthCompare=0
[DR.MARIO%2064]
Good_Name=Dr. Mario 64 (U)
frameBufferEmulation\fbInfoDisabled=0
frameBufferEmulation\copyFromRDRAM=1
frameBufferEmulation\copyToRDRAM=0
[EXTREME_G]
Good_Name=Extreme-G (E)
frameBufferEmulation\N64DepthCompare=1
[EXTREME-G]
Good_Name=Extreme-G (J)
frameBufferEmulation\N64DepthCompare=1
[EXTREMEG]
Good_Name=Extreme-G (U)
frameBufferEmulation\N64DepthCompare=1
[EXTREME%20G%202]
Good_Name=Extreme-G XG2 (E) (U)
frameBufferEmulation\N64DepthCompare=1
[208E05CD]
Good_Name=Extreme-G XG2 (J)
frameBufferEmulation\N64DepthCompare=1
[F1%20POLE%20POSITION%2064]
Good_Name=F-1 Pole Position 64 (E)(U)
frameBufferEmulation\copyToRDRAM=1
[FLAPPYBIRD64]
Good_Name=FlappyBird64
frameBufferEmulation\fbInfoDisabled=0
frameBufferEmulation\copyFromRDRAM=1
frameBufferEmulation\copyToRDRAM=0
[GOEMON2%20DERODERO]
Good_Name=Ganbare Goemon - Dero Dero Douchuu Obake Tenkomori (J)
graphics2D\enableNativeResTexrects=1
[GOEMONS%20GREAT%20ADV]
Good_Name=Goemons Great Adventure (U)
graphics2D\enableNativeResTexrects=1
[HARVESTMOON64]
Good_Name=Harvest Moon 64 (U)
frameBufferEmulation\N64DepthCompare=1
[5CFA0A2E]
Good_Name=Heiwa Pachinko World 64 (J)
frameBufferEmulation\copyToRDRAM=1
[HEXEN]
Good_Name=Hexen (E)(F)(G)(J)(U)
frameBufferEmulation\copyToRDRAM=1
[HUMAN%20GRAND%20PRIX]
frameBufferEmulation\copyToRDRAM=1
[I%20S%20S%2064]
Good_Name=International Superstar Soccer 64 (E) (U)
frameBufferEmulation\N64DepthCompare=1
[JET%20FORCE%20GEMINI]
Good_Name=Jet Force Gemini (E)(U)
frameBufferEmulation\fbInfoDisabled=0
frameBufferEmulation\copyAuxToRDRAM=1
[J%20F%20G%20DISPLAY]
; See Jet Force Gemini for notes
Good_Name=Jet Force Gemini Kiosk Demo (U)
frameBufferEmulation\fbInfoDisabled=0
frameBufferEmulation\copyAuxToRDRAM=1
[J%20WORLD%20SOCCER3]
frameBufferEmulation\N64DepthCompare=1
[301E07CC]
Good_Name=Mahjong Master (J)
frameBufferEmulation\N64DepthCompare=1
[DMGJ]
Good_Name=Mario Artist Polygon Studio (J)
frameBufferEmulation\copyAuxToRDRAM=1
[KEN%20GRIFFEY%20SLUGFEST]
Good_Name=Ken Griffey Jr.'s Slugfest
frameBufferEmulation\fbInfoDisabled=0
[KIRBY64]
Good_Name=Kirby 64 - The Crystal Shards (E)(J)(U)
graphics2D\enableNativeResTexrects=1
[MARIOGOLF64]
Good_Name=Mario Golf (E)(J)(U)
frameBufferEmulation\copyDepthToRDRAM=0
[MARIOKART64]
Good_Name=Mario Kart 64 (E)(J)(U)
graphics2D\enableNativeResTexrects=1
graphics2D\enableTexCoordBounds=1
[MARIO%20STORY]
Good_Name=Mario Story (J)
frameBufferEmulation\copyToRDRAM=1
[MEGA%20MAN%2064]
Good_Name=Mega Man 64 (U)
graphics2D\correctTexrectCoords=2
[MEGAMAN%2064]
Good_Name=Mega Man 64 (Proto)
graphics2D\correctTexrectCoords=2
[MLB%20FEATURING%20K%20G%20JR]
Good_Name=Major League Baseball Featuring Ken Griffey Jr.
frameBufferEmulation\fbInfoDisabled=0
[MYSTICAL%20NINJA2%20SG]
Good_Name=Mystical Ninja 2 Starring Goemon (E)
graphics2D\enableNativeResTexrects=1
[NASCAR%202000]
Good_Name=NASCAR 2000 (U)
frameBufferEmulation\copyToRDRAM=1
[NASCAR%2099]
Good_Name=NASCAR 99 (U)
frameBufferEmulation\copyToRDRAM=1
[NUD-DMPJ-JPN_convert]
Good_Name=Mario Paint Studio (cart hack)
frameBufferEmulation\copyFromRDRAM=1
[NUD-DMTJ-JPN_convert]
Good_Name=Mario Artist Talent Studio (cart hack)
frameBufferEmulation\copyAuxToRDRAM=1
[OGREBATTLE64]
Good_Name=Ogre Battle 64 - Person of Lordly Caliber (U)
graphics2D\enableTexCoordBounds=1
[OLYMPIC%20HOCKEY]
frameBufferEmulation\bufferSwapMode=1
[PAPER%20MARIO]
Good_Name=Paper Mario (E)(U)
frameBufferEmulation\copyToRDRAM=1
graphics2D\enableTexCoordBounds=1
[PENNY%20RACERS]
Good_Name=Penny Racers (E)(U)
frameBufferEmulation\copyToRDRAM=0
[PERFECT%20STRIKER]
Good_Name=Jikkyou J.League Perfect Striker (J)
frameBufferEmulation\N64DepthCompare=1
[POKEMON%20SNAP]
Good_Name=Pokemon Snap (U)
generalEmulation\rdramImageDitheringMode=1
frameBufferEmulation\copyAuxToRDRAM=1
frameBufferEmulation\copyToRDRAM=1
frameBufferEmulation\fbInfoDisabled=0
[POKEMON%20STADIUM]
Good_Name=Pokemon Stadium (U)
frameBufferEmulation\copyDepthToRDRAM=0
[POKEMON%20STADIUM%202]
Good_Name=Pokemon Stadium 2 (E)(F)(G)(I)(J)(S)(U)
frameBufferEmulation\copyToRDRAM=0
frameBufferEmulation\copyDepthToRDRAM=0
[POKEMON%20STADIUM%20G%26S]
Good_Name=Pokemon Stadium Kin Gin (J)
frameBufferEmulation\copyToRDRAM=0
frameBufferEmulation\copyDepthToRDRAM=0
[PUZZLE%20LEAGUE%20N64]
Good_Name=Pokemon Puzzle League (E)(F)(G)(U)
texture\enableHalosRemoval=1
[RAT%20ATTACK]
Good_Name=Rat Attack
frameBufferEmulation\fbInfoDisabled=0
[RESIDENT%20EVIL%20II]
frameBufferEmulation\copyFromRDRAM=1
frameBufferEmulation\copyToRDRAM=0
frameBufferEmulation\copyDepthToRDRAM=0
[ROCKMAN%20DASH]
Good_Name=Rockman Dash - Hagane no Boukenshin (J)
graphics2D\correctTexrectCoords=2
[RUSH%202]
frameBufferEmulation\bufferSwapMode=1
graphics2D\correctTexrectCoords=2
[SAN%20FRANCISCO%20RUSH]
Good_Name=San Francisco Rush Extreme Racing (U)
frameBufferEmulation\bufferSwapMode=1
graphics2D\enableNativeResTexrects=2
[S.F.RUSH]
Good_Name=San Francisco Rush Extreme Racing (E)
frameBufferEmulation\bufferSwapMode=1
graphics2D\enableNativeResTexrects=2
[S.F.%20RUSH]
Good_Name=San Francisco Rush Extreme Racing (U)
frameBufferEmulation\bufferSwapMode=1
graphics2D\enableNativeResTexrects=2
[SHADOWMAN]
Good_Name=Shadow Man (B)(E)(F)(G)(U)
frameBufferEmulation\copyDepthToRDRAM=0
[SPACE%20INVADERS]
Good_Name=Space Invaders (U)
frameBufferEmulation\copyToRDRAM=0
[STAR%20TWINS]
; See Jet Force Gemini for notes
Good_Name=Star Twins (J)
frameBufferEmulation\fbInfoDisabled=0
frameBufferEmulation\copyAuxToRDRAM=1
[TEST]
Good_Name=Mario Artist Paint Studio (J) (1999-02-11 Prototype) (64DD)
frameBufferEmulation\copyAuxToRDRAM=1
frameBufferEmulation\copyFromRDRAM=1
generalEmulation\rdramImageDitheringMode=0
[TETRISPHERE]
Good_Name=Tetrisphere (U)
generalEmulation\correctTexrectCoords=2
[TIGGER%27S%20HONEY%20HUNT]
Good_Name=Tiggers Honey Hunt (E)(U)
frameBufferEmulation\N64DepthCompare=1
[TONIC%20TROUBLE]
Good_Name=Tonic Trouble (E)(U)
frameBufferEmulation\copyToRDRAM=1
[TG%20RALLY%202]
frameBufferEmulation\copyToRDRAM=1
[TOP%20GEAR%20RALLY%202]
frameBufferEmulation\copyToRDRAM=1
[TUROK_DINOSAUR_HUNTE]
Good_Name=Turok - Dinosaur Hunter (E)(G)(U)(J)
frameBufferEmulation\copyDepthToRDRAM=1
[W.G.%203DHOCKEY]
frameBufferEmulation\bufferSwapMode=1
[MARIOPARTY3]
frameBufferEmulation\N64DepthCompare=1

View file

@ -19,16 +19,8 @@ namespace Common
const std::string& GetScmRevStr()
{
static const std::string scm_rev_str = "Dolphin "
#if !SCM_IS_MASTER
"[" SCM_BRANCH_STR "] "
#endif
#ifdef __INTEL_COMPILER
BUILD_TYPE_STR SCM_DESC_STR "-ICC";
#else
BUILD_TYPE_STR SCM_DESC_STR;
#endif
#define MPN_REV_STR "02/27/2022"
static const std::string scm_rev_str = "Dolphin MPN";
return scm_rev_str;
}
@ -64,12 +56,13 @@ const std::string& GetScmUpdateTrackStr()
const std::string& GetNetplayDolphinVer()
{
#define LABEL "MPN"
#ifdef _WIN32
static const std::string netplay_dolphin_ver = SCM_DESC_STR " Win";
static const std::string netplay_dolphin_ver = LABEL " Win";
#elif __APPLE__
static const std::string netplay_dolphin_ver = SCM_DESC_STR " Mac";
static const std::string netplay_dolphin_ver = LABEL " Mac";
#else
static const std::string netplay_dolphin_ver = SCM_DESC_STR " Lin";
static const std::string netplay_dolphin_ver = LABEL " Lin";
#endif
return netplay_dolphin_ver;
}

View file

@ -79,7 +79,7 @@ var branch = GetFirstStdOutLine(gitexe + cmd_branch);
var isStable = +("master" == branch || "stable" == branch);
// Get environment information.
var distributor = wshShell.ExpandEnvironmentStrings("%DOLPHIN_DISTRIBUTOR%");
var distributor = "Mario Party Netplay";
if (distributor == "%DOLPHIN_DISTRIBUTOR%") distributor = "None";
var default_update_track = wshShell.ExpandEnvironmentStrings("%DOLPHIN_DEFAULT_UPDATE_TRACK%");
if (default_update_track == "%DOLPHIN_DEFAULT_UPDATE_TRACK%") default_update_track = "";

View file

@ -429,6 +429,10 @@ add_library(core
IOS/WFS/WFSSRV.h
LibusbUtils.cpp
LibusbUtils.h
MarioPartyNetplay/Discord.cpp
MarioPartyNetplay/Discord.h
MarioPartyNetplay/Gamestate.cpp
MarioPartyNetplay/Gamestate.h
MemTools.cpp
MemTools.h
Movie.cpp

View file

@ -44,7 +44,7 @@ const Info<bool> GFX_OVERLAY_SCISSOR_STATS{{System::GFX, "Settings", "OverlaySci
const Info<bool> GFX_DUMP_TEXTURES{{System::GFX, "Settings", "DumpTextures"}, false};
const Info<bool> GFX_DUMP_MIP_TEXTURES{{System::GFX, "Settings", "DumpMipTextures"}, true};
const Info<bool> GFX_DUMP_BASE_TEXTURES{{System::GFX, "Settings", "DumpBaseTextures"}, true};
const Info<bool> GFX_HIRES_TEXTURES{{System::GFX, "Settings", "HiresTextures"}, false};
const Info<bool> GFX_HIRES_TEXTURES{{System::GFX, "Settings", "HiresTextures"}, true};
const Info<bool> GFX_CACHE_HIRES_TEXTURES{{System::GFX, "Settings", "CacheHiresTextures"}, false};
const Info<bool> GFX_DUMP_EFB_TARGET{{System::GFX, "Settings", "DumpEFBTarget"}, false};
const Info<bool> GFX_DUMP_XFB_TARGET{{System::GFX, "Settings", "DumpXFBTarget"}, false};

View file

@ -44,7 +44,7 @@ const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 4
const Info<bool> MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, true};
const Info<bool> MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true};
const Info<std::string> MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""};
const Info<bool> MAIN_ENABLE_CHEATS{{System::Main, "Core", "EnableCheats"}, false};
const Info<bool> MAIN_ENABLE_CHEATS{{System::Main, "Core", "EnableCheats"}, true};
const Info<int> MAIN_GC_LANGUAGE{{System::Main, "Core", "SelectedLanguage"}, 0};
const Info<bool> MAIN_OVERRIDE_REGION_SETTINGS{{System::Main, "Core", "OverrideRegionSettings"},
false};

View file

@ -21,7 +21,7 @@ const Info<std::string> NETPLAY_TRAVERSAL_CHOICE{{System::Main, "NetPlay", "Trav
const Info<std::string> NETPLAY_INDEX_URL{{System::Main, "NetPlay", "IndexServer"},
"https://lobby.dolphin-emu.org"};
const Info<bool> NETPLAY_USE_INDEX{{System::Main, "NetPlay", "UseIndex"}, false};
const Info<bool> NETPLAY_USE_INDEX{{System::Main, "NetPlay", "UseIndex"}, true};
const Info<std::string> NETPLAY_INDEX_NAME{{System::Main, "NetPlay", "IndexName"}, ""};
const Info<std::string> NETPLAY_INDEX_REGION{{System::Main, "NetPlay", "IndexRegion"}, ""};
const Info<std::string> NETPLAY_INDEX_PASSWORD{{System::Main, "NetPlay", "IndexPassword"}, ""};
@ -33,7 +33,7 @@ const Info<std::string> NETPLAY_ADDRESS{{System::Main, "NetPlay", "Address"}, "1
const Info<u16> NETPLAY_CONNECT_PORT{{System::Main, "NetPlay", "ConnectPort"}, DEFAULT_LISTEN_PORT};
const Info<u16> NETPLAY_LISTEN_PORT{{System::Main, "NetPlay", "ListenPort"}, DEFAULT_LISTEN_PORT};
const Info<std::string> NETPLAY_NICKNAME{{System::Main, "NetPlay", "Nickname"}, "Player"};
const Info<std::string> NETPLAY_NICKNAME{{System::Main, "NetPlay", "Nickname"}, "MPN Player"};
const Info<bool> NETPLAY_USE_UPNP{{System::Main, "NetPlay", "UseUPNP"}, false};
const Info<bool> NETPLAY_ENABLE_QOS{{System::Main, "NetPlay", "EnableQoS"}, true};
@ -48,6 +48,7 @@ const Info<u32> NETPLAY_CLIENT_BUFFER_SIZE{{System::Main, "NetPlay", "BufferSize
const Info<bool> NETPLAY_SAVEDATA_LOAD{{System::Main, "NetPlay", "SyncSaves"}, true};
const Info<bool> NETPLAY_SAVEDATA_WRITE{{System::Main, "NetPlay", "WriteSaveData"}, true};
const Info<bool> NETPLAY_SAVEDATA_SYNC_ALL_WII{{System::Main, "NetPlay", "SyncAllWiiSaves"}, false};
const Info<bool> NETPLAY_SYNC_CODES{{System::Main, "NetPlay", "SyncCodes"}, true};
const Info<bool> NETPLAY_RECORD_INPUTS{{System::Main, "NetPlay", "RecordInputs"}, false};
const Info<bool> NETPLAY_STRICT_SETTINGS_SYNC{{System::Main, "NetPlay", "StrictSettingsSync"},

View file

@ -0,0 +1,28 @@
#ifndef MPN_8PLAYER_H
#define MPN_8PLAYER_H
#include <stdlib.h>
#include "InputCommon/GCPadStatus.h"
#define MPN_TEAM_ACTIVE (1 << 0)
#define MPN_TEAM_L_READY (1 << 1)
#define MPN_TEAM_R_READY (1 << 2)
typedef struct mpn_team_t
{
uint8_t Flags;
GCPadStatus LeftPad;
GCPadStatus RightPad;
} mpn_team_t;
bool mpn_8p_active ();
GCPadStatus mpn_8p_combined_input (uint8_t Port);
void mpn_8p_free ();
void mpn_8p_init ();
bool mpn_8p_port_ready (uint8_t Port);
void mpn_8p_push_back_input (GCPadStatus* Pad, uint8_t Port);
void mpn_8p_set_port_active (uint8_t Port, bool Active);
extern mpn_team_t* Teams;
#endif

View file

@ -0,0 +1,44 @@
#include "Discord.h"
#include "UICommon/DiscordPresence.h"
#include "Core/Config/NetplaySettings.h"
bool mpn_update_discord()
{
if (!Memory::IsInitialized())
return false;
DiscordRichPresence RichPresence = {};
RichPresence.largeImageKey = CurrentState.Image ? CurrentState.Image : "default";
RichPresence.largeImageText = CurrentState.Title ? CurrentState.Title : "In-Game";
if (CurrentState.Scenes != NULL && CurrentState.Scene != NULL)
RichPresence.state = CurrentState.Scene->Name.c_str();
if (CurrentState.Addresses != NULL)
{
char Details[128] = "";
if (CurrentState.Boards && CurrentState.Board)
{
snprintf(Details, sizeof(Details), "Players: 1/4 Turn: %d/%d",
mpn_read_value(CurrentState.Addresses->CurrentTurn, 1),
mpn_read_value(CurrentState.Addresses->TotalTurns, 1));
RichPresence.smallImageKey = CurrentState.Board->Icon.c_str();
RichPresence.smallImageText = CurrentState.Board->Name.c_str();
}
else
{
snprintf(Details, sizeof(Details), "Players: 1/4");
RichPresence.smallImageKey = "";
RichPresence.smallImageText = "";
}
RichPresence.details = Details;
}
RichPresence.startTimestamp = std::time(nullptr);
Discord_UpdatePresence(&RichPresence);
return true;
}

View file

@ -0,0 +1,4 @@
#include <discord_rpc.h>
#include "Gamestate.h"
bool mpn_update_discord();

View file

@ -0,0 +1,194 @@
#include "Gamestate.h"
mpn_state_t CurrentState;
bool mpn_init_state()
{
if (!Memory::IsInitialized())
return false;
switch (mpn_read_value(0x00000000, 4))
{
case MPN_GAMEID_MP4:
CurrentState.Addresses = &MP4_ADDRESSES;
CurrentState.Boards = MP4_BOARDS;
CurrentState.Image = "box-mp4";
CurrentState.IsMarioParty = true;
CurrentState.Scenes = MP4_GAMESTATES;
CurrentState.Title = "Mario Party 4";
break;
case MPN_GAMEID_MP5:
CurrentState.Addresses = &MP5_ADDRESSES;
CurrentState.Boards = MP5_BOARDS;
CurrentState.Image = "box-mp5";
CurrentState.IsMarioParty = true;
CurrentState.Scenes = MP5_GAMESTATES;
CurrentState.Title = "Mario Party 5";
break;
case MPN_GAMEID_MP6:
CurrentState.Addresses = &MP6_ADDRESSES;
CurrentState.Boards = MP6_BOARDS;
CurrentState.Image = "box-mp6";
CurrentState.IsMarioParty = true;
CurrentState.Scenes = MP6_GAMESTATES;
CurrentState.Title = "Mario Party 6";
break;
case MPN_GAMEID_MP7:
CurrentState.Addresses = &MP7_ADDRESSES;
CurrentState.Boards = MP7_BOARDS;
CurrentState.Image = "box-mp7";
CurrentState.IsMarioParty = true;
CurrentState.Scenes = MP7_GAMESTATES;
CurrentState.Title = "Mario Party 7";
break;
case MPN_GAMEID_MP8:
CurrentState.Addresses = &MP8_ADDRESSES;
CurrentState.Boards = NULL;
CurrentState.Image = "box-mp8";
CurrentState.IsMarioParty = true;
CurrentState.Scenes = MP8_GAMESTATES;
CurrentState.Title = "Mario Party 8";
break;
case MPN_GAMEID_MP9: /* TODO */
default:
CurrentState.Addresses = NULL;
CurrentState.Boards = NULL;
CurrentState.Image = "box-mp9";
CurrentState.IsMarioParty = false;
CurrentState.Scenes = NULL;
}
return CurrentState.Scenes != NULL;
}
bool mpn_update_board()
{
uint8_t i;
if (CurrentState.Boards == NULL)
CurrentState.Board = NULL;
else if (CurrentState.CurrentSceneId != CurrentState.PreviousSceneId)
{
for (i = 0;; i++)
{
/* Unknown scene ID */
if (CurrentState.Boards[i].SceneId == NONE)
break;
if (CurrentState.Boards[i].SceneId == CurrentState.CurrentSceneId)
{
CurrentState.Board = &CurrentState.Boards[i];
return true;
}
}
}
return false;
}
uint8_t mpn_get_needs(uint16_t StateId, bool IsSceneId)
{
uint16_t i;
if (CurrentState.Scenes == NULL)
return MPN_NEEDS_NOTHING;
else if (CurrentState.CurrentSceneId != CurrentState.PreviousSceneId)
{
for (i = 0;; i++)
{
/* Unknown scene ID */
if (CurrentState.Scenes[i].SceneId == NONE)
return MPN_NEEDS_NOTHING;
/* Scene ID found in array */
if ((IsSceneId && StateId == CurrentState.Scenes[i].SceneId) ||
(StateId == CurrentState.Scenes[i].MiniGameId))
return CurrentState.Scenes[i].Needs;
}
}
return MPN_NEEDS_NOTHING;
}
void mpn_push_osd_message(const std::string& Message)
{
#ifdef MPN_USE_OSD
OSD::AddMessage(Message, OSD::Duration::SHORT, MPN_OSD_COLOR);
#endif
}
bool mpn_update_state()
{
if (CurrentState.Scenes == NULL && !mpn_init_state())
return false;
if (!Memory::IsInitialized())
return false;
CurrentState.PreviousSceneId = CurrentState.CurrentSceneId;
CurrentState.CurrentSceneId = mpn_read_value(CurrentState.Addresses->SceneIdAddress, 2);
for (uint16_t i = 0;; i++)
{
if (CurrentState.Scenes[i].SceneId == NONE)
break;
if (CurrentState.CurrentSceneId == CurrentState.Scenes[i].SceneId)
{
CurrentState.Scene = &CurrentState.Scenes[i];
return true;
}
}
return false;
}
#define OSD_PUSH(a) mpn_push_osd_message("Adjusting #a for " + CurrentState.Scene->Name);
void mpn_per_frame()
{
uint8_t Needs = 0;
if (!mpn_update_state() || CurrentState.PreviousSceneId == CurrentState.CurrentSceneId)
return;
mpn_update_board();
mpn_update_discord();
Needs = mpn_get_needs(mpn_read_value(CurrentState.Addresses->SceneIdAddress, 2), true);
if (Needs != MPN_NEEDS_NOTHING)
{
if (Needs & MPN_NEEDS_SAFE_TEX_CACHE)
{
OSD_PUSH(GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES)
Config::SetCurrent(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, 0);
}
else
Config::SetCurrent(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, 128);
if (Needs & MPN_NEEDS_NATIVE_RES)
{
OSD_PUSH(GFX_EFB_SCALE)
Config::SetCurrent(Config::GFX_EFB_SCALE, 1);
}
else
Config::SetCurrent(Config::GFX_EFB_SCALE, Config::GetBase(Config::GFX_EFB_SCALE));
if (Needs & MPN_NEEDS_EFB_TO_TEXTURE)
{
OSD_PUSH(GFX_HACK_SKIP_EFB_COPY_TO_RAM)
Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, false);
}
else
Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, true);
UpdateActiveConfig();
}
}
uint32_t mpn_read_value(uint32_t Address, uint8_t Size)
{
uint32_t Value = 0;
for (int8_t i = 0; i < Size; i++)
Value += Memory::m_pRAM[Address + i] * pow(256, Size - i - 1);
return Value;
}

View file

@ -0,0 +1,684 @@
#ifndef MPN_GAMESTATE_H
#define MPN_GAMESTATE_H
#include <stdint.h>
#include <string>
#include "Core/Config/GraphicsSettings.h"
#include "Core/Core.h"
#include "Core/HW/CPU.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
#include "InputCommon/InputConfig.h"
#include "VideoCommon/VideoConfig.h"
#define MPN_GAMEID_MP4 0x474D5045
#define MPN_GAMEID_MP5 0x47503545
#define MPN_GAMEID_MP6 0x47503645
#define MPN_GAMEID_MP7 0x47503745
#define MPN_GAMEID_MP8 0x524D3845
#define MPN_GAMEID_MP9 0x53535145
#define MPN_NEEDS_SAFE_TEX_CACHE (1 << 0)
#define MPN_NEEDS_NATIVE_RES (1 << 1)
#define MPN_NEEDS_EFB_TO_TEXTURE (1 << 2)
#define MPN_NEEDS_SIDEWAYS_WIIMOTE (1 << 3)
#define MPN_NEEDS_NOTHING 0xFF
#define NONE -1
#undef MPN_USE_LEADERBOARDS
#define MPN_USE_OSD
#include "Discord.h"
#ifdef MPN_USE_LEADERBOARDS
#include "Core/MarioPartyNetplay/Leaderboards.h"
#endif
#ifdef MPN_USE_OSD
#include "VideoCommon/OnScreenDisplay.h"
#define MPN_OSD_COLOR 0xFF4A4A94
#endif
typedef struct mpn_scene_t
{
int16_t MiniGameId;
int16_t SceneId;
std::string Name;
uint8_t Needs;
} mpn_scene_t;
typedef struct mpn_addresses_t
{
/*
uint32_t BlueSpaces;
uint32_t RedSpaces;
uint32_t HappeningSpaces;
uint32_t ChanceSpaces;
uint32_t BowserSpaces;
uint32_t BattleSpaces;
uint32_t ItemSpaces;
uint32_t SpringSpaces;
*/
uint32_t CurrentTurn;
uint32_t TotalTurns;
uint32_t MinigameIdAddress;
uint32_t SceneIdAddress;
} mpn_addresses_t;
typedef struct mpn_player_t
{
uint8_t BlueSpaces;
uint16_t Coins;
uint16_t CoinStar;
uint16_t GameStar;
uint8_t Stars;
} mpn_player_t;
typedef struct mpn_board_t
{
int8_t BoardId;
int16_t SceneId;
std::string Name;
std::string Icon;
} mpn_board_t;
typedef struct mpn_state_t
{
bool IsMarioParty;
int16_t CurrentSceneId;
int16_t PreviousSceneId;
const char* Title;
const char* Image;
const mpn_addresses_t* Addresses;
const mpn_board_t* Board;
const mpn_board_t* Boards;
const mpn_scene_t* Scene;
const mpn_scene_t* Scenes;
} mpn_state_t;
extern mpn_state_t CurrentState;
/* Function prototypes */
uint8_t mpn_get_needs(uint16_t StateId, bool IsSceneId = false);
void mpn_per_frame();
uint32_t mpn_read_value(uint32_t Address, uint8_t Size);
bool mpn_update_state();
/* ============================================================================
Mario Party 4 metadata
============================================================================ */
const mpn_addresses_t MP4_ADDRESSES = {0x0018FCFC, 0x0018FCFD, 0x0018FD2C, 0x001D3CE2};
const mpn_board_t MP4_BOARDS[] = {{1, 0x59, {"Toad's Midway Madness"}, {"mp4-toad"}},
{2, 0x5A, {"Goomba's Greedy Gala"}, {"mp4-goomba"}},
{3, 0x5B, {"Shy Guy's Jungle Jam"}, {"mp4-shyguy"}},
{4, 0x5C, {"Boo's Haunted Bash"}, {"mp4-boo"}},
{5, 0x5D, {"Koopa's Seaside Soiree"}, {"mp4-koopa"}},
{6, 0x5E, {"Bowser's Gnarly Party"}, {"mp4-bowser"}},
{7, 0x60, {"Mega Board Mayhem"}, {"mp4-mega"}},
{8, 0x61, {"Mini Board Mad-Dash"}, {"mp4-mini"}},
{NONE, NONE, {""}, ""}};
const mpn_scene_t MP4_GAMESTATES[] = {{NONE, 0x01, {"Title Screen"}, 0},
{0x00, 0x09, {"Manta Rings"}, 0},
{0x01, 0x0A, {"Slime Time"}, 0},
{0x02, 0x0B, {"Booksquirm"}, 0},
{0x03, 0x0C, {"Trace Race"}, MPN_NEEDS_SAFE_TEX_CACHE},
{0x04, 0x0D, {"Mario Medley"}, 0},
{0x05, 0x0E, {"Avalanche!"}, 0},
{0x06, 0x0F, {"Domination"}, 0},
{0x07, 0x10, {"Paratrooper Plunge"}, 0},
{0x08, 0x11, {"Toad's Quick Draw"}, 0},
{0x09, 0x12, {"Three Throw"}, 0},
{0x0A, 0x13, {"Photo Finish"}, 0},
{0x0B, 0x14, {"Mr. Blizzard's Brigade"}, 0},
{0x0C, 0x15, {"Bob-omb Breakers"}, 0},
{0x0D, 0x16, {"Long Claw of the Law"}, 0},
{0x0E, 0x17, {"Stamp Out!"}, 0},
{0x0F, 0x18, {"Candlelight Fright"}, 0},
{0x10, 0x19, {"Makin' Waves"}, 0},
{0x11, 0x1A, {"Hide and Go BOOM!"}, 0},
{0x12, 0x1B, {"Tree Stomp"}, 0},
{0x13, 0x1C, {"Fish n' Drips"}, 0},
{0x14, 0x1D, {"Hop or Pop"}, 0},
{0x15, 0x1E, {"Money Belts"}, 0},
{0x16, 0x1F, {"GOOOOOOOAL!!"}, 0},
{0x17, 0x20, {"Blame it on the Crane"}, 0},
{0x18, 0x21, {"The Great Deflate"}, 0},
{0x19, 0x22, {"Revers-a-Bomb"}, 0},
{0x1A, 0x23, {"Right Oar Left?"}, 0},
{0x1B, 0x24, {"Cliffhangers"}, 0},
{0x1C, 0x25, {"Team Treasure Trek"}, 0},
{0x1D, 0x26, {"Pair-a-sailing"}, 0},
{0x1E, 0x27, {"Order Up"}, 0},
{0x1F, 0x28, {"Dungeon Duos"}, 0},
{0x20, 0x29, {"Beach Volley Folley"}, 0},
{0x21, 0x2A, {"Cheep Cheep Sweep"}, 0},
{0x22, 0x2B, {"Darts of Doom"}, 0},
{0x23, 0x2C, {"Fruits of Doom"}, 0},
{0x24, 0x2D, {"Balloon of Doom"}, 0},
{0x25, 0x2E, {"Chain Chomp Fever"}, 0},
{0x26, 0x2F, {"Paths of Peril"}, MPN_NEEDS_EFB_TO_TEXTURE},
{0x27, 0x30, {"Bowser's Bigger Blast"}, 0},
{0x28, 0x31, {"Butterfly Blitz"}, 0},
{0x29, 0x32, {"Barrel Baron"}, 0},
{0x2A, 0x33, {"Mario Speedwagons"}, 0},
/* 2B? */
{0x2C, 0x35, {"Bowser Bop"}, 0},
{0x2D, 0x36, {"Mystic Match 'Em"}, 0},
{0x2E, 0x37, {"Archaeologuess"}, 0},
{0x2F, 0x38, {"Goomba's Chip Flip"}, 0},
{0x30, 0x39, {"Kareening Koopas"}, 0},
{0x31, 0x3A, {"The Final Battle!"}, 0},
{NONE, 0x3B, {"Jigsaw Jitters"}, 0},
{NONE, 0x3C, {"Challenge Booksquirm"}, 0},
{NONE, 0x3D, {"Rumble Fishing"}, 0},
{NONE, 0x3E, {"Take a Breather"}, 0},
{NONE, 0x3F, {"Bowser Wrestling"}, 0},
{NONE, 0x41, {"Mushroom Medic"}, 0},
{NONE, 0x42, {"Doors of Doom"}, 0},
{NONE, 0x43, {"Bob-omb X-ing"}, 0},
{NONE, 0x44, {"Goomba Stomp"}, 0},
{NONE, 0x45, {"Panel Panic"}, 0},
{NONE, 0x46, {"Party Mode Menu"}, 0},
{NONE, 0x48, {"Mini-Game Mode Menu"}, 0},
{NONE, 0x4A, {"Main Menu"}, 0},
{NONE, 0x4B, {"Extra Room"}, 0},
{NONE, 0x52, {"Option Room"}, 0},
{NONE, 0x53, {"Present Room"}, 0},
{NONE, 0x59, {"Toad's Midway Madness"}, 0},
{NONE, 0x5A, {"Goomba's Greedy Gala"}, 0},
{NONE, 0x5B, {"Shy Guy's Jungle Jam"}, 0},
{NONE, 0x5C, {"Boo's Haunted Bash"}, 0},
{NONE, 0x5D, {"Koopa's Seaside Soiree"}, 0},
{NONE, 0x5E, {"Bowser's Gnarly Party"}, 0},
{NONE, 0x5F, {"Board Map Rules"}, 0},
{NONE, 0x60, {"Mega Board Mayhem"}, 0},
{NONE, 0x61, {"Mini Board Mad-Dash"}, 0},
{NONE, 0x62, {"Beach Volley Folley Menu"}, 0},
{NONE, NONE, {""}}};
/* ============================================================================
Mario Party 5 metadata
============================================================================ */
const mpn_addresses_t MP5_ADDRESSES = {
0x0022A494, // Current Turns
0x0022A495, // Total Turns
0x0022A4C4, // Mini ID
0x00288862 // Scene ID
};
const mpn_board_t MP5_BOARDS[] = {{1, 0x76, {"Toy Dream"}, {"mp5-toy"}},
{2, 0x78, {"Rainbow Dream"}, {"mp5-rainbow"}},
{3, 0x7A, {"Pirate Dream"}, {"mp5-pirate"}},
{4, 0x7C, {"Undersea Dream"}, {"mp5-undersea"}},
{5, 0x7E, {"Future Dream"}, {"mp5-future"}},
{6, 0x80, {"Sweet Dream"}, {"mp5-sweet"}},
{7, 0x82, {"Bowser Nightmare"}, {"mp5-bowser"}},
{NONE, NONE, {""}, ""}};
const mpn_scene_t MP5_GAMESTATES[] = {{NONE, 0x01, {"Title Screen"}, 0},
{NONE, 0x02, {"Card Party"}, 0},
{NONE, 0x06, {"Save-File Screen"}, 0},
//{NONE, 0x07, {"Mini-game Explanation"}, 0},
{0x4D, 0x0B, {"Beach Volleyball"}, 0},
{0x00, 0x0F, {"Coney Island"}, 0},
{0x01, 0x10, {"Ground Pound Down"}, 0},
{0x02, 0x11, {"Chimp Chase"}, 0},
{0x03, 0x12, {"Chomp Romp"}, 0},
{0x04, 0x13, {"Pushy Penguins"}, MPN_NEEDS_EFB_TO_TEXTURE},
{0x05, 0x14, {"Leaf Leap"}, 0},
{0x06, 0x15, {"Night Light Fright"}, 0},
{0x07, 0x16, {"Pop-Star Piranhas"}, 0},
{0x08, 0x17, {"Mazed & Confused"}, 0},
{0x09, 0x18, {"Dinger Derby"}, 0},
{0x0A, 0x19, {"Hydrostars"}, 0},
{0x0B, 0x1A, {"Later Skater"}, 0},
{0x0C, 0x1B, {"Will Flower"}, 0},
{0x0D, 0x1C, {"Triple Jump"}, 0},
{0x0E, 0x1D, {"Hotel Goomba"}, 0},
{0x0F, 0x1E, {"Coin Cache"}, 0},
{0x10, 0x1F, {"Flatiator"}, 0},
{0x11, 0x20, {"Squared Away"}, 0},
{0x12, 0x21, {"Mario Mechs"}, 0},
{0x13, 0x22, {"Revolving Fire"}, 0},
{0x14, 0x23, {"Clock Stoppers"}, 0},
{0x15, 0x24, {"Heat Stroke"}, 0},
{0x16, 0x25, {"Beam Team"}, 0},
{0x17, 0x26, {"Vicious Vending"}, 0},
{0x18, 0x27, {"Big Top Drop"}, 0},
{0x19, 0x28, {"Defuse or Lose"}, 0},
{0x1A, 0x29, {"ID UFO"}, 0},
{0x1B, 0x2A, {"Mario Can-Can"}, 0},
{0x1C, 0x2B, {"Handy Hoppers"}, 0},
{0x1D, 0x2C, {"Berry Basket"}, 0},
{0x1E, 0x2D, {"Bus Buffer"}, 0},
{0x1F, 0x2E, {"Rumble Ready"}, 0},
{0x20, 0x2F, {"Submarathon"}, 0},
{0x21, 0x30, {"Manic Mallets"}, 0},
{0x22, 0x31, {"Astro-Logical"}, 0},
{0x23, 0x32, {"Bill Blasters"}, 0},
{0x24, 0x33, {"Tug-o-Dorrie"}, 0},
{0x25, 0x34, {"Twist 'n' Out"}, 0},
{0x26, 0x35, {"Lucky Lineup"}, 0},
{0x27, 0x36, {"Random Ride"}, 0},
{0x28, 0x37, {"Shock Absorbers"}, 0},
{0x29, 0x38, {"Countdown Pound"}, 0},
{0x2A, 0x39, {"Whomp Maze"}, 0},
{0x2B, 0x3A, {"Shy Guy Showdown"}, 0},
{0x2C, 0x3B, {"Button Mashers"}, 0},
{0x2D, 0x3C, {"Get a Rope"}, 0},
{0x2E, 0x3D, {"Pump 'n' Jump"}, 0},
{0x2F, 0x3E, {"Head Waiter"}, 0},
{0x30, 0x3F, {"Blown Away"}, 0},
{0x31, 0x40, {"Merry Poppings"}, 0},
{0x32, 0x41, {"Pound Peril"}, 0},
{0x33, 0x42, {"Piece Out"}, 0},
{0x34, 0x43, {"Bound of Music"}, 0},
{0x35, 0x44, {"Wind Wavers"}, 0},
{0x36, 0x45, {"Sky Survivor"}, 0},
{0x3A, 0x46, {"Rain of Fire"}, 0},
{0x3B, 0x47, {"Cage-in Cookin'"}, 0},
{0x3C, 0x48, {"Scaldin' Cauldron"}, 0},
{0x3D, 0x49, {"Frightmare"}, 0},
{0x3E, 0x4A, {"Flower Shower"}, 0},
{0x3F, 0x4B, {"Dodge Bomb"}, 0},
{0x40, 0x4C, {"Fish Upon a Star"}, 0},
{0x41, 0x4D, {"Rumble Fumble"}, 0},
{0x42, 0x4E, {"Quilt for Speed"}, 0},
{0x43, 0x4F, {"Tube It or Lose It"}, 0},
{0x44, 0x50, {"Mathletes"}, 0},
{0x45, 0x51, {"Fight Cards"}, 0},
{0x46, 0x52, {"Banana Punch"}, 0},
{0x47, 0x53, {"Da Vine Climb"}, 0},
{0x48, 0x54, {"Mass A-peel"}, 0},
{0x49, 0x55, {"Panic Pinball"}, 0},
{0x4A, 0x56, {"Banking Coins"}, 0},
{0x4B, 0x57, {"Frozen Frenzy"}, 0},
{0x4C, 0x58, {"Curvy Curbs"}, 0},
{0x4E, 0x59, {"Fish Sticks"}, 0},
{0x4F, 0x5A, {"Ice Hockey"}, 0},
{NONE, 0x5C, {"Card Party Menu"}, 0},
{NONE, 0x5E, {"Bonus Mode Menu"}, 0},
{NONE, 0x60, {"Party Mode Menu"}, 0},
{NONE, 0x61, {"Main Menu"}, 0},
{NONE, 0x62, {"Party Mode Menu"}, 0},
{NONE, 0x64, {"Free Play"}, 0},
{NONE, 0x6F, {"Super Duel Mode Menu"}, 0},
{NONE, 0x76, {"Toy Dream"}, 0},
{NONE, 0x78, {"Rainbow Dream"}, 0},
{NONE, 0x7A, {"Pirate Dream"}, 0},
{NONE, 0x7C, {"Undersea Dream"}, 0},
{NONE, 0x7E, {"Future Dream"}, 0},
{NONE, 0x80, {"Sweet Dream"}, 0},
{NONE, 0x82, {"Bowser Nightmare"}, 0},
{NONE, NONE, {""}}};
/* ============================================================================
Mario Party 6 metadata
============================================================================ */
const mpn_addresses_t MP6_ADDRESSES = {
0x00265B74, // Current Turns
0x00265B75, // Total Turns
0x00265BA8, // Mini ID
0x002C0256 // Scene ID
};
const mpn_board_t MP6_BOARDS[] = {{1, 0x7B, {"Towering Treetop"}, {"mp6-treetop"}},
{2, 0x7C, {"E. Gadd's Garage"}, {"mp6-garage"}},
{3, 0x7D, {"Faire Square"}, {"mp6-square"}},
{4, 0x7E, {"Snowflake Lake"}, {"mp6-lake"}},
{5, 0x7F, {"Castaway Bay"}, {"mp6-bay"}},
{6, 0x80, {"Clockwork Castle"}, {"mp6-castle"}},
{7, 0x72, {"Thirsty Gultch"}, {"mp6-gultch"}},
{8, 0x73, {"Astro Avenue"}, {"mp6-avenue"}},
{9, 0x74, {"Infernal Tower"}, {"mp6-tower"}},
{NONE, NONE, {""}, ""}};
const mpn_scene_t MP6_GAMESTATES[] = {{NONE, 0x01, {"Title Screen"}, 0},
{NONE, 0x03, {"File-selection Screen"}, 0},
//{NONE, 0x04, {"Mini-game Explanation"}, 0},
{0x00, 0x06, {"Smashdance"}, 0},
{0x01, 0x07, {"Odd Card Out"}, 0},
{0x02, 0x08, {"Freeze Frame"}, 0},
{0x03, 0x09, {"What Goes Up..."}, 0},
{0x04, 0x0A, {"Granite Getaway"}, 0},
{0x05, 0x0B, {"Circuit Maximus"}, 0},
{0x06, 0x0C, {"Catch You Letter"}, 0},
{0x07, 0x0D, {"Snow Whirled"}, 0},
{0x08, 0x0E, {"Daft Rafts"}, 0},
{0x09, 0x0F, {"Tricky Tires"}, 0},
{0x0A, 0x10, {"Treasure Trawlers"}, 0},
{0x0B, 0x11, {"Memory Lane"}, 0},
{0x0C, 0x12, {"Mowtown"}, MPN_NEEDS_SAFE_TEX_CACHE},
{0x0D, 0x13, {"Cannonball Fun"}, 0},
{0x0E, 0x14, {"Note to Self"}, 0},
{0x0F, 0x15, {"Same is Lame"}, 0},
{0x10, 0x16, {"Light Up My Night"}, 0},
{0x11, 0x17, {"Lift Leapers"}, 0},
{0x12, 0x18, {"Blooper Scooper"}, 0},
{0x13, 0x19, {"Trap Ease Artist"}, 0},
{0x14, 0x1A, {"Pokey Punch-out"}, 0},
{0x15, 0x1B, {"Money Belt"}, 0},
{0x16, 0x1C, {"Cash Flow"}, 0},
{0x17, 0x1D, {"Cog Jog"}, 0},
{0x18, 0x1E, {"Sink or Swim"}, 0},
{0x19, 0x1F, {"Snow Brawl"}, 0},
{0x1A, 0x20, {"Ball Dozers"}, 0},
{0x1B, 0x21, {"Surge and Destroy"}, 0},
{0x1C, 0x22, {"Pop Star"}, 0},
{0x1D, 0x23, {"Stage Fright"}, 0},
{0x1E, 0x24, {"Conveyor Bolt"}, 0},
{0x1F, 0x25, {"Crate and Peril"}, 0},
{0x20, 0x26, {"Ray of Fright"}, 0},
{0x21, 0x27, {"Dust 'til Dawn"}, 0},
{0x22, 0x28, {"Garden Grab"}, 0},
{0x23, 0x29, {"Pixel Perfect"}, 0},
{0x24, 0x2A, {"Slot Trot"}, 0},
{0x25, 0x2B, {"Gondola Glide"}, 0},
{0x26, 0x2C, {"Light Breeze"}, 0},
{0x27, 0x2D, {"Body Builder"}, 0},
{0x28, 0x2E, {"Mole-it!"}, 0},
{0x29, 0x2F, {"Cashapult"}, 0},
{0x2A, 0x30, {"Jump the Gun"}, 0},
{0x2B, 0x31, {"Rocky Road"}, 0},
{0x2C, 0x32, {"Clean Team"}, 0},
{0x2D, 0x33, {"Hyper Sniper"}, 0},
{0x2E, 0x34, {"Insectiride"}, 0},
{0x2F, 0x35, {"Sunday Drivers"}, 0},
{0x30, 0x36, {"Stamp By Me"}, 0},
{0x31, 0x37, {"Throw Me a Bone"}, 0},
{0x32, 0x38, {"Black Hole Boogie"}, 0},
{0x33, 0x39, {"Full Tilt"}, 0},
{0x34, 0x3A, {"Sumo of Doom-o"}, 0},
{0x35, 0x3B, {"O-Zone"}, 0},
{0x36, 0x3C, {"Pitifall"}, 0},
{0x37, 0x3D, {"Mass Meteor"}, 0},
{0x38, 0x3E, {"Lunar-tics"}, 0},
{0x39, 0x3F, {"T Minus Five"}, 0},
{0x3A, 0x40, {"Asteroad Rage"}, 0},
{0x3B, 0x41, {"Boo'd Off the Stage"}, 0},
{0x3C, 0x42, {"Boonanza!"}, 0},
{0x3D, 0x43, {"Trick or Tree"}, 0},
{0x3E, 0x44, {"Something's Amist"}, 0},
{0x3F, 0x45, {"Wrasslin' Rapids"}, 0},
{0x43, 0x46, {"Burnstile"}, 0},
{0x44, 0x47, {"Word Herd"}, 0},
{0x45, 0x48, {"Fruit Talktail"}, 0},
{0x46, 0x4C, {"Pit Boss"}, 0},
{0x47, 0x4D, {"Dizzy Rotisserie"}, 0},
{0x48, 0x4E, {"Dark 'n Crispy"}, 0},
{0x49, 0x4F, {"Tally Me Banana"}, 0},
{0x4A, 0x50, {"Banana Shake"}, 0},
{0x4B, 0x51, {"Pier Factor"}, 0},
{0x4C, 0x52, {"Seer Terror"}, 0},
{0x4D, 0x53, {"Block Star"}, 0},
{0x4E, 0x54, {"Lab Brats"}, 0},
{0x4F, 0x55, {"Strawberry Shortfuse"}, 0},
{0x50, 0x56, {"Control Shtick"}, 0},
{0x51, 0x57, {"Dunk Bros."}, 0},
{NONE, 0x58, {"Star Bank"}, 0},
{NONE, 0x5A, {"Mini-game Mode"}, 0},
{NONE, 0x5B, {"Party Mode Menu"}, 0},
{NONE, 0x5C, {"Final Results"}, 0},
{NONE, 0x5D, {"Main Menu"}, 0},
{NONE, 0x5E, {"Solo Mode Menu"}, 0},
{NONE, 0x60, {"Battle Bridge"}, 0},
{NONE, 0x61, {"Treetop Bingo"}, 0},
{NONE, 0x62, {"Mount Duel"}, 0},
{NONE, 0x63, {"Mini-game Tour"}, MPN_NEEDS_EFB_TO_TEXTURE},
{NONE, 0x63, {"Decathlon Park"}, 0},
{NONE, 0x64, {"Endurance Alley"}, 0},
{NONE, 0x6F, {"Option Mode"}, 0},
{NONE, 0x71, {"Mini-game Results"}, 0},
{NONE, 0x72, {"Thirsty Gultch"}, 0},
{NONE, 0x73, {"Astro Avenue"}, 0},
{NONE, 0x74, {"Infernal Tower"}, 0},
{NONE, 0x7B, {"Towering Treetop"}, 0},
{NONE, 0x7C, {"E. Gadd's Garage"}, 0},
{NONE, 0x7D, {"Faire Square"}, 0},
{NONE, 0x7E, {"Snowflake Lake"}, 0},
{NONE, 0x7F, {"Castaway Bay"}, 0},
{NONE, 0x80, {"Clockwork Castle"}, 0},
{NONE, NONE, {""}}};
/* ============================================================================
Mario Party 7 metadata
============================================================================ */
const mpn_addresses_t MP7_ADDRESSES = {0x0029151C, 0x0029151D, 0x00291558, 0x002F2F3E};
const mpn_board_t MP7_BOARDS[] = {{1, 0x7A, {"Grand Canal"}, {"mp7-canal"}},
{2, 0x7B, {"Pagoda Peak"}, {"mp7-peak"}},
{3, 0x7C, {"Pyramid Park"}, {"mp7-park"}},
{4, 0x7D, {"Neon Heights"}, {"mp7-heights"}},
{5, 0x7E, {"Windmillville"}, {"mp7-windmillville"}},
{6, 0x7F, {"Bowser's Enchanted Inferno!"}, {"mp7-inferno"}},
{NONE, NONE, "", ""}};
const mpn_scene_t MP7_GAMESTATES[] = {{NONE, 0x03, {"Boot Logos"}, 0},
{NONE, 0x05, {"File Select"}, 0},
//{NONE, 0x06, {"Mini-Game Explanation"}, 0},
{0x00, 0x07, {"Catchy Tunes"}, 0},
{0x01, 0x08, {"Bubble Brawl"}, 0},
{0x02, 0x09, {"Track & Yield"}, 0},
{0x03, 0x0A, {"Fun Run"}, 0},
{0x04, 0x0B, {"Cointagious"}, 0},
{0x05, 0x0C, {"Snow Ride"}, 0},
{0x07, 0x0E, {"Picture This"}, 0},
{0x08, 0x0F, {"Ghost in the Hall"}, 0},
{0x09, 0x10, {"Big Dripper"}, 0},
{0x0A, 0x11, {"Target Tag"}, 0},
{0x0B, 0x12, {"Pokey Pummel"}, 0},
{0x0C, 0x13, {"Take Me Ohm"}, 0},
{0x0D, 0x14, {"Kart Wheeled"}, 0},
{0x0E, 0x15, {"Balloon Busters"}, 0},
{0x0F, 0x16, {"Clock Watchers"}, 0},
{0x10, 0x17, {"Dart Attack"}, 0},
{0x12, 0x18, {"Oil Crisis"}, 0},
{0x14, 0x1A, {"La Bomba"}, 0},
{0x15, 0x1B, {"Spray Anything"}, 0},
{0x16, 0x1C, {"Balloonatic"}, 0},
{0x17, 0x1D, {"Spinner Cell"}, 0},
{0x18, 0x1E, {"Think Tank"}, 0},
{0x19, 0x1F, {"Flashfright"}, 0},
{0x1A, 0x20, {"Coin-op Bop"}, 0},
{0x1B, 0x21, {"Easy Pickings"}, 0},
{0x1C, 0x22, {"Wheel of Woe"}, 0},
{0x1D, 0x23, {"Boxing Day"}, 0},
{0x1E, 0x24, {"Be My Chum!"}, 0},
{0x1F, 0x25, {"StratosFEAR!"}, 0},
{0x20, 0x26, {"Pogo-a-go-go"}, 0},
{0x21, 0x27, {"Buzzstormer"}, 0},
{0x22, 0x28, {"Tile and Error"}, 0},
{0x23, 0x29, {"Battery Ram"}, 0},
{0x24, 0x2A, {"Cardinal Rule"}, 0},
{0x25, 0x2B, {"Ice Moves"}, 0},
{0x26, 0x2C, {"Bumper Crop"}, 0},
{0x27, 0x2D, {"Hop-O-Matic 4000"}, 0},
{0x28, 0x2E, {"Wingin' It"}, 0},
{0x29, 0x2F, {"Sphere Factor"}, 0},
{0x2A, 0x30, {"Herbicidal Maniac"}, 0},
{0x2B, 0x31, {"Pyramid Scheme"}, 0},
{0x2C, 0x32, {"World Piece"}, 0},
{0x2D, 0x33, {"Warp Pipe Dreams"}, 0},
{0x2E, 0x34, {"Weight for It"}, 0},
{0x2F, 0x35, {"Helipopper"}, 0},
{0x30, 0x36, {"Monty's Revenge"}, 0},
{0x31, 0x37, {"Deck Hands"}, 0},
{0x32, 0x38, {"Mad Props"}, 0},
{0x33, 0x39, {"Gimme a Sign"}, 0},
{0x34, 0x3A, {"Bridge Work"}, 0},
{0x35, 0x3B, {"Spin Doctor"}, 0},
{0x36, 0x3C, {"Hip Hop Drop"}, 0},
{0x37, 0x3D, {"Air Farce"}, 0},
{0x38, 0x3E, {"The Final Countdown"}, 0},
{0x39, 0x3F, {"Royal Rumpus"}, 0},
{0x3A, 0x40, {"Light Speed"}, 0},
{0x3B, 0x41, {"Apes of Wrath"}, 0},
{0x3C, 0x42, {"Fish & Cheeps"}, 0},
{0x3D, 0x43, {"Camp Ukiki"}, 0},
{0x3E, 0x44, {"Funstacle Course!"}, 0},
{0x3F, 0x45, {"Funderwall!"}, 0},
{0x40, 0x46, {"Magmagical Journey!"}, 0},
{0x41, 0x47, {"Tunnel of Lava!"}, 0},
{0x42, 0x48, {"Treasure Dome!"}, 0},
{0x43, 0x49, {"Slot-O-Whirl!"}, 0},
{0x44, 0x4A, {"Peel Out"}, 0},
{0x45, 0x4B, {"Bananas Faster"}, 0},
{0x46, 0x4C, {"Stump Change"}, 0},
{0x47, 0x4D, {"Jump, Man"}, 0},
{0x48, 0x4E, {"Vine Country"}, 0},
{0x49, 0x4F, {"A Bridge Too Short"}, 0},
{0x4A, 0x50, {"Spider Stomp"}, 0},
{0x4B, 0x51, {"Stick and Spin"}, 0},
{0x55, 0x5B, {"Bowser's Lovely Lift!"}, 0},
{0x57, 0x5D, {"Mathemortician"}, 0},
{NONE, 0x61, {"Duty-Free Shop"}, 0},
{NONE, 0x63, {"Deluxe Cruise"}, 0},
{NONE, 0x64, {"Minigame Cruise"}, 0},
{NONE, 0x65, {"Control Room"}, 0},
{NONE, 0x67, {"Main Menu"}, 0},
{NONE, 0x68, {"Solo Cruise"}, 0},
{NONE, 0x6A, {"Decathlon Castle"}, 0},
{NONE, 0x6B, {"Free-Play Sub"}, 0},
{NONE, 0x6C, {"Waterfall Battle"}, 0},
{NONE, 0x6E, {"Volcano Peril"}, 0},
{NONE, 0x6F, {"Pearl Hunt"}, 0},
{NONE, 0x70, {"King of the River"}, 0},
{NONE, 0x66, {"Party Cruise"}, 0},
{NONE, 0x7A, {"Grand Canal"}, 0},
{NONE, 0x7B, {"Pagoda Peak"}, 0},
{NONE, 0x7C, {"Pyramid Park"}, 0},
{NONE, 0x7D, {"Neon Heights"}, 0},
{NONE, 0x7E, {"Windmillville"}, 0},
{NONE, 0x7F, {"Bowser's Enchanted Inferno!"}, 0},
{NONE, 0x73, {"Mini-Game Results"}, 0},
{NONE, NONE, {""}, 0}};
/* ============================================================================
Mario Party 8 metadata
============================================================================ */
const mpn_addresses_t MP8_ADDRESSES = {0x00228764, 0x00228765, 0x002287CC, 0x002CD222};
const mpn_board_t MP8_BOARDS[] = {{1, 0x10, {"DK's Treetop Temple"}, {"mp8-dktt"}},
{2, 0x11, {"Goomba's Booty Boardwalk"}, {"mp8-gbb"}},
{3, 0x12, {"King Boo's Haunted Hideaway"}, {"mp8-kbhh"}},
{4, 0x13, {"Shy Guy's Perplex Express"}, {"mp8-sgpe"}},
{5, 0x14, {"Koopa's Tycoon Town"}, {"mp8-ktt"}},
{6, 0x15, {"Bowser's Warped Orbit"}, {"mp8-bwo"}},
{NONE, NONE, {""}, ""}};
const mpn_scene_t MP8_GAMESTATES[] = {
{NONE, 0x04, {"Main Menu"}, 0},
{NONE, 0x08, {"Fun Bazaar"}, 0},
{NONE, 0x0A, {"Free Play Arcade"}, 0},
{NONE, 0x0B, {"Crown Showdown"}, 0},
{NONE, 0x0C, {"Flip-Out Frenzy"}, 0},
{NONE, 0x0D, {"Tic-Tac Drop"}, 0},
{NONE, 0x0E, {"Test for the Best"}, 0},
{NONE, 0x10, {"DK's Treetop Temple"}, 0},
{NONE, 0x11, {"Goomba's Booty Boardwalk"}, 0},
{NONE, 0x12, {"King Boo's Haunted Hideaway"}, 0},
{NONE, 0x13, {"Shy Guy's Perplex Express"}, 0},
{NONE, 0x14, {"Koopa's Tycoon Town"}, 0},
{NONE, 0x15, {"Bowser's Warped Orbit"}, 0},
//{NONE, 0x16, {"Mini-Game Explanation"}, 0},
{0x00, 0x17, {"Speedy Graffiti"}, MPN_NEEDS_EFB_TO_TEXTURE},
{0x01, 0x18, {"Swing Kings"}, 0},
{0x02, 0x19, {"Water Ski Spree"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x03, 0x1A, {"Punch-a-Bunch"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x04, 0x1B, {"Crank to Rank"}, 0},
{0x05, 0x1C, {"At the Chomp Wash"}, 0},
{0x06, 0x1D, {"Mosh-Pit Playroom"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x07, 0x1E, {"Mario Matrix"}, 0},
{0x08, 0x1F, {"??? - Hammer de Pokari"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x09, 0x20, {"Grabby Giridion"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x0A, 0x21, {"Lava or Leave 'Em"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x0B, 0x22, {"Kartastrophe"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x0C, 0x23, {"??? - Ribbon Game"}, 0},
{0x0D, 0x24, {"Aim of the Game"}, 0},
{0x0E, 0x25, {"Rudder Madness"}, 0},
{0x0F, 0x26, {"Gun the Runner"}, MPN_NEEDS_SIDEWAYS_WIIMOTE}, // 1P is sideways
{0x10, 0x27, {"Grabbin' Gold"}, 0},
{0x11, 0x28, {"Power Trip"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x12, 0x29, {"Bob-ombs Away"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x13, 0x2A, {"Swervin' Skies"}, 0},
{0x14, 0x2B, {"Picture Perfect"}, 0},
{0x15, 0x2C, {"Snow Way Out"}, MPN_NEEDS_SIDEWAYS_WIIMOTE}, // 3P are sideways
{0x16, 0x2D, {"Thrash 'n' Crash"}, 0},
{0x17, 0x2E, {"Chump Rope"}, 0},
{0x18, 0x2F, {"Sick and Twisted"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x19, 0x30, {"Bumper Balloons"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x1A, 0x31, {"Rowed to Victory"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x1B, 0x32, {"Winner or Dinner"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x1C, 0x33, {"Paint Misbehavin'"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x1D, 0x34, {"Sugar Rush"}, 0},
{0x1E, 0x35, {"King of the Thrill"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x1F, 0x36, {"Shake It Up"}, 0},
{0x20, 0x37, {"Lean, Mean Ravine"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x21, 0x38, {"Boo-ting Gallery"}, 0},
{0x22, 0x39, {"Crops 'n' Robbers"}, 0},
{0x23, 0x3A, {"In the Nick of Time"}, 0},
{0x24, 0x3B, {"Cut from the Team"}, 0},
{0x25, 0x3C, {"Snipe for the Picking"}, 0},
{0x26, 0x3D, {"Saucer Swarm"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x27, 0x3E, {"Glacial Meltdown"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x28, 0x3F, {"Attention Grabber"}, 0},
{0x29, 0x40, {"Blazing Lassos"}, 0},
{0x2A, 0x41, {"Wing and a Scare"}, 0},
{0x2B, 0x42, {"Lob to Rob"}, 0},
{0x2C, 0x43, {"Pumper Cars"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x2D, 0x44, {"Cosmic Slalom"}, 0},
{0x2E, 0x45, {"Lava Lobbers"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x2F, 0x46, {"Loco Motives"}, 0},
{0x30, 0x47, {"Specter Inspector"}, 0},
{0x31, 0x48, {"Frozen Assets"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x32, 0x49, {"Breakneck Building"}, MPN_NEEDS_NATIVE_RES},
{0x33, 0x4A, {"Surf's Way Up"}, 0},
{0x34, 0x4B, {"??? - Bull Riding"}, 0},
{0x35, 0x4C, {"Balancing Act"}, 0},
{0x36, 0x4D, {"Ion the Prize"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x37, 0x4E, {"You're the Bob-omb"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x38, 0x4F, {"Scooter Pursuit"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x39, 0x50, {"Cardiators"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x3A, 0x51, {"Rotation Station"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x3B, 0x52, {"Eyebrawl"}, 0},
{0x3C, 0x53, {"Table Menace"}, 0},
{0x3D, 0x54, {"Flagging Rights"}, 0},
{0x3E, 0x55, {"Trial by Tile"}, 0},
{0x3F, 0x56, {"Star Carnival Bowling"}, 0},
{0x40, 0x57, {"Puzzle Pillars"}, 0},
{0x41, 0x58, {"Canyon Cruisers"}, 0},
{0x42, 0x59, {"??? - CRASH"}, 0},
{0x43, 0x5A, {"Settle It in Court"}, 0},
{0x44, 0x5B, {"Moped Mayhem"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{0x45, 0x5C, {"Flip the Chimp"}, 0},
{0x46, 0x5D, {"Pour to Score"}, 0},
{0x47, 0x5E, {"Fruit Picker"}, 0},
{0x48, 0x5F, {"Stampede"}, 0},
{0x49, 0x60, {"Superstar Showdown"}, 0},
{0x4A, 0x61, {"Alpine Assault"}, 0},
{0x4B, 0x62, {"Treacherous Tightrope"}, MPN_NEEDS_SIDEWAYS_WIIMOTE},
{NONE, NONE, {""}, 0}};
#endif

View file

@ -130,9 +130,12 @@ public:
void SendChatMessage(const std::string& msg);
void RequestStopGame();
void SendPowerButtonEvent();
void SendActiveGeckoCodes();
void GetActiveGeckoCodes();
void RequestGolfControl(PlayerId pid);
void RequestGolfControl();
std::string GetCurrentGolfer();
std::vector<std::string> v_ActiveGeckoCodes;
// Send and receive pads values
struct WiimoteDataBatchEntry

View file

@ -425,8 +425,8 @@ ConnectionError NetPlayServer::OnConnect(ENetPeer* incoming_connection, sf::Pack
{
std::string netplay_version;
received_packet >> netplay_version;
if (netplay_version != Common::GetScmRevGitStr())
return ConnectionError::VersionMismatch;
if (m_is_running || m_start_pending)
return ConnectionError::GameRunning;

View file

@ -32,6 +32,7 @@
#include "Core/Debugger/PPCDebugInterface.h"
#include "Core/GeckoCode.h"
#include "Core/GeckoCodeConfig.h"
#include "Core/MarioPartyNetplay/Gamestate.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
@ -345,6 +346,8 @@ bool ApplyFramePatches()
ApplyPatches(guard, s_on_frame);
ApplyMemoryPatches(guard, s_on_frame_memory);
mpn_per_frame();
// Run the Gecko code handler
Gecko::RunCodeHandler(guard);
ActionReplay::RunAllActive(guard);

View file

@ -59,6 +59,14 @@
<Import Project="$(ExternalsDir)xxhash\exports.props" />
<Import Project="$(ExternalsDir)zlib-ng\exports.props" />
<Import Project="$(ExternalsDir)zstd\exports.props" />
<ItemGroup>
<ClCompile Include="Core\MarioPartyNetplay\Discord.cpp" />
<ClCompile Include="Core\MarioPartyNetplay\Gamestate.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Core\MarioPartyNetplay\Discord.h" />
<ClInclude Include="Core\MarioPartyNetplay\Gamestate.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<PropertyGroup>

View file

@ -96,4 +96,5 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& ga
layout->addWidget(close_box);
setLayout(layout);
tab_widget->setCurrentIndex(3);
}

View file

@ -17,6 +17,12 @@
<Import Project="$(VSPropsDir)QtCompile.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>Dolphin-MPN</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>Dolphin-MPN</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)Config\Graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -408,9 +414,6 @@
<ProjectReference Include="$(CoreDir)DolphinLib.vcxproj">
<Project>{D79392F7-06D6-4B4B-A39F-4D587C215D3A}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)Common\SCMRevGen.vcxproj">
<Project>{41279555-f94f-4ebc-99de-af863c10c5c4}</Project>
</ProjectReference>
<ProjectReference Include="$(DolphinRootDir)Languages\Languages.vcxproj">
<Project>{0e033be3-2e08-428e-9ae9-bc673efa12b5}</Project>
</ProjectReference>
@ -444,13 +447,15 @@
<!--Copy Exe, Data directory and DLLs which should be located in the executable directory-->
<ItemGroup>
<DataSysFiles Include="$(DolphinRootDir)Data\**\Sys\**\*.*" />
<DataUserFiles Include="$(DolphinRootDir)Data\**\User\**\*.*" />
<DataTxtFiles Include="$(DolphinRootDir)Data\license.txt" />
<BinaryFiles Include="$(TargetPath)" />
<AllInputFiles Include="@(DataSysFiles);@(DataTxtFiles);@(BinaryFiles)" />
<AllInputFiles Include="@(DataSysFiles);@(DataUserFiles);@(DataTxtFiles);@(BinaryFiles)" />
</ItemGroup>
<Target Name="AfterBuild" Inputs="@(AllInputFiles)" Outputs="@(AllInputFiles -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying Data directory..." Importance="High" />
<Copy SourceFiles="@(DataSysFiles)" DestinationFolder="$(BinaryOutputDir)%(RecursiveDir)" Condition="!Exists('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)') OR $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) &gt; $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)').Ticks)" />
<Copy SourceFiles="@(DataUserFiles)" DestinationFolder="$(BinaryOutputDir)%(RecursiveDir)" Condition="!Exists('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)') OR $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) &gt; $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)').Ticks)" />
<Copy SourceFiles="@(DataTxtFiles)" DestinationFolder="$(BinaryOutputDir)" Condition="!Exists('$(BinaryOutputDir)%(Filename)%(DataTxtFiles.Extension)') OR $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) &gt; $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataTxtFiles.Extension)').Ticks)" />
<Message Text="Copy: @(BinaryFiles) -&gt; $(BinaryOutputDir)" Importance="High" />
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />

View file

@ -518,8 +518,6 @@ void MainWindow::ConnectMenuBar()
connect(m_menu_bar, &MenuBar::ImportNANDBackup, this, &MainWindow::OnImportNANDBackup);
connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
connect(m_menu_bar, &MenuBar::BootWiiSystemMenu, this, &MainWindow::BootWiiSystemMenu);
connect(m_menu_bar, &MenuBar::StartNetPlay, this, &MainWindow::ShowNetPlaySetupDialog);
connect(m_menu_bar, &MenuBar::BrowseNetPlay, this, &MainWindow::ShowNetPlayBrowser);
connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer);
connect(m_menu_bar, &MenuBar::ShowSkylanderPortal, this, &MainWindow::ShowSkylanderPortal);
connect(m_menu_bar, &MenuBar::ConnectWiiRemote, this, &MainWindow::OnConnectWiiRemote);
@ -640,6 +638,8 @@ void MainWindow::ConnectToolBar()
connect(m_tool_bar, &ToolBar::ControllersPressed, this, &MainWindow::ShowControllersWindow);
connect(m_tool_bar, &ToolBar::GraphicsPressed, this, &MainWindow::ShowGraphicsWindow);
connect(m_tool_bar, &ToolBar::StartNetPlayPressed, this, &MainWindow::ShowNetPlaySetupDialog);
connect(m_tool_bar, &ToolBar::StepPressed, m_code_widget, &CodeWidget::Step);
connect(m_tool_bar, &ToolBar::StepOverPressed, m_code_widget, &CodeWidget::StepOver);
connect(m_tool_bar, &ToolBar::StepOutPressed, m_code_widget, &CodeWidget::StepOut);
@ -947,6 +947,110 @@ bool MainWindow::RequestStop()
return true;
}
bool MainWindow::RequestStopNetplay()
{
if (!Core::IsRunning())
{
Core::QueueHostJob([this] { OnStopComplete(); }, true);
return true;
}
const bool rendered_widget_was_active =
m_render_widget->isActiveWindow() && !m_render_widget->isFullScreen();
QWidget* confirm_parent = (!m_rendering_to_main && rendered_widget_was_active) ?
m_render_widget :
static_cast<QWidget*>(this);
const bool was_cursor_locked = m_render_widget->IsCursorLocked();
if (!m_render_widget->isFullScreen())
m_render_widget_geometry = m_render_widget->saveGeometry();
else
FullScreen();
if (Config::Get(Config::MAIN_CONFIRM_ON_STOP))
{
if (std::exchange(m_stop_confirm_showing, true))
return true;
Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; });
const Core::State state = Core::GetState();
// Only pause the game, if NetPlay is not running
bool pause = !Settings::Instance().GetNetPlayClient();
if (pause)
Core::SetState(Core::State::Paused);
if (rendered_widget_was_active)
{
// We have to do this before creating the message box, otherwise we might receive the window
// activation event before we know we need to lock the cursor again.
m_render_widget->SetCursorLockedOnNextActivation(was_cursor_locked);
}
// This is to avoid any "race conditions" between the "Window Activate" message and the
// message box returning, which could break cursor locking depending on the order
m_render_widget->SetWaitingForMessageBox(true);
auto confirm = ModalMessageBox::question(
confirm_parent, tr("Quitter!"),
m_stop_requested ? tr("A user closed down their game from the netplay lobby. "
"This could the Netplay session has ended due to someone ragequitting! "
"Do you want to stop the current emulation?") :
tr("A user closed down their game from the netplay lobby. "
"This could the Netplay session has ended due to someone ragequitting"
"Do you want to stop the current emulation?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
// If a user confirmed stopping the emulation, we do not capture the cursor again,
// even if the render widget will stay alive for a while.
// If a used rejected stopping the emulation, we instead capture the cursor again,
// and let them continue playing as if nothing had happened
// (assuming cursor locking is on).
if (confirm != QMessageBox::Yes)
{
m_render_widget->SetWaitingForMessageBox(false);
if (pause)
Core::SetState(state);
return false;
}
else
{
m_render_widget->SetCursorLockedOnNextActivation(false);
// This needs to be after SetCursorLockedOnNextActivation(false) as it depends on it
m_render_widget->SetWaitingForMessageBox(false);
}
}
OnStopRecording();
// TODO: Add Debugger shutdown
if (!m_stop_requested && UICommon::TriggerSTMPowerEvent())
{
m_stop_requested = true;
// Unpause because gracefully shutting down needs the game to actually request a shutdown.
// TODO: Do not unpause in debug mode to allow debugging until the complete shutdown.
if (Core::GetState() == Core::State::Paused)
Core::SetState(Core::State::Running);
// Tell NetPlay about the power event
if (NetPlay::IsNetPlayRunning())
NetPlay::SendPowerButtonEvent();
return true;
}
ForceStop();
#ifdef Q_OS_WIN
// Allow windows to idle or turn off display again
SetThreadExecutionState(ES_CONTINUOUS);
#endif
return true;
}
void MainWindow::ForceStop()
{
Core::Stop();
@ -1424,10 +1528,11 @@ void MainWindow::NetPlayInit()
m_netplay_discord = new DiscordHandler(this);
#endif
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop);
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::RequestStopNetplay);
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Host, this, &MainWindow::NetPlayHost);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::JoinBrowser, this, &MainWindow::NetPlayJoin);
#ifdef USE_DISCORD_PRESENCE
connect(m_netplay_discord, &DiscordHandler::Join, this, &MainWindow::NetPlayJoin);

View file

@ -90,6 +90,7 @@ private:
// May ask for confirmation. Returns whether or not it actually stopped.
bool RequestStop();
bool RequestStopNetplay();
void ForceStop();
void Reset();
void FrameAdvance();

View file

@ -61,6 +61,7 @@
#include "UICommon/AutoUpdate.h"
#include "UICommon/GameFile.h"
#include <qprocess.h>
QPointer<MenuBar> MenuBar::s_menu_bar;
@ -224,11 +225,6 @@ void MenuBar::AddToolsMenu()
tools_menu->addSeparator();
tools_menu->addAction(tr("Start &NetPlay..."), this, &MenuBar::StartNetPlay);
tools_menu->addAction(tr("Browse &NetPlay Sessions...."), this, &MenuBar::BrowseNetPlay);
tools_menu->addSeparator();
QMenu* gc_ipl = tools_menu->addMenu(tr("Load GameCube Main Menu"));
m_ntscj_ipl = gc_ipl->addAction(tr("NTSC-J"), this,
@ -296,7 +292,7 @@ void MenuBar::AddToolsMenu()
void MenuBar::AddEmulationMenu()
{
QMenu* emu_menu = addMenu(tr("&Emulation"));
m_play_action = emu_menu->addAction(tr("&Play"), this, &MenuBar::Play);
m_play_action = emu_menu->addAction(tr("&Local Play"), this, &MenuBar::Play);
m_pause_action = emu_menu->addAction(tr("&Pause"), this, &MenuBar::Pause);
m_stop_action = emu_menu->addAction(tr("&Stop"), this, &MenuBar::Stop);
m_reset_action = emu_menu->addAction(tr("&Reset"), this, &MenuBar::Reset);
@ -543,16 +539,6 @@ void MenuBar::AddOptionsMenu()
m_change_font = options_menu->addAction(tr("&Font..."), this, &MenuBar::ChangeDebugFont);
}
void MenuBar::InstallUpdateManually()
{
const std::string autoupdate_track = Config::Get(Config::MAIN_AUTOUPDATE_UPDATE_TRACK);
const std::string manual_track = autoupdate_track.empty() ? "dev" : autoupdate_track;
auto* const updater = new Updater(this->parentWidget(), manual_track,
Config::Get(Config::MAIN_AUTOUPDATE_HASH_OVERRIDE));
updater->CheckForUpdate();
}
void MenuBar::AddHelpMenu()
{
QMenu* help_menu = addMenu(tr("&Help"));
@ -574,13 +560,6 @@ void MenuBar::AddHelpMenu()
QUrl(QStringLiteral("https://bugs.dolphin-emu.org/projects/emulator")));
});
if (AutoUpdateChecker::SystemSupportsAutoUpdates())
{
help_menu->addSeparator();
help_menu->addAction(tr("&Check for Updates..."), this, &MenuBar::InstallUpdateManually);
}
#ifndef __APPLE__
help_menu->addSeparator();
#endif

View file

@ -63,61 +63,7 @@ void NetPlayBrowser::CreateWidgets()
{
auto* layout = new QVBoxLayout;
m_table_widget = new QTableWidget;
m_table_widget->setTabKeyNavigation(false);
m_table_widget->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table_widget->setSelectionMode(QAbstractItemView::SingleSelection);
m_table_widget->setWordWrap(false);
m_region_combo = new QComboBox;
m_region_combo->addItem(tr("Any Region"));
for (const auto& region : NetPlayIndex::GetRegions())
{
m_region_combo->addItem(
tr("%1 (%2)").arg(tr(region.second.c_str())).arg(QString::fromStdString(region.first)),
QString::fromStdString(region.first));
}
m_region_combo->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
m_status_label = new QLabel;
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_button_refresh = new NonDefaultQPushButton(tr("Refresh"));
m_edit_name = new QLineEdit;
m_edit_game_id = new QLineEdit;
m_check_hide_incompatible = new QCheckBox(tr("Hide Incompatible Sessions"));
m_check_hide_ingame = new QCheckBox(tr("Hide In-Game Sessions"));
m_check_hide_incompatible->setChecked(true);
m_radio_all = new QRadioButton(tr("Private and Public"));
m_radio_private = new QRadioButton(tr("Private"));
m_radio_public = new QRadioButton(tr("Public"));
m_radio_all->setChecked(true);
auto* filter_box = new QGroupBox(tr("Filters"));
auto* filter_layout = new QGridLayout;
filter_box->setLayout(filter_layout);
filter_layout->addWidget(new QLabel(tr("Region:")), 0, 0);
filter_layout->addWidget(m_region_combo, 0, 1, 1, -1);
filter_layout->addWidget(new QLabel(tr("Name:")), 1, 0);
filter_layout->addWidget(m_edit_name, 1, 1, 1, -1);
filter_layout->addWidget(new QLabel(tr("Game ID:")), 2, 0);
filter_layout->addWidget(m_edit_game_id, 2, 1, 1, -1);
filter_layout->addWidget(m_radio_all, 3, 1);
filter_layout->addWidget(m_radio_public, 3, 2);
filter_layout->addWidget(m_radio_private, 3, 3);
filter_layout->addItem(new QSpacerItem(4, 1, QSizePolicy::Expanding), 3, 4);
filter_layout->addWidget(m_check_hide_incompatible, 4, 1, 1, -1);
filter_layout->addWidget(m_check_hide_ingame, 5, 1, 1, -1);
layout->addWidget(m_table_widget);
layout->addWidget(filter_box);
layout->addWidget(m_status_label);
layout->addWidget(m_button_box);
@ -220,7 +166,7 @@ void NetPlayBrowser::UpdateList()
m_table_widget->clear();
m_table_widget->setColumnCount(7);
m_table_widget->setHorizontalHeaderLabels({tr("Region"), tr("Name"), tr("Password?"),
m_table_widget->setHorizontalHeaderLabels({tr("Name"), tr("Password?"),
tr("In-Game?"), tr("Game"), tr("Players"),
tr("Version")});
@ -239,26 +185,20 @@ void NetPlayBrowser::UpdateList()
{
const auto& entry = m_sessions[i];
auto* region = new QTableWidgetItem(QString::fromStdString(entry.region));
auto* name = new QTableWidgetItem(QString::fromStdString(entry.name));
auto* password = new QTableWidgetItem(entry.has_password ? tr("Yes") : tr("No"));
auto* in_game = new QTableWidgetItem(entry.in_game ? tr("Yes") : tr("No"));
auto* game_id = new QTableWidgetItem(QString::fromStdString(entry.game_id));
auto* player_count = new QTableWidgetItem(QStringLiteral("%1").arg(entry.player_count));
auto* version = new QTableWidgetItem(QString::fromStdString(entry.version));
const bool enabled = Common::GetScmDescStr() == entry.version;
for (const auto& item : {region, name, password, in_game, game_id, player_count, version})
for (const auto& item : {name, in_game, game_id, player_count})
item->setFlags(enabled ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags);
m_table_widget->setItem(i, 0, region);
m_table_widget->setItem(i, 1, name);
m_table_widget->setItem(i, 2, password);
m_table_widget->setItem(i, 3, in_game);
m_table_widget->setItem(i, 4, game_id);
m_table_widget->setItem(i, 5, player_count);
m_table_widget->setItem(i, 6, version);
m_table_widget->setItem(i, 2, in_game);
m_table_widget->setItem(i, 3, game_id);
m_table_widget->setItem(i, 4, player_count);
}
m_status_label->setText(
@ -377,8 +317,11 @@ void NetPlayBrowser::RestoreSettings()
else if (visibility == QStringLiteral("private"))
m_radio_private->setChecked(true);
m_check_hide_incompatible->setChecked(
m_check_hide_incompatible->setChecked(true);
m_check_hide_ingame->setChecked(true);
/* m_check_hide_incompatible->setChecked(
settings.value(QStringLiteral("netplaybrowser/hide_incompatible"), true).toBool());
m_check_hide_ingame->setChecked(
settings.value(QStringLiteral("netplaybrowser/hide_ingame")).toBool());
settings.value(QStringLiteral("netplaybrowser/hide_ingame")).toBool());*/
}

View file

@ -129,6 +129,12 @@ void NetPlayDialog::CreateMainLayout()
m_game_button = new QPushButton;
m_start_button = new QPushButton(tr("Start"));
m_buffer_size_box = new QSpinBox;
m_buffer_size_box->setToolTip(
tr("Set the buffer based on the ping. The buffer should be ping ÷ 8 (rounded up).\nFor a "
"simple method, "
"use 8 for 64 ping and less, 12 for 100 ping and less, and 16 for 150 ping and "
"less.\nGames above 150 ping will be very laggy and are not recommended for competitive "
"play."));
m_buffer_label = new QLabel(tr("Buffer:"));
m_quit_button = new QPushButton(tr("Quit"));
m_splitter = new QSplitter(Qt::Horizontal);
@ -922,7 +928,7 @@ void NetPlayDialog::OnPadBufferChanged(u32 buffer)
});
DisplayMessage(m_host_input_authority ? tr("Max buffer size changed to %1").arg(buffer) :
tr("Buffer size changed to %1").arg(buffer),
"darkcyan");
"orange");
m_buffer_size = static_cast<int>(buffer);
}

View file

@ -9,13 +9,19 @@
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHeaderView>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QRadioButton>
#include <QSignalBlocker>
#include <QSpinBox>
#include <QTabWidget>
#include <QTableWidget>
#include <QTableWidgetItem>
#include "Core/Config/NetplaySettings.h"
#include "Core/NetPlayProto.h"
@ -25,6 +31,8 @@
#include "DolphinQt/QtUtils/UTF8CodePointCountValidator.h"
#include "DolphinQt/Settings.h"
#include "Common/Version.h"
#include "DolphinQt/NetPlay/NetPlayBrowser.h"
#include "UICommon/GameFile.h"
#include "UICommon/NetPlayIndex.h"
@ -37,16 +45,11 @@ NetPlaySetupDialog::NetPlaySetupDialog(const GameListModel& game_list_model, QWi
CreateMainLayout();
bool use_index = Config::Get(Config::NETPLAY_USE_INDEX);
std::string index_region = Config::Get(Config::NETPLAY_INDEX_REGION);
std::string index_name = Config::Get(Config::NETPLAY_INDEX_NAME);
std::string index_password = Config::Get(Config::NETPLAY_INDEX_PASSWORD);
std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
int connect_port = Config::Get(Config::NETPLAY_CONNECT_PORT);
int host_port = Config::Get(Config::NETPLAY_HOST_PORT);
int host_listen_port = Config::Get(Config::NETPLAY_LISTEN_PORT);
bool enable_chunked_upload_limit = Config::Get(Config::NETPLAY_ENABLE_CHUNKED_UPLOAD_LIMIT);
u32 chunked_upload_limit = Config::Get(Config::NETPLAY_CHUNKED_UPLOAD_LIMIT);
#ifdef USE_UPNP
bool use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
@ -58,28 +61,41 @@ NetPlaySetupDialog::NetPlaySetupDialog(const GameListModel& game_list_model, QWi
m_connect_port_box->setValue(connect_port);
m_host_port_box->setValue(host_port);
m_host_force_port_box->setValue(host_listen_port);
m_host_force_port_box->setEnabled(false);
m_host_server_browser->setChecked(use_index);
m_host_server_region->setEnabled(use_index);
m_host_server_region->setCurrentIndex(
m_host_server_region->findData(QString::fromStdString(index_region)));
m_host_server_name->setEnabled(use_index);
m_host_server_name->setText(QString::fromStdString(index_name));
m_host_server_password->setEnabled(use_index);
m_host_server_password->setText(QString::fromStdString(index_password));
// Browser Stuff
const auto& settings = Settings::Instance().GetQSettings();
m_host_chunked_upload_limit_check->setChecked(enable_chunked_upload_limit);
m_host_chunked_upload_limit_box->setValue(chunked_upload_limit);
m_host_chunked_upload_limit_box->setEnabled(enable_chunked_upload_limit);
const QByteArray geometry =
settings.value(QStringLiteral("netplaybrowser/geometry")).toByteArray();
if (!geometry.isEmpty())
restoreGeometry(geometry);
const QString region = settings.value(QStringLiteral("netplaybrowser/region")).toString();
const bool valid_region = m_region_combo->findText(region) != -1;
if (valid_region)
m_region_combo->setCurrentText(region);
m_edit_name->setText(settings.value(QStringLiteral("netplaybrowser/name")).toString());
const QString visibility = settings.value(QStringLiteral("netplaybrowser/visibility")).toString();
if (visibility == QStringLiteral("public"))
m_radio_public->setChecked(true);
else if (visibility == QStringLiteral("private"))
m_radio_private->setChecked(true);
m_check_hide_ingame->setChecked(true);
OnConnectionTypeChanged(m_connection_type->currentIndex());
ConnectWidgets();
m_refresh_run.Set(true);
m_refresh_thread = std::thread([this] { RefreshLoopBrowser(); });
UpdateListBrowser();
RefreshBrowser();
}
void NetPlaySetupDialog::CreateMainLayout()
@ -88,7 +104,10 @@ void NetPlaySetupDialog::CreateMainLayout()
m_button_box = new QDialogButtonBox(QDialogButtonBox::Cancel);
m_nickname_edit = new QLineEdit;
m_connection_type = new QComboBox;
m_connection_type->setCurrentIndex(1);
m_reset_traversal_button = new NonDefaultQPushButton(tr("Reset Traversal Settings"));
m_tab_widget = new QTabWidget;
m_nickname_edit->setValidator(
@ -98,6 +117,50 @@ void NetPlaySetupDialog::CreateMainLayout()
auto* connection_widget = new QWidget;
auto* connection_layout = new QGridLayout;
// NetPlay Browser
auto* browser_widget = new QWidget;
auto* layout = new QVBoxLayout;
m_table_widget = new QTableWidget;
m_table_widget->setTabKeyNavigation(false);
m_table_widget->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table_widget->setSelectionMode(QAbstractItemView::SingleSelection);
m_table_widget->setWordWrap(false);
m_region_combo = new QComboBox;
m_region_combo->addItem(tr("Any Region"));
for (const auto& region : NetPlayIndex::GetRegions())
{
m_region_combo->addItem(
tr("%1 (%2)").arg(tr(region.second.c_str())).arg(QString::fromStdString(region.first)),
QString::fromStdString(region.first));
}
m_region_combo->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
m_status_label = new QLabel;
m_b_button_box = new QDialogButtonBox;
m_button_refresh = new QPushButton(tr("Refresh"));
m_edit_name = new QLineEdit;
m_check_hide_ingame = new QCheckBox(tr("Hide In-Game Sessions"));
m_radio_all = new QRadioButton(tr("Private and Public"));
m_radio_private = new QRadioButton(tr("Private"));
m_radio_public = new QRadioButton(tr("Public"));
m_radio_all->setChecked(true);
layout->addWidget(m_table_widget);
layout->addWidget(m_status_label);
layout->addWidget(m_b_button_box);
m_b_button_box->addButton(m_button_refresh, QDialogButtonBox::ResetRole);
browser_widget->setLayout(layout);
m_ip_label = new QLabel;
m_ip_edit = new QLineEdit;
m_connect_port_label = new QLabel(tr("Port:"));
@ -113,7 +176,7 @@ void NetPlaySetupDialog::CreateMainLayout()
connection_layout->addWidget(
new QLabel(
tr("ALERT:\n\n"
"All players must use the same Dolphin version.\n"
"All players must use the same Dolphin version, unless Orange Dolphin is used to host\n"
"If enabled, SD cards must be identical between players.\n"
"If DSP LLE is used, DSP ROMs must be identical between players.\n"
"If a game is hanging on boot, it may not support Dual Core Netplay."
@ -130,16 +193,10 @@ void NetPlaySetupDialog::CreateMainLayout()
// Host widget
auto* host_widget = new QWidget;
auto* host_layout = new QGridLayout;
m_host_port_label = new QLabel(tr("Port:"));
m_host_port_box = new QSpinBox;
m_host_force_port_check = new QCheckBox(tr("Force Listen Port:"));
m_host_force_port_box = new QSpinBox;
m_host_chunked_upload_limit_check = new QCheckBox(tr("Limit Chunked Upload Speed:"));
m_host_chunked_upload_limit_box = new QSpinBox;
m_host_server_browser = new QCheckBox(tr("Show in server browser"));
m_host_server_name = new QLineEdit;
m_host_server_password = new QLineEdit;
m_host_server_region = new QComboBox;
#ifdef USE_UPNP
m_host_upnp = new QCheckBox(tr("Forward port (UPnP)"));
@ -148,41 +205,17 @@ void NetPlaySetupDialog::CreateMainLayout()
m_host_button = new NonDefaultQPushButton(tr("Host"));
m_host_port_box->setMaximum(65535);
m_host_force_port_box->setMaximum(65535);
m_host_chunked_upload_limit_box->setRange(1, 1000000);
m_host_chunked_upload_limit_box->setSingleStep(100);
m_host_chunked_upload_limit_box->setSuffix(QStringLiteral(" kbps"));
m_host_chunked_upload_limit_check->setToolTip(tr(
"This will limit the speed of chunked uploading per client, which is used for save sync."));
m_host_server_name->setToolTip(tr("Name of your session shown in the server browser"));
m_host_server_name->setPlaceholderText(tr("Name"));
m_host_server_password->setToolTip(tr("Password for joining your game (leave empty for none)"));
m_host_server_password->setPlaceholderText(tr("Password"));
for (const auto& region : NetPlayIndex::GetRegions())
{
m_host_server_region->addItem(
tr("%1 (%2)").arg(tr(region.second.c_str())).arg(QString::fromStdString(region.first)),
QString::fromStdString(region.first));
}
host_layout->addWidget(m_host_port_label, 0, 0);
host_layout->addWidget(m_host_port_box, 0, 1);
host_layout->addWidget(m_host_port_box, 0, 0, Qt::AlignLeft);
#ifdef USE_UPNP
host_layout->addWidget(m_host_upnp, 0, 2);
host_layout->addWidget(m_host_upnp, 0, 5, Qt::AlignRight);
#endif
host_layout->addWidget(m_host_server_browser, 1, 0);
host_layout->addWidget(m_host_server_region, 1, 1);
host_layout->addWidget(m_host_server_name, 1, 2);
host_layout->addWidget(m_host_server_password, 1, 3);
host_layout->addWidget(m_host_games, 2, 0, 1, -1);
host_layout->addWidget(m_host_force_port_check, 3, 0);
host_layout->addWidget(m_host_force_port_box, 3, 1, Qt::AlignLeft);
host_layout->addWidget(m_host_chunked_upload_limit_check, 4, 0);
host_layout->addWidget(m_host_chunked_upload_limit_box, 4, 1, Qt::AlignLeft);
host_layout->addWidget(m_host_button, 4, 3, 2, 1, Qt::AlignRight);
host_layout->addWidget(m_host_button, 4, 5, Qt::AlignRight);
host_widget->setLayout(host_layout);
@ -200,10 +233,21 @@ void NetPlaySetupDialog::CreateMainLayout()
// Tabs
m_tab_widget->addTab(connection_widget, tr("Connect"));
m_tab_widget->addTab(host_widget, tr("Host"));
m_tab_widget->addTab(browser_widget, tr("Browser"));
setLayout(m_main_layout);
}
NetPlaySetupDialog::~NetPlaySetupDialog()
{
m_refresh_run.Set(false);
m_refresh_event.Set();
if (m_refresh_thread.joinable())
m_refresh_thread.join();
SaveSettings();
}
void NetPlaySetupDialog::ConnectWidgets()
{
connect(m_connection_type, qOverload<int>(&QComboBox::currentIndexChanged), this,
@ -222,23 +266,12 @@ void NetPlaySetupDialog::ConnectWidgets()
m_host_games->item(index)->text());
});
// refresh browser on tab changed
connect(m_tab_widget, &QTabWidget::currentChanged, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_host_games, &QListWidget::itemDoubleClicked, this, &NetPlaySetupDialog::accept);
connect(m_host_force_port_check, &QCheckBox::toggled,
[this](bool value) { m_host_force_port_box->setEnabled(value); });
connect(m_host_chunked_upload_limit_check, &QCheckBox::toggled, this, [this](bool value) {
m_host_chunked_upload_limit_box->setEnabled(value);
SaveSettings();
});
connect(m_host_chunked_upload_limit_box, qOverload<int>(&QSpinBox::valueChanged), this,
&NetPlaySetupDialog::SaveSettings);
connect(m_host_server_browser, &QCheckBox::toggled, this, &NetPlaySetupDialog::SaveSettings);
connect(m_host_server_name, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
connect(m_host_server_password, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
connect(m_host_server_region,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&NetPlaySetupDialog::SaveSettings);
#ifdef USE_UPNP
connect(m_host_upnp, &QCheckBox::stateChanged, this, &NetPlaySetupDialog::SaveSettings);
@ -249,11 +282,26 @@ void NetPlaySetupDialog::ConnectWidgets()
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(m_reset_traversal_button, &QPushButton::clicked, this,
&NetPlaySetupDialog::ResetTraversalHost);
connect(m_host_server_browser, &QCheckBox::toggled, this, [this](bool value) {
m_host_server_region->setEnabled(value);
m_host_server_name->setEnabled(value);
m_host_server_password->setEnabled(value);
});
// Browser Stuff
connect(m_region_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
&NetPlaySetupDialog::RefreshBrowser);
connect(m_button_refresh, &QPushButton::clicked, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_radio_all, &QRadioButton::toggled, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_radio_private, &QRadioButton::toggled, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_check_hide_ingame, &QRadioButton::toggled, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_edit_name, &QLineEdit::textChanged, this, &NetPlaySetupDialog::RefreshBrowser);
connect(m_table_widget, &QTableWidget::itemDoubleClicked, this,
&NetPlaySetupDialog::acceptBrowser);
connect(this, &NetPlaySetupDialog::UpdateStatusRequestedBrowser, this,
&NetPlaySetupDialog::OnUpdateStatusRequestedBrowser, Qt::QueuedConnection);
connect(this, &NetPlaySetupDialog::UpdateListRequestedBrowser, this,
&NetPlaySetupDialog::OnUpdateListRequestedBrowser, Qt::QueuedConnection);
}
void NetPlaySetupDialog::SaveSettings()
@ -271,21 +319,27 @@ void NetPlaySetupDialog::SaveSettings()
Config::SetBaseOrCurrent(Config::NETPLAY_USE_UPNP, m_host_upnp->isChecked());
#endif
if (m_host_force_port_check->isChecked())
Config::SetBaseOrCurrent(Config::NETPLAY_LISTEN_PORT,
static_cast<u16>(m_host_force_port_box->value()));
Config::SetBaseOrCurrent(Config::NETPLAY_ENABLE_CHUNKED_UPLOAD_LIMIT,
m_host_chunked_upload_limit_check->isChecked());
Config::SetBaseOrCurrent(Config::NETPLAY_CHUNKED_UPLOAD_LIMIT,
m_host_chunked_upload_limit_box->value());
Config::SetBaseOrCurrent(Config::NETPLAY_USE_INDEX, m_host_server_browser->isChecked());
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_REGION,
m_host_server_region->currentData().toString().toStdString());
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_REGION, "NA");
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_NAME, m_host_server_name->text().toStdString());
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_PASSWORD,
m_host_server_password->text().toStdString());
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_PASSWORD, "");
// Browser Stuff
auto& settings = Settings::Instance().GetQSettings();
settings.setValue(QStringLiteral("netplaybrowser/geometry"), saveGeometry());
settings.setValue(QStringLiteral("netplaybrowser/region"), m_region_combo->currentText());
settings.setValue(QStringLiteral("netplaybrowser/name"), m_edit_name->text());
QString visibility(QStringLiteral("all"));
if (m_radio_public->isChecked())
visibility = QStringLiteral("public");
else if (m_radio_private->isChecked())
visibility = QStringLiteral("private");
settings.setValue(QStringLiteral("netplaybrowser/visibility"), visibility);
settings.setValue(QStringLiteral("netplaybrowser/hide_incompatible"), true);
settings.setValue(QStringLiteral("netplaybrowser/hide_ingame"), m_check_hide_ingame->isChecked());
}
void NetPlaySetupDialog::OnConnectionTypeChanged(int index)
@ -293,14 +347,10 @@ void NetPlaySetupDialog::OnConnectionTypeChanged(int index)
m_connect_port_box->setHidden(index != 0);
m_connect_port_label->setHidden(index != 0);
m_host_port_label->setHidden(index != 0);
m_host_port_box->setHidden(index != 0);
#ifdef USE_UPNP
m_host_upnp->setHidden(index != 0);
#endif
m_host_force_port_check->setHidden(index == 0);
m_host_force_port_box->setHidden(index == 0);
m_reset_traversal_button->setHidden(index == 0);
std::string address =
@ -315,6 +365,16 @@ void NetPlaySetupDialog::OnConnectionTypeChanged(int index)
void NetPlaySetupDialog::show()
{
// Here i'm setting the lobby name if it's empty to make
// NetPlay sessions start more easily for first time players
if (m_host_server_name->text().isEmpty())
{
std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
m_host_server_name->setText(QString::fromStdString(nickname));
}
m_connection_type->setCurrentIndex(1);
m_tab_widget->setCurrentIndex(2); // start on browser
PopulateGameList();
QDialog::show();
}
@ -335,20 +395,6 @@ void NetPlaySetupDialog::accept()
return;
}
if (m_host_server_browser->isChecked() && m_host_server_name->text().isEmpty())
{
ModalMessageBox::critical(this, tr("Error"), tr("You must provide a name for your session!"));
return;
}
if (m_host_server_browser->isChecked() &&
m_host_server_region->currentData().toString().isEmpty())
{
ModalMessageBox::critical(this, tr("Error"),
tr("You must provide a region for your session!"));
return;
}
emit Host(*items[0]->data(Qt::UserRole).value<std::shared_ptr<const UICommon::GameFile>>());
}
}
@ -391,3 +437,176 @@ void NetPlaySetupDialog::ResetTraversalHost()
.arg(QString::fromStdString(Config::NETPLAY_TRAVERSAL_SERVER.GetDefaultValue()),
QString::number(Config::NETPLAY_TRAVERSAL_PORT.GetDefaultValue())));
}
void NetPlaySetupDialog::RefreshBrowser()
{
std::map<std::string, std::string> filters;
if (!m_edit_name->text().isEmpty())
filters["name"] = m_edit_name->text().toStdString();
if (true)
filters["version"] = Common::GetScmDescStr();
if (!m_radio_all->isChecked())
filters["password"] = std::to_string(m_radio_private->isChecked());
if (m_region_combo->currentIndex() != 0)
filters["region"] = m_region_combo->currentData().toString().toStdString();
if (m_check_hide_ingame->isChecked())
filters["in_game"] = "0";
std::unique_lock<std::mutex> lock(m_refresh_filters_mutex);
m_refresh_filters = std::move(filters);
m_refresh_event.Set();
SaveSettings();
}
void NetPlaySetupDialog::RefreshLoopBrowser()
{
while (m_refresh_run.IsSet())
{
m_refresh_event.Wait();
std::unique_lock<std::mutex> lock(m_refresh_filters_mutex);
if (m_refresh_filters)
{
auto filters = std::move(*m_refresh_filters);
m_refresh_filters.reset();
lock.unlock();
emit UpdateStatusRequestedBrowser(tr("Refreshing..."));
NetPlayIndex client;
auto entries = client.List(filters);
if (entries)
{
emit UpdateListRequestedBrowser(std::move(*entries));
}
else
{
emit UpdateStatusRequestedBrowser(tr("Error obtaining session list: %1")
.arg(QString::fromStdString(client.GetLastError())));
}
}
}
}
void NetPlaySetupDialog::UpdateListBrowser()
{
const int session_count = static_cast<int>(m_sessions.size());
m_table_widget->clear();
m_table_widget->setColumnCount(4);
m_table_widget->setHorizontalHeaderLabels({
tr("Name"),
tr("Game"),
tr("Players"),
tr("In-Game"),
});
auto* hor_header = m_table_widget->horizontalHeader();
hor_header->setSectionResizeMode(0, QHeaderView::Stretch);
hor_header->setSectionResizeMode(0, QHeaderView::Stretch);
hor_header->setSectionResizeMode(1, QHeaderView::Stretch);
hor_header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
hor_header->setSectionResizeMode(3, QHeaderView::ResizeToContents);
hor_header->setHighlightSections(false);
m_table_widget->setRowCount(session_count);
for (int i = 0; i < session_count; i++)
{
const auto& entry = m_sessions[i];
auto* name = new QTableWidgetItem(QString::fromStdString(entry.name));
auto* in_game = new QTableWidgetItem(entry.in_game ? tr("Yes") : tr("No"));
auto* game_id = new QTableWidgetItem(QString::fromStdString(entry.game_id));
auto* player_count = new QTableWidgetItem(QStringLiteral("%1").arg(entry.player_count));
const bool enabled = Common::GetScmDescStr() == entry.version;
for (const auto& item : {name, game_id, player_count, in_game})
item->setFlags(enabled ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags);
m_table_widget->setItem(i, 0, name);
m_table_widget->setItem(i, 1, game_id);
m_table_widget->setItem(i, 2, player_count);
m_table_widget->setItem(i, 3, in_game);
}
m_status_label->setText(
(session_count == 1 ? tr("%1 session found") : tr("%1 sessions found")).arg(session_count));
}
void NetPlaySetupDialog::OnSelectionChangedBrowser()
{
return;
}
void NetPlaySetupDialog::OnUpdateStatusRequestedBrowser(const QString& status)
{
m_status_label->setText(status);
}
void NetPlaySetupDialog::OnUpdateListRequestedBrowser(std::vector<NetPlaySession> sessions)
{
m_sessions = std::move(sessions);
UpdateListBrowser();
}
void NetPlaySetupDialog::acceptBrowser()
{
if (m_table_widget->selectedItems().isEmpty())
return;
const int index = m_table_widget->selectedItems()[0]->row();
NetPlaySession& session = m_sessions[index];
std::string server_id = session.server_id;
if (m_sessions[index].has_password)
{
auto* dialog = new QInputDialog(this);
dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
dialog->setWindowTitle(tr("Enter password"));
dialog->setLabelText(tr("This session requires a password:"));
dialog->setWindowModality(Qt::WindowModal);
dialog->setTextEchoMode(QLineEdit::Password);
if (dialog->exec() != QDialog::Accepted)
return;
const std::string password = dialog->textValue().toStdString();
auto decrypted_id = session.DecryptID(password);
if (!decrypted_id)
{
ModalMessageBox::warning(this, tr("Error"), tr("Invalid password provided."));
return;
}
server_id = decrypted_id.value();
}
QDialog::accept();
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_CHOICE, session.method);
Config::SetBaseOrCurrent(Config::NETPLAY_CONNECT_PORT, session.port);
if (session.method == "traversal")
Config::SetBaseOrCurrent(Config::NETPLAY_HOST_CODE, server_id);
else
Config::SetBaseOrCurrent(Config::NETPLAY_ADDRESS, server_id);
emit JoinBrowser();
}

View file

@ -6,6 +6,7 @@
#include <QDialog>
#include "DolphinQt/GameList/GameListModel.h"
#include "UICommon/NetPlayIndex.h"
class QCheckBox;
class QComboBox;
@ -17,6 +18,9 @@ class QGridLayout;
class QPushButton;
class QSpinBox;
class QTabWidget;
class QGroupBox;
class QTableWidget;
class QRadioButton;
namespace UICommon
{
@ -28,13 +32,17 @@ class NetPlaySetupDialog : public QDialog
Q_OBJECT
public:
explicit NetPlaySetupDialog(const GameListModel& game_list_model, QWidget* parent);
~NetPlaySetupDialog();
void accept() override;
void show();
signals:
bool Join();
void JoinBrowser();
bool Host(const UICommon::GameFile& game);
void UpdateStatusRequestedBrowser(const QString& status);
void UpdateListRequestedBrowser(std::vector<NetPlaySession> sessions);
private:
void CreateMainLayout();
@ -42,6 +50,15 @@ private:
void PopulateGameList();
void ResetTraversalHost();
// Browser Stuff
void RefreshBrowser();
void RefreshLoopBrowser();
void UpdateListBrowser();
void OnSelectionChangedBrowser();
void OnUpdateStatusRequestedBrowser(const QString& status);
void OnUpdateListRequestedBrowser(std::vector<NetPlaySession> sessions);
void acceptBrowser();
void SaveSettings();
void OnConnectionTypeChanged(int index);
@ -62,18 +79,32 @@ private:
QPushButton* m_connect_button;
// Host Widget
QLabel* m_host_port_label;
QSpinBox* m_host_port_box;
QListWidget* m_host_games;
QPushButton* m_host_button;
QCheckBox* m_host_force_port_check;
QSpinBox* m_host_force_port_box;
QCheckBox* m_host_chunked_upload_limit_check;
QSpinBox* m_host_chunked_upload_limit_box;
QCheckBox* m_host_server_browser;
QLineEdit* m_host_server_name;
QLineEdit* m_host_server_password;
QComboBox* m_host_server_region;
QTableWidget* m_table_widget;
QComboBox* m_region_combo;
QLabel* m_status_label;
QDialogButtonBox* m_b_button_box;
QPushButton* m_button_refresh;
QLineEdit* m_edit_name;
QCheckBox* m_check_hide_ingame;
QRadioButton* m_radio_all;
QRadioButton* m_radio_private;
QRadioButton* m_radio_public;
std::vector<NetPlaySession> m_sessions;
std::thread m_refresh_thread;
std::optional<std::map<std::string, std::string>> m_refresh_filters;
std::mutex m_refresh_filters_mutex;
Common::Flag m_refresh_run;
Common::Event m_refresh_event;
#ifdef USE_UPNP
QCheckBox* m_host_upnp;

View file

@ -65,9 +65,6 @@ void GeneralPane::CreateLayout()
// Create layout here
CreateBasic();
if (AutoUpdateChecker::SystemSupportsAutoUpdates())
CreateAutoUpdate();
CreateFallbackRegion();
#if defined(USE_ANALYTICS) && USE_ANALYTICS
@ -175,25 +172,6 @@ void GeneralPane::CreateBasic()
speed_limit_layout->addRow(tr("&Speed Limit:"), m_combobox_speedlimit);
}
void GeneralPane::CreateAutoUpdate()
{
auto* auto_update_group = new QGroupBox(tr("Auto Update Settings"));
auto* auto_update_group_layout = new QFormLayout;
auto_update_group->setLayout(auto_update_group_layout);
m_main_layout->addWidget(auto_update_group);
auto_update_group_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
auto_update_group_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
m_combobox_update_track = new QComboBox(this);
auto_update_group_layout->addRow(tr("&Auto Update:"), m_combobox_update_track);
for (const QString& option :
{tr("Don't Update"), tr("Beta (once a month)"), tr("Dev (multiple times a day)")})
m_combobox_update_track->addItem(option);
}
void GeneralPane::CreateFallbackRegion()
{
auto* fallback_region_group = new QGroupBox(tr("Fallback Region"));

View file

@ -28,7 +28,7 @@ private:
void CreateLayout();
void ConnectLayout();
void CreateBasic();
void CreateAutoUpdate();
//void CreateAutoUpdate();
void CreateFallbackRegion();
void LoadConfig();

View file

@ -128,7 +128,7 @@ void InterfacePane::CreateUI()
// User Style Combobox
m_combobox_userstyle = new QComboBox;
m_label_userstyle = new QLabel(tr("User Style:"));
m_label_userstyle = new QLabel(tr("Window Theme:"));
combobox_layout->addRow(m_label_userstyle, m_combobox_userstyle);
auto userstyle_search_results = Common::DoFileSearch({File::GetUserPath(D_STYLES_IDX)});
@ -210,6 +210,7 @@ void InterfacePane::ConnectLayout()
{
connect(m_checkbox_use_builtin_title_database, &QCheckBox::toggled, this,
&InterfacePane::OnSaveConfig);
connect(m_checkbox_use_userstyle, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_use_covers, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_disable_screensaver, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);

View file

@ -118,9 +118,12 @@ void ToolBar::MakeActions()
addSeparator();
m_pause_play_action = addAction(tr("Play"), this, &ToolBar::PlayPressed);
m_pause_play_action = addAction(tr("Local Play"), this, &ToolBar::PlayPressed);
m_start_netplay_action = addAction(tr("Online Play"), this, &ToolBar::StartNetPlayPressed);
m_stop_action = addAction(tr("Stop"), this, &ToolBar::StopPressed);
addSeparator();
m_fullscreen_action = addAction(tr("FullScr"), this, &ToolBar::FullScreenPressed);
m_screenshot_action = addAction(tr("ScrShot"), this, &ToolBar::ScreenShotPressed);
@ -162,7 +165,7 @@ void ToolBar::UpdatePausePlayButtonState(const bool playing_state)
else
{
disconnect(m_pause_play_action, 0, 0, 0);
m_pause_play_action->setText(tr("Play"));
m_pause_play_action->setText(tr("Local Play"));
m_pause_play_action->setIcon(Resources::GetScaledThemeIcon("play"));
connect(m_pause_play_action, &QAction::triggered, this, &ToolBar::PlayPressed);
}
@ -193,4 +196,5 @@ void ToolBar::UpdateIcons()
m_config_action->setIcon(Resources::GetScaledThemeIcon("config"));
m_controllers_action->setIcon(Resources::GetScaledThemeIcon("classic"));
m_graphics_action->setIcon(Resources::GetScaledThemeIcon("graphics"));
m_start_netplay_action->setIcon(Resources::GetScaledThemeIcon("wifi"));
}

View file

@ -33,6 +33,8 @@ signals:
void ControllersPressed();
void GraphicsPressed();
void StartNetPlayPressed();
void StepPressed();
void StepOverPressed();
void StepOutPressed();
@ -58,6 +60,8 @@ private:
QAction* m_controllers_action;
QAction* m_graphics_action;
QAction* m_start_netplay_action;
QAction* m_step_action;
QAction* m_step_over_action;
QAction* m_step_out_action;

View file

@ -195,65 +195,17 @@ void AutoUpdateChecker::CheckForUpdate(std::string_view update_track,
version_hash, GetPlatformID());
const bool is_manual_check = check_type == CheckType::Manual;
Common::HttpRequest req{std::chrono::seconds{10}};
auto resp = req.Get(url);
if (!resp)
{
if (is_manual_check)
CriticalAlertFmtT("Unable to contact update server.");
return;
}
const std::string contents(reinterpret_cast<char*>(resp->data()), resp->size());
INFO_LOG_FMT(COMMON, "Auto-update JSON response: {}", contents);
picojson::value json;
const std::string err = picojson::parse(json, contents);
if (!err.empty())
{
CriticalAlertFmtT("Invalid JSON received from auto-update service : {0}", err);
return;
}
picojson::object obj = json.get<picojson::object>();
if (obj["status"].get<std::string>() != "outdated")
{
if (is_manual_check)
SuccessAlertFmtT("You are running the latest version available on this update track.");
INFO_LOG_FMT(COMMON, "Auto-update status: we are up to date.");
return;
}
NewVersionInformation nvi;
nvi.this_manifest_url = obj["old"].get<picojson::object>()["manifest"].get<std::string>();
nvi.next_manifest_url = obj["new"].get<picojson::object>()["manifest"].get<std::string>();
nvi.content_store_url = obj["content-store"].get<std::string>();
nvi.new_shortrev = obj["new"].get<picojson::object>()["name"].get<std::string>();
nvi.new_hash = obj["new"].get<picojson::object>()["hash"].get<std::string>();
// TODO: generate the HTML changelog from the JSON information.
nvi.changelog_html = GenerateChangelog(obj["changelog"].get<picojson::array>());
if (std::getenv("DOLPHIN_UPDATE_TEST_DONE"))
{
// We are at end of updater test flow, send a message to server, which will kill us.
req.Get(fmt::format("{}/update-test-done/{}", GetUpdateServerUrl(), GetOwnProcessId()));
}
else
{
OnUpdateAvailable(nvi);
}
}
void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInformation& info,
const AutoUpdateChecker::RestartMode restart_mode)
{
// Check to make sure we don't already have an update triggered
if (s_update_triggered)
/* if (s_update_triggered)
{
WARN_LOG_FMT(COMMON, "Auto-update: received a redundant trigger request, ignoring");
return;
}
}*/
s_update_triggered = true;
#ifdef OS_SUPPORTS_UPDATER

View file

@ -3,6 +3,9 @@
#include "UICommon/DiscordPresence.h"
#include "Common/Hash.h"
#include "Common/StringUtil.h"
#include "Core/Config/NetplaySettings.h"
#include "Core/Config/UISettings.h"
#include "Core/ConfigManager.h"
@ -109,11 +112,6 @@ std::string ArtworkForGameId(const std::string& gameid)
"GFT", // GFTE01: Mario Golf: Toadstool Tour
"RMC", // RMCE01: Mario Kart Wii
"GM4", // GM4E01: Mario Kart: Double Dash!!
"GMP", // GMPE01: Mario Party 4
"GP5", // GP5E01: Mario Party 5
"GP6", // GP6E01: Mario Party 6
"GP7", // GP7E01: Mario Party 7
"RM8", // RM8E01: Mario Party 8
"SSQ", // SSQE01: Mario Party 9
"GOM", // GOME01: Mario Power Tennis
"GYQ", // GYQE01: Mario Superstar Baseball
@ -191,7 +189,8 @@ void Init()
handlers.ready = HandleDiscordReady;
handlers.joinRequest = HandleDiscordJoinRequest;
handlers.joinGame = HandleDiscordJoin;
Discord_Initialize(DEFAULT_CLIENT_ID.c_str(), &handlers, 1, nullptr);
// The number is the client ID for Dolphin, it's used for images and the application name
Discord_Initialize("888655408623943731", &handlers, 1, nullptr);
UpdateDiscordPresence();
#endif
}
@ -283,33 +282,26 @@ void UpdateDiscordPresence(int party_size, SecretType type, const std::string& s
DiscordRichPresence discord_presence = {};
if (game_artwork.empty())
{
discord_presence.largeImageKey = "dolphin_logo";
discord_presence.largeImageText = "Dolphin is an emulator for the GameCube and the Wii.";
discord_presence.largeImageKey = "dolphin";
}
else
{
discord_presence.largeImageKey = game_artwork.c_str();
discord_presence.largeImageText = title.c_str();
discord_presence.smallImageKey = "dolphin_logo";
discord_presence.smallImageText = "Dolphin is an emulator for the GameCube and the Wii.";
discord_presence.smallImageKey = "dolphin";
}
discord_presence.details = title.empty() ? "Not in-game" : title.c_str();
discord_presence.startTimestamp = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
if (party_size > 0)
{
if (party_size < 4)
{
discord_presence.state = "In a party";
discord_presence.partySize = party_size;
discord_presence.partyMax = 4;
}
else
{
// others can still join to spectate
discord_presence.state = "In a full party";
discord_presence.partySize = party_size;
// Note: joining still works without partyMax
}

View file

@ -339,60 +339,11 @@ void SetUserDirectory(std::string custom_path)
local = local != 0 || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt");
// Attempt to check if the old User directory exists in Documents.
wil::unique_cotaskmem_string documents;
bool documents_found = SUCCEEDED(
SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, documents.put()));
// Get Documents path in case we need it.
// TODO: Maybe use WIL when it's available?
PWSTR my_documents = nullptr;
std::optional<std::string> old_user_folder;
if (documents_found)
{
old_user_folder = TStrToUTF8(documents.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP;
}
if (local) // Case 1-2
{
user_path = File::GetExeDirectory() + DIR_SEP PORTABLE_USER_DIR DIR_SEP;
}
else if (configPath) // Case 3
{
user_path = TStrToUTF8(configPath.get());
}
else if (old_user_folder && File::Exists(old_user_folder.value())) // Case 4
{
user_path = old_user_folder.value();
}
else if (appdata_found) // Case 5
{
user_path = TStrToUTF8(appdata.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP;
// Set the UserConfigPath value in the registry for backwards compatibility with older Dolphin
// builds, which will look for the default User directory in Documents. If we set this key,
// they will use this as the User directory instead.
// (If we're in this case, then this key doesn't exist, so it's OK to set it.)
std::wstring wstr_path = UTF8ToWString(user_path);
RegSetKeyValueW(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), TEXT("UserConfigPath"),
REG_SZ, wstr_path.c_str(),
static_cast<DWORD>((wstr_path.size() + 1) * sizeof(wchar_t)));
}
else // Case 6
{
user_path = File::GetExeDirectory() + DIR_SEP PORTABLE_USER_DIR DIR_SEP;
}
#else // ifndef STEAM
if (File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt")) // Case 1
{
user_path = File::GetExeDirectory() + DIR_SEP PORTABLE_USER_DIR DIR_SEP;
}
else if (appdata_found) // Case 2
{
user_path = TStrToUTF8(appdata.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP;
}
else // Case 3
{
user_path = File::GetExeDirectory() + DIR_SEP PORTABLE_USER_DIR DIR_SEP;
}
#endif
user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
#else
if (File::IsDirectory(ROOT_DIR DIR_SEP EMBEDDED_USER_DIR))

View file

@ -197,7 +197,7 @@ void HiresTexture::Prefetch()
if (size_sum > max_mem)
{
Config::SetCurrent(Config::GFX_HIRES_TEXTURES, false);
Config::SetCurrent(Config::GFX_HIRES_TEXTURES, true);
OSD::AddMessage(
fmt::format(