Skip to content

Commit

Permalink
Merge branch 'netplay_canary_experimental' of https://github.com/Adri…
Browse files Browse the repository at this point in the history
…anCassar/xenia-canary into netplay_canary_experimental
  • Loading branch information
marinesciencedude committed Dec 31, 2023
2 parents 1852b31 + 17b6784 commit 623f2b2
Show file tree
Hide file tree
Showing 34 changed files with 1,821 additions and 876 deletions.
86 changes: 64 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,60 +33,102 @@ Are games dependant on servers?

Can I use multiple instances for the same game?

- No, you cannot use multiple instances due to the first instance using up ports. You will need to use a VM.
- No, you cannot use multiple instances due to the first instance using up ports. You will need to use a VM or a [Shadow PC](https://shadow.tech/).

Can I use multiple PCs on the same network?

- No, you currently cannot use different PCs on the same network to connect to a session hosted on the same network. However a VPN will get around this issue.

Where can I **download** the Canary Netplay build?

- You can download it from [releases](https://github.com/marinesciencedude/xenia-canary-mousehook/tree/netplay_canary_experimental).
- You can download it from [releases](https://github.com/marinesciencedude/xenia-canary-mousehook/releases?q=Netplay).

## Config Setup

To connect to a **Xenia WebServices** server you can either privately host it yourself or connect to my server.

```toml
api_address = "https://xenia-netplay-2a0298c0e3f4.herokuapp.com/"
api_address = "https://xenia-netplay-2a0298c0e3f4.herokuapp.com"
```

UPnP is disabled by default, you can enable it in the config.
```toml
upnp = true
```

## Linux Notes

<details>
<summary>Failure to Bind to Ports</summary>

### Failure to Bind to Ports
Binding to ports <= 1024 will usually fail on Linux as they are protected by default. To verify this is an issue you are encountering, search your log for the following message:
`NetDll_WSAGetLastError: 10013`

To fix this run this command:
```console
sudo sysctl net.ipv4.ip_unprivileged_port_start=999
echo 'sysctl net.ipv4.ip_unprivileged_port_start=999' | sudo tee /etc/sysctl.d/99-xenia.conf
```
This command configures privileged ports to start at port 999 instead of port 1024 in this logon session and future logons. This should allow for most games to now bind.

If you are still seeing `NetDll_WSAGetLastError: 10013` in logs after running this, you can try rerunning the previous commands with a number lower than `999`. `23` should solve every case. You can try `0` but it will prevent you from running ssh.

It should also be noted that due to the way Steam Decks handle configuration, you will need to rerun this command on every reboot.

</details>

## Supported Games

| Game | Notes | Patches/Plugins |
|---|---|---|
| CS:GO | Mousehook support |
| CS:GO Beta | Mousehook support |
| GTA V Beta | [Video 1](https://www.youtube.com/watch?v=nIjZ7sRGZlo), [Video 2](https://www.youtube.com/watch?v=YIBjy5ZJcq4) |
| GTA V TU 2-13 | Very unstable and will crash often |
| Gundam Operation Troy | [English patch](https://github.com/Eight-Mansions/MSGOT/releases)
| Halo 3 ODST v13.2 using [Sunrise Server](https://github.com/ahnewark/Sunrise-Halo3-WebServices) | [Video](https://www.youtube.com/watch?v=amS8OxH3exs), Mousehook support | [Halo 3 Patch](https://github.com/AdrianCassar/Xenia-WebServices/blob/main/patches/4D5307E6%20-%20Halo%203.patch.toml)
| Left 4 Dead 2 | Mousehook support |
| Game | Notes | Gameplay | Patches/Plugins |
|---|---|---|---|
| CS:GO | Mousehook |
| CS:GO Beta | Mousehook |
| Call of Duty 2 | ```launch_module = "default_mp.xex"``` | [Deathmatch](https://www.youtube.com/watch?v=DR9Op_f1UUw) |
| Death Tank | |
| DiRT | | [Race](https://www.youtube.com/watch?v=udMf-MUzpEc) |
| GRID | |
| GTA V Beta | Requires ```protect_zero = false``` or use patches. | [Beta Showcase](https://www.youtube.com/watch?v=nIjZ7sRGZlo), [Beta Showcase](https://www.youtube.com/watch?v=YIBjy5ZJcq4) | [TU 13](https://github.com/AdrianCassar/Xenia-WebServices/blob/main/patches/545408A7%20-%20Grand%20Theft%20Auto%20V%20(TU13).patch.toml), [TU 10](https://github.com/AdrianCassar/Xenia-WebServices/blob/main/patches/545408A7%20-%20Grand%20Theft%20Auto%20V%20(TU10).patch.toml) |
| GTA V TU 2-13 | Must complete prologue, download gamesave [here](https://cdn.discordapp.com/attachments/641360906495983616/1101132116441440366/545408A7.rar). Unstable and often crashes. | [Solo Session](https://www.youtube.com/watch?v=lap7liW6pco) |
| Guilty Gear 2: Overture | |
| Gundam Operation Troy | [English Patch](https://github.com/Eight-Mansions/MSGOT/releases)
| Halo 3 ODST v13.2 using [Sunrise Server](https://github.com/ahnewark/Sunrise-Halo3-WebServices) | Mousehook | [Head to Head](https://www.youtube.com/watch?v=amS8OxH3exs) | [Halo 3 Patch](https://github.com/AdrianCassar/Xenia-WebServices/blob/main/patches/4D5307E6%20-%20Halo%203.patch.toml)
| Juiced 2 | |
| Kung Fu Panda: SLL | |
| Left 4 Dead | Mousehook | Compatible with GOTY. |
| Left 4 Dead GOTY | Mousehook | |
| Left 4 Dead 2 | Mousehook | |
| Left 4 Dead 2 Demo |
| Marble Blast Ultra | |
| Marvel Ultimate Alliance | |
| Marvel Ultimate Alliance 2 | |
| Portal 2 | Mousehook support |
| Saints Row 2 | [Video 1](https://www.youtube.com/watch?v=YTw84keeWfs), [Video 2](https://www.youtube.com/watch?v=nf7TDOtTEIE) |
| Saints Row the Third / The Full Package | Unplayable due to broken graphics. Requires [Online Pass](https://www.xbox.com/en-GB/games/store/online-pass/BS7JTR0MN356) + license_mask|
| Saints Row IV | Unplayable due to broken graphics. Requires Online Pass + license_mask|
| Team Fortress 2 | Mousehook support |
| MotoGP 14 | Sprint Season only works |
| MotoGP 15 | Sprint Season only works |
| OutRun Online Arcade | | [Race](https://www.youtube.com/watch?v=-UqxjFgGvhk) |
| Portal 2 | Mousehook |
| Resident Evil 5 | | [Chapter 1](https://www.youtube.com/watch?v=SKgnUVairqs) |
| Ridge Racer 6 | |
| Saints Row 2 | | [Co-op](https://www.youtube.com/watch?v=YTw84keeWfs), [Setup Guide](https://www.youtube.com/watch?v=nf7TDOtTEIE) |
| Saints Row the Third / The Full Package | Unplayable due to broken graphics. Requires [Online Pass](https://www.xbox.com/en-GB/games/store/online-pass/BS7JTR0MN356) + license_mask |
| Saints Row IV | Unplayable due to broken graphics. Requires Online Pass + license_mask |
| Screwjumper! | |
| Splinter Cell: Double Agent | |
| Star Wars Battlefront III (Unreleased Game) | Alpha, Mar 17 2008 | [Conquest Taoonie](https://www.youtube.com/watch?v=C54jCqFnCmQ), [MP Event Stream](https://www.youtube.com/watch?v=xSpTmsSvP4s) |
| Team Fortress 2 | Mousehook |
| The Outfit | |
---

### Non-Supported Games

| Game | Description |
|---|---|
| Gears of War 3 | Connects online but cannot play with others. |
| Grand Theft Auto 4 | Connects online but cannot play with others. |
| Minecraft | Requires friend lists to invite friends. |
| Quantum of a Solace | Crashes on start-up. |
| Red Dead Redemption | Connects online but cannot play with others. |
| Saints Row 1 | Unstable to find sessions to join. |
| Forza Motorsport 4 | Connects online but cannot play with others. |
| Grand Theft Auto 4 | Connects online but cannot play with others. |
| Saints Row 1 | Connects online but cannot play with others. |
| Gears of War 3 | Connects online but cannot play with others. |
| Chromehounds | Requires a file from a dedicated Xbox server. |

#### Requires Servers
- Activision Games
Expand All @@ -108,7 +150,7 @@ This is also a fork of [emoose's Xenia build](https://github.com/emoose/xenia) a
| CSGO | |
| CSGO Beta | |
| Left 4 Dead 2 | TU0 |
| Left 4 Dead | TU0 |
| Left 4 Dead | TU0, GOTY |
| Portal 2 | TU0 |
| Team Fortress 2 | TU0 |
| GoldenEye XBLA | Nov 16th 2007, also renamed as 'Aug 25th 2007' |
Expand Down
105 changes: 105 additions & 0 deletions src/xenia/app/emulator_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ DECLARE_bool(d3d12_readback_resolve);

DECLARE_string(api_address);

DECLARE_bool(upnp);

DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.",
"Display");

Expand Down Expand Up @@ -280,6 +282,14 @@ void EmulatorWindow::EmulatorWindowListener::OnKeyDown(ui::KeyEvent& e) {
emulator_window_.OnKeyDown(e);
}

void EmulatorWindow::EmulatorWindowListener::OnMouseDown(ui::MouseEvent& e) {
//emulator_window_.OnMouseDown(e);
}

void EmulatorWindow::EmulatorWindowListener::OnMouseUp(ui::MouseEvent& e) {
//emulator_window_.OnMouseUp(e);
}

void EmulatorWindow::DisplayConfigGameConfigLoadCallback::PostGameConfigLoad() {
emulator_window_.ApplyDisplayConfigForCvars();
}
Expand Down Expand Up @@ -650,6 +660,15 @@ bool EmulatorWindow::Initialize() {
}
main_menu->AddChild(std::move(hid_menu));

// Netplay menu.
auto Netplay_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Netplay");
{
Netplay_menu->AddChild(
MenuItem::Create(MenuItem::Type::kString, "&Status", "",
std::bind(&EmulatorWindow::NetplayStatus, this)));
}
main_menu->AddChild(std::move(Netplay_menu));

// Help menu.
auto help_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Help");
{
Expand Down Expand Up @@ -868,6 +887,40 @@ void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
e.set_handled(true);
}

void EmulatorWindow::OnMouseDown(const ui::MouseEvent& e) {
ToggleFullscreenOnDoubleClick();
}

void EmulatorWindow::OnMouseUp(const ui::MouseEvent& e) {
last_mouse_up = steady_clock::now();
}

void EmulatorWindow::ToggleFullscreenOnDoubleClick() {
// this function tests if user has double clicked.
// if double click was achieved the fullscreen gets toggled
const auto now = steady_clock::now(); // current mouse event time
const int16_t mouse_down_max_threshold = 250;
const int16_t mouse_up_max_threshold = 250;
const int16_t mouse_up_down_max_delta = 100;
// max delta to prevent 'chaining' of double clicks with next mouse events

const auto last_mouse_down_delta = diff_in_ms(now, last_mouse_down);
if (last_mouse_down_delta >= mouse_down_max_threshold) {
last_mouse_down = now;
return;
}

const auto last_mouse_up_delta = diff_in_ms(now, last_mouse_up);
const auto mouse_event_deltas = diff_in_ms(last_mouse_up, last_mouse_down);
if (last_mouse_up_delta >= mouse_up_max_threshold) {
return;
}

if (mouse_event_deltas < mouse_up_down_max_delta) {
ToggleFullscreen();
}
}

void EmulatorWindow::FileDrop(const std::filesystem::path& path) {
if (!emulator_initialized_) {
return;
Expand Down Expand Up @@ -1440,6 +1493,58 @@ bool EmulatorWindow::IsUseNexusForGameBarEnabled() {
#endif
}

void EmulatorWindow::NetplayStatus() {
std::string msg = "";

msg += "API Address: " + cvars::api_address;
msg += "\n";

msg += "XLiveAPI Initialized: " +
xe::string_util::BoolToString(xe::kernel::XLiveAPI::is_active());
msg += "\n";

if (xe::kernel::XLiveAPI::is_initialized() && cvars::upnp) {
if (xe::kernel::XLiveAPI::upnp_handler.is_active()) {
msg += "UPnP: Device found";
} else {
msg += "UPnP: Device search failed";
}

msg += "\n";
} else {
msg += "UPnP: " + xe::string_util::BoolToString(cvars::upnp);
msg += "\n";
}

msg += "Offline Mode: " + xe::string_util::BoolToString(cvars::offline_mode);
msg += "\n";

if (xe::kernel::XLiveAPI::is_initialized()) {
msg += "\n";

if (xe::kernel::XLiveAPI::is_active()) {
msg += "Communication succeeded with api_address: " + cvars::api_address;
} else {
msg += "Communication failed with api_address: " + cvars::api_address;
}
}

msg += "\n\n";

const auto& port_results =
*xe::kernel::XLiveAPI::upnp_handler.port_binding_results();

for (const auto& [protocol, m_port_bindings] : port_results) {
for (const auto& [port, error] : m_port_bindings) {
msg += fmt::format("{} - {}: {}\n", protocol, port, error);
}
}

imgui_drawer_.get()->ClearDialogs();
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_.get(), "Netplay Status",
msg);
}

void EmulatorWindow::DisplayHotKeysConfig() {
std::string msg = "";
std::string msg_passthru = "";
Expand Down
21 changes: 20 additions & 1 deletion src/xenia/app/emulator_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct RecentTitleEntry {

class EmulatorWindow {
public:
using steady_clock = std::chrono::steady_clock; // stdlib steady clock

enum : size_t {
// The UI is on top of the game and is open in special cases, so
// lowest-priority.
Expand All @@ -57,7 +59,17 @@ class EmulatorWindow {
std::unique_ptr<xe::threading::Thread> Gamepad_HotKeys_Listener;

int32_t selected_title_index = -1;


static constexpr int64_t diff_in_ms(
const steady_clock::time_point t1,
const steady_clock::time_point t2) noexcept {
using ms = std::chrono::milliseconds;
return std::chrono::duration_cast<ms>(t1 - t2).count();
}

steady_clock::time_point last_mouse_up = steady_clock::now();
steady_clock::time_point last_mouse_down = steady_clock::now();

Emulator* emulator() const { return emulator_; }
ui::WindowedAppContext& app_context() const { return app_context_; }
ui::Window* window() const { return window_.get(); }
Expand Down Expand Up @@ -131,6 +143,9 @@ class EmulatorWindow {

void OnKeyDown(ui::KeyEvent& e) override;

void OnMouseDown(ui::MouseEvent& e) override;
void OnMouseUp(ui::MouseEvent& e) override;

private:
EmulatorWindow& emulator_window_;
};
Expand Down Expand Up @@ -184,7 +199,10 @@ class EmulatorWindow {
void ApplyDisplayConfigForCvars();

void OnKeyDown(ui::KeyEvent& e);
void OnMouseDown(const ui::MouseEvent& e);
void ToggleFullscreenOnDoubleClick();
void FileDrop(const std::filesystem::path& filename);
void OnMouseUp(const ui::MouseEvent& e);
void FileOpen();
void FileClose();
void InstallContent();
Expand All @@ -209,6 +227,7 @@ class EmulatorWindow {
void ToggleGPUSetting(gpu_cvar index);
bool IsUseNexusForGameBarEnabled();
std::string BoolToString(bool value);
void NetplayStatus();
void DisplayHotKeysConfig();

void RunPreviouslyPlayedTitle();
Expand Down
4 changes: 2 additions & 2 deletions src/xenia/app/xenia_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -483,12 +483,12 @@ void EmulatorApp::OnDestroy() {

#pragma region NetplayCleanup
// UPnP Shutdown

if (cvars::upnp) {
xe::kernel::XLiveAPI::upnp_handler.~upnp();
}

xe::kernel::XLiveAPI::DeleteAllSessions();
// Delete sessions on shutdown.
xe::kernel::XLiveAPI::DeleteAllSessionsByMac();

curl_global_cleanup();
#pragma endregion
Expand Down
1 change: 1 addition & 0 deletions src/xenia/cpu/ppc/testing/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ project("xenia-cpu-ppc-tests")
"imgui",
"xenia-core",
"xenia-cpu",
"xenia-gpu", -- Should probably be removed sometime
"xenia-base",
"xenia-kernel",
"xenia-patcher",
Expand Down
1 change: 1 addition & 0 deletions src/xenia/cpu/testing/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ test_suite("xenia-cpu-tests", project_root, ".", {
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-gpu", -- Should probably be removed sometime

-- TODO(benvanik): cut these dependencies?
"xenia-kernel",
Expand Down
Loading

0 comments on commit 623f2b2

Please sign in to comment.