mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-09 01:59:49 -10:00
269 lines
10 KiB
C++
269 lines
10 KiB
C++
/*
|
|
Copyright 2025 flyinghead
|
|
|
|
This file is part of Flycast.
|
|
|
|
Flycast is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Flycast is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "settings.h"
|
|
#include "gui.h"
|
|
#include "network/ggpo.h"
|
|
#include "network/ice.h"
|
|
#include "imgui_stdlib.h"
|
|
|
|
void gui_settings_network()
|
|
{
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
header(T("Network Type"));
|
|
{
|
|
DisabledScope scope(game_started);
|
|
|
|
int netType = 0;
|
|
if (config::GGPOEnable)
|
|
netType = 1;
|
|
else if (config::NetworkEnable)
|
|
netType = 2;
|
|
else if (config::BattleCableEnable)
|
|
netType = 3;
|
|
ImGui::Columns(4, "networkType", false);
|
|
ImGui::RadioButton(T("Native"), &netType, 0);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Use native Dreamcast online features using the modem or Broadband Adapter"));
|
|
ImGui::NextColumn();
|
|
ImGui::RadioButton("GGPO", &netType, 1);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Enable networking using GGPO"));
|
|
ImGui::NextColumn();
|
|
ImGui::RadioButton("Naomi", &netType, 2);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Enable networking for supported Naomi and Atomiswave games"));
|
|
ImGui::NextColumn();
|
|
ImGui::RadioButton(T("Battle Cable"), &netType, 3);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Emulate the Taisen (Battle) null modem cable for games that support it"));
|
|
ImGui::Columns(1, nullptr, false);
|
|
|
|
config::GGPOEnable = false;
|
|
config::NetworkEnable = false;
|
|
config::BattleCableEnable = false;
|
|
switch (netType) {
|
|
case 1:
|
|
config::GGPOEnable = true;
|
|
break;
|
|
case 2:
|
|
config::NetworkEnable = true;
|
|
break;
|
|
case 3:
|
|
config::BattleCableEnable = true;
|
|
break;
|
|
}
|
|
}
|
|
if (config::GGPOEnable || config::NetworkEnable || config::BattleCableEnable) {
|
|
ImGui::Spacing();
|
|
header(T("Configuration"));
|
|
}
|
|
{
|
|
if (config::GGPOEnable)
|
|
{
|
|
config::NetworkEnable = false;
|
|
OptionCheckbox(T("Play as Player 1"), config::ActAsServer,
|
|
T("Deselect to play as player 2"));
|
|
InputText(T("Peer"), &config::NetworkServer.get(), ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CallbackCharFilter, dnsCharFilter);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("Your peer IP address and optional port"));
|
|
OptionSlider(T("Frame Delay"), config::GGPODelay, 0, 20,
|
|
T("Sets Frame Delay, advisable for sessions with ping >100 ms"));
|
|
|
|
ImGui::Text("%s", T("Left Thumbstick:"));
|
|
OptionRadioButton<int>((Ts("Disabled") + "##analogaxis").c_str(), config::GGPOAnalogAxes, 0, T("Left thumbstick not used"));
|
|
ImGui::SameLine();
|
|
OptionRadioButton<int>(T("Horizontal"), config::GGPOAnalogAxes, 1, T("Use the left thumbstick horizontal axis only"));
|
|
ImGui::SameLine();
|
|
OptionRadioButton<int>(T("Full"), config::GGPOAnalogAxes, 2, T("Use the left thumbstick horizontal and vertical axes"));
|
|
|
|
OptionCheckbox(T("Enable Chat"), config::GGPOChat, T("Open the chat window when a chat message is received"));
|
|
if (config::GGPOChat)
|
|
{
|
|
OptionCheckbox(T("Enable Chat Window Timeout"), config::GGPOChatTimeoutToggle, T("Automatically close chat window after 20 seconds"));
|
|
if (config::GGPOChatTimeoutToggle)
|
|
{
|
|
char chatTimeout[256];
|
|
snprintf(chatTimeout, sizeof(chatTimeout), "%d", (int)config::GGPOChatTimeout);
|
|
InputText(T("Chat Window Timeout (seconds)"), chatTimeout, sizeof(chatTimeout), ImGuiInputTextFlags_CharsDecimal);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("Sets duration that chat window stays open after new message is received."));
|
|
config::GGPOChatTimeout.set(atoi(chatTimeout));
|
|
}
|
|
}
|
|
OptionCheckbox(T("Network Statistics"), config::NetworkStats,
|
|
T("Display network statistics on screen"));
|
|
}
|
|
else if (config::NetworkEnable)
|
|
{
|
|
// Naomi networking
|
|
ImGui::Text("%s", T("Network Role"));
|
|
int role = 0;
|
|
if (!config::ActAsServer)
|
|
role = config::NaomiSatellite ? 2 : 1;
|
|
ImGui::Columns(3, "networkRole", false);
|
|
ImGui::RadioButton(T("Master"), &role, 0);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Create a local server for Naomi network games"));
|
|
ImGui::NextColumn();
|
|
ImGui::RadioButton(T("Slave"), &role, 1);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Connect to the master server"));
|
|
ImGui::NextColumn();
|
|
ImGui::RadioButton(T("Satellite"), &role, 2);
|
|
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
|
ShowHelpMarker(T("Live monitor for games that support it (Virtual-On Oratorio Tangram and Club Kart)"));
|
|
ImGui::Columns(1, nullptr, false);
|
|
|
|
if (!config::ActAsServer)
|
|
{
|
|
InputText(T("Server"), &config::NetworkServer.get(), ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CallbackCharFilter, dnsCharFilter);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("The server to connect to. Leave blank to find a server automatically on the default port"));
|
|
}
|
|
char localPort[256];
|
|
snprintf(localPort, sizeof(localPort), "%d", (int)config::LocalPort);
|
|
InputText(T("Local Port"), localPort, sizeof(localPort), ImGuiInputTextFlags_CharsDecimal);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("The local UDP port to use"));
|
|
config::LocalPort.set(atoi(localPort));
|
|
|
|
switch (role) {
|
|
case 0:
|
|
config::ActAsServer = true;
|
|
config::NaomiSatellite = false;
|
|
break;
|
|
case 1:
|
|
config::ActAsServer = false;
|
|
config::NaomiSatellite = false;
|
|
break;
|
|
case 2:
|
|
config::ActAsServer = false;
|
|
config::NaomiSatellite = true;
|
|
break;
|
|
}
|
|
}
|
|
else if (config::BattleCableEnable)
|
|
{
|
|
#if defined(USE_ICE) && defined(USE_WEBSOCKET)
|
|
if (ImGui::BeginTabBar("battleMode", ImGuiTabBarFlags_NoTooltip))
|
|
{
|
|
if (ImGui::BeginTabItem(T("Match Code")))
|
|
{
|
|
ice::State state = ice::getState();
|
|
ImGuiInputTextFlags textFlags = state == ice::Offline ? ImGuiInputTextFlags_CharsNoBlank : ImGuiInputTextFlags_ReadOnly;
|
|
static std::string matchCode;
|
|
InputText(T("Code"), &matchCode, textFlags);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("Choose a unique word or number and share it with your opponent."));
|
|
if (state == ice::Offline) {
|
|
if (ImGui::Button(T("Connect")) && !matchCode.empty())
|
|
ice::init(matchCode, true);
|
|
}
|
|
else {
|
|
if (ImGui::Button(T("Disconnect")))
|
|
try { ice::term(); } catch (...) {}
|
|
}
|
|
std::string status;
|
|
switch (state)
|
|
{
|
|
case ice::Offline:
|
|
status = ice::getStatusText();
|
|
break;
|
|
case ice::Online:
|
|
status = T("Waiting at meeting point...");
|
|
break;
|
|
case ice::ChalAccepted:
|
|
status = T("Preparing game...");
|
|
break;
|
|
case ice::Playing:
|
|
status = strprintf(T("Playing %s (%s)"), matchCode.c_str(), ice::getStatusText().c_str());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ImGui::TextDisabled("%s", status.c_str());
|
|
OptionCheckbox(T("Network Statistics"), config::NetworkStats,
|
|
T("Display network statistics on screen"));
|
|
ImGui::EndTabItem();
|
|
}
|
|
if (ImGui::BeginTabItem(T("Manual")))
|
|
{
|
|
#endif
|
|
InputText(T("Peer"), &config::NetworkServer.get(), ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CallbackCharFilter, dnsCharFilter);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("The peer to connect to. Leave blank to find a player automatically on the default port"));
|
|
char localPort[256];
|
|
snprintf(localPort, sizeof(localPort), "%d", (int)config::LocalPort);
|
|
InputText(T("Local Port"), localPort, sizeof(localPort), ImGuiInputTextFlags_CharsDecimal);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("The local UDP port to use"));
|
|
config::LocalPort.set(atoi(localPort));
|
|
#if defined(USE_ICE) && defined(USE_WEBSOCKET)
|
|
ImGui::EndTabItem();
|
|
}
|
|
ImGui::EndTabBar();
|
|
}
|
|
#endif
|
|
OptionCheckbox(T("Act as Master"), config::ActAsServer,
|
|
T("Only used for Maximum Speed. One of the peer must be master."));
|
|
}
|
|
}
|
|
ImGui::Spacing();
|
|
header(T("Network Options"));
|
|
{
|
|
OptionCheckbox(T("Enable UPnP"), config::EnableUPnP, T("Automatically configure your network router for netplay"));
|
|
OptionCheckbox(T("Broadcast Digital Outputs"), config::NetworkOutput, T("Broadcast digital outputs and force-feedback state on TCP port 8000. "
|
|
"Compatible with the \"-output network\" MAME option. Arcade games only."));
|
|
{
|
|
DisabledScope scope(game_started);
|
|
|
|
OptionCheckbox(T("Broadband Adapter Emulation"), config::EmulateBBA,
|
|
T("Emulate the Ethernet Broadband Adapter (BBA) instead of the Modem"));
|
|
}
|
|
OptionCheckbox(T("Use DCNet"), config::UseDCNet, T("Use the DCNet cloud service for Dreamcast Internet access."));
|
|
|
|
std::string& ispUsername = config::ISPUsername;
|
|
InputText(T("ISP User Name"), &ispUsername, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CallbackCharFilter,
|
|
[](ImGuiInputTextCallbackData *data) { return static_cast<int>(data->EventChar <= ' ' || data->EventChar > '~'); });
|
|
// CallbackCharFilter isn't called on switch
|
|
auto it = std::remove_if(ispUsername.begin(), ispUsername.end(), [](char c) { return c <= ' ' || c > '~'; });
|
|
ispUsername.erase(it, ispUsername.end());
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("The ISP user name stored in the console Flash RAM. Used by some online games as the player name. Leave blank to keep the current Flash RAM value."));
|
|
#if !defined(NDEBUG) || defined(DEBUGFAST)
|
|
{
|
|
DisabledScope scope(config::UseDCNet);
|
|
InputText("DNS", &config::DNS.get(), ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CallbackCharFilter, dnsCharFilter);
|
|
ImGui::SameLine();
|
|
ShowHelpMarker(T("DNS server name or IP address"));
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef NAOMI_MULTIBOARD
|
|
ImGui::Spacing();
|
|
header(T("Multiboard Screens"));
|
|
{
|
|
OptionRadioButton<int>(T("1 (Twin, Satellite)"), config::MultiboardSlaves, 1, T("One screen configuration (F355 Twin, Derby Owners Club satellite)"));
|
|
ImGui::SameLine();
|
|
OptionRadioButton<int>(T("2+ (Deluxe, Main screen)"), config::MultiboardSlaves, 2,
|
|
T("Two or three screens configuration (Airline Pilot, Derby Owners Club main screen, F355 Deluxe, Sega Strike Fighter)"));
|
|
}
|
|
#endif
|
|
}
|