snes9x/gtk/src/gtk_netplay.cpp

315 lines
7.0 KiB
C++
Raw Normal View History

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
2010-09-25 17:46:12 +02:00
#include <glib.h>
#include "gtk_s9x.h"
#include "gtk_netplay_dialog.h"
#include "gtk_netplay.h"
#include "gtk_sound.h"
#include "snes9x.h"
#include "memmap.h"
#include "netplay.h"
#include "cpuexec.h"
#include "display.h"
#include "ppu.h"
2010-09-25 17:46:12 +02:00
uint16 MovieGetJoypad(int i);
void MovieSetJoypad(int i, uint16 buttons);
2010-09-25 17:46:12 +02:00
static uint32 local_joypads[8], joypads[8];
static GThread *npthread;
extern SNPServer NPServer;
static void S9xNetplayPreconnect()
2010-09-25 17:46:12 +02:00
{
S9xNetplayDisconnect();
2010-09-25 17:46:12 +02:00
if (gui_config->rom_loaded)
{
S9xAutoSaveSRAM();
2010-09-25 17:46:12 +02:00
}
NetPlay.MaxBehindFrameCount = gui_config->netplay_max_frame_loss;
NetPlay.Waiting4EmulationThread = false;
2010-09-25 17:46:12 +02:00
}
static void S9xNetplayConnect()
2010-09-25 17:46:12 +02:00
{
GtkWidget *msg;
S9xNetplayPreconnect();
2010-09-25 17:46:12 +02:00
uint32 flags = CPU.Flags;
if (!gui_config->netplay_last_rom.empty() &&
!top_level->try_open_rom(gui_config->netplay_last_rom))
2010-09-25 17:46:12 +02:00
{
return;
}
if (!S9xNPConnectToServer(gui_config->netplay_last_host.c_str(),
gui_config->netplay_last_port,
Memory.ROMName))
2010-09-25 17:46:12 +02:00
{
msg = gtk_message_dialog_new(NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Couldn't connect to server: %s:%d",
gui_config->netplay_last_host.c_str(),
gui_config->netplay_last_port);
gtk_window_set_title(GTK_WINDOW(msg), _("Connection Error"));
gtk_dialog_run(GTK_DIALOG(msg));
gtk_widget_destroy(msg);
2010-09-25 17:46:12 +02:00
}
gui_config->netplay_activated = true;
2010-09-25 17:46:12 +02:00
/* If no rom is specified, assume we'll get it from the server */
if (gui_config->netplay_last_rom.empty())
2010-09-25 17:46:12 +02:00
{
Settings.StopEmulation = false;
S9xROMLoaded();
2010-09-25 17:46:12 +02:00
}
S9xReset();
2010-09-25 17:46:12 +02:00
CPU.Flags = flags;
top_level->configure_widgets();
2010-09-25 17:46:12 +02:00
}
void S9xNetplaySyncClients()
2010-09-25 17:46:12 +02:00
{
if (Settings.NetPlay && Settings.NetPlayServer)
S9xNPServerQueueSyncAll();
2010-09-25 17:46:12 +02:00
}
void S9xNetplayStopServer()
2010-09-25 17:46:12 +02:00
{
S9xNPStopServer();
2010-09-25 17:46:12 +02:00
g_thread_join(npthread);
Settings.NetPlayServer = false;
gui_config->netplay_server_up = false;
2010-09-25 17:46:12 +02:00
}
void S9xNetplayDisconnect()
2010-09-25 17:46:12 +02:00
{
if (Settings.NetPlay)
{
if (NetPlay.Connected)
S9xNPDisconnect();
2010-09-25 17:46:12 +02:00
}
if (gui_config->netplay_server_up)
{
S9xNetplayStopServer();
2010-09-25 17:46:12 +02:00
}
gui_config->netplay_activated = false;
NetPlay.Paused = false;
2010-09-25 17:46:12 +02:00
top_level->configure_widgets();
2010-09-25 17:46:12 +02:00
}
static gpointer S9xNetplayServerThread(gpointer)
2010-09-25 17:46:12 +02:00
{
S9xNPStartServer(gui_config->netplay_default_port);
2010-09-25 17:46:12 +02:00
return NULL;
}
void S9xNetplayStartServer()
2010-09-25 17:46:12 +02:00
{
uint32 flags;
S9xNetplayPreconnect();
2010-09-25 17:46:12 +02:00
flags = CPU.Flags;
if (gui_config->netplay_last_rom.empty() ||
!top_level->try_open_rom(gui_config->netplay_last_rom))
2010-09-25 17:46:12 +02:00
{
return;
}
Settings.NetPlayServer = true;
2010-09-25 17:46:12 +02:00
NPServer.SyncByReset = gui_config->netplay_sync_reset;
NPServer.SendROMImageOnConnect = gui_config->netplay_send_rom;
npthread = g_thread_new(NULL, S9xNetplayServerThread, NULL);
2010-09-25 17:46:12 +02:00
/* Sleep to let the server create itself */
usleep(10000);
2010-09-25 17:46:12 +02:00
S9xNPConnectToServer("127.0.0.1",
gui_config->netplay_default_port,
Memory.ROMName);
2010-09-25 17:46:12 +02:00
S9xReset();
2010-09-25 17:46:12 +02:00
S9xROMLoaded();
2010-09-25 17:46:12 +02:00
gui_config->netplay_activated = true;
gui_config->netplay_server_up = true;
2010-09-25 17:46:12 +02:00
CPU.Flags = flags;
top_level->configure_widgets();
2010-09-25 17:46:12 +02:00
}
void S9xNetplayDialogOpen()
2010-09-25 17:46:12 +02:00
{
Snes9xNetplayDialog *np_dialog;
top_level->pause_from_focus_change();
2010-09-25 17:46:12 +02:00
np_dialog = new Snes9xNetplayDialog(gui_config);
2010-09-25 17:46:12 +02:00
gtk_window_set_transient_for(np_dialog->get_window(),
top_level->get_window());
2010-09-25 17:46:12 +02:00
if (np_dialog->show())
2010-09-25 17:46:12 +02:00
{
if (!gui_config->netplay_is_server)
{
S9xNetplayConnect();
2010-09-25 17:46:12 +02:00
}
else
{
S9xNetplayStartServer();
2010-09-25 17:46:12 +02:00
}
S9xSoundStart();
2010-09-25 17:46:12 +02:00
}
delete np_dialog;
top_level->unpause_from_focus_change();
2010-09-25 17:46:12 +02:00
}
int S9xNetplaySyncSpeed()
2010-09-25 17:46:12 +02:00
{
if (!Settings.NetPlay || !NetPlay.Connected)
return 0;
// Send 1st joypad's position update to server
S9xNPSendJoypadUpdate(local_joypads[0]);
2010-09-25 17:46:12 +02:00
// set input from network
for (int i = 0; i < NP_MAX_CLIENTS; i++)
joypads[i] = S9xNPGetJoypad(i);
2010-09-25 17:46:12 +02:00
if (!S9xNPCheckForHeartBeat())
2010-09-25 17:46:12 +02:00
{
// No heartbeats already arrived, have to wait for one.
NetPlay.PendingWait4Sync = !S9xNPWaitForHeartBeatDelay(100);
2010-09-25 17:46:12 +02:00
IPPU.RenderThisFrame = true;
2010-09-25 17:46:12 +02:00
IPPU.SkippedFrames = 0;
}
else
{
int difference = (int)(NetPlay.MySequenceNum) -
(int)(NetPlay.ServerSequenceNum);
2010-09-25 17:46:12 +02:00
if (difference < 0)
difference += 256;
if (NetPlay.Waiting4EmulationThread)
{
if ((unsigned int)difference <= (NetPlay.MaxBehindFrameCount / 2))
2010-09-25 17:46:12 +02:00
{
NetPlay.Waiting4EmulationThread = false;
S9xNPSendPause(false);
2010-09-25 17:46:12 +02:00
}
}
else
{
if ((unsigned int)difference >= (NetPlay.MaxBehindFrameCount))
2010-09-25 17:46:12 +02:00
{
NetPlay.Waiting4EmulationThread = true;
S9xNPSendPause(true);
2010-09-25 17:46:12 +02:00
}
}
NetPlay.PendingWait4Sync = !S9xNPWaitForHeartBeatDelay(200);
2010-09-25 17:46:12 +02:00
if (IPPU.SkippedFrames < NetPlay.MaxFrameSkip)
{
IPPU.SkippedFrames++;
IPPU.RenderThisFrame = false;
2010-09-25 17:46:12 +02:00
}
else
{
IPPU.RenderThisFrame = true;
2010-09-25 17:46:12 +02:00
IPPU.SkippedFrames = 0;
}
}
if (!NetPlay.PendingWait4Sync)
{
NetPlay.FrameCount++;
S9xNPStepJoypadHistory();
2010-09-25 17:46:12 +02:00
}
return 1;
}
int S9xNetplayPush()
2010-09-25 17:46:12 +02:00
{
if (gui_config->netplay_activated &&
(!Settings.NetPlay || !NetPlay.Connected))
S9xNetplayDisconnect();
2010-09-25 17:46:12 +02:00
if (!Settings.NetPlay)
return 0;
if (NetPlay.PendingWait4Sync && !S9xNPWaitForHeartBeatDelay(100))
2010-09-25 17:46:12 +02:00
{
S9xProcessEvents(false);
2010-09-25 17:46:12 +02:00
S9xSoundStop();
NetPlay.Paused = true;
2010-09-25 17:46:12 +02:00
return 1;
}
NetPlay.Paused = false;
2010-09-25 17:46:12 +02:00
S9xSoundStart();
2010-09-25 17:46:12 +02:00
/* Save the joypad input */
for (int i = 0; i < 8; i++)
{
local_joypads[i] = MovieGetJoypad(i);
2010-09-25 17:46:12 +02:00
MovieSetJoypad(i, joypads[i]);
2010-09-25 17:46:12 +02:00
}
if (NetPlay.PendingWait4Sync)
{
NetPlay.PendingWait4Sync = false;
2010-09-25 17:46:12 +02:00
NetPlay.FrameCount++;
S9xNPStepJoypadHistory();
2010-09-25 17:46:12 +02:00
}
return 0;
}
void S9xNetplayPop()
2010-09-25 17:46:12 +02:00
{
if (!Settings.NetPlay)
return;
for (int i = 0; i < 8; i++)
MovieSetJoypad(i, local_joypads[i]);
2010-09-25 17:46:12 +02:00
}