⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netplay.cpp

📁 著名SFC模拟器Snes9x的源代码。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and *                           Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code  * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and *                           Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#ifdef NETPLAY_SUPPORT#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <memory.h>#include <sys/types.h>#ifndef __WIN32__#include <unistd.h>#include <sys/time.h>#endif#if defined (__WIN32__)#include <winsock.h>#include <process.h>#define ioctl ioctlsocket#define close closesocket#define read(a,b,c) recv(a, b, c, 0)#define write(a,b,c) send(a, b, c, 0)#else#include <netdb.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/param.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef __SVR4#include <sys/stropts.h>#endif#endif#ifdef USE_THREADS#include <pthread.h>#include <sched.h>#include <semaphore.h>#endif#include "snes9x.h"#include "cpuexec.h"#include "netplay.h"#include "memmap.h"#include "snapshot.h"#include "display.h"void S9xNPClientLoop (void *);bool8 S9xNPLoadROM (uint32 len);bool8 S9xNPLoadROMDialog (const char *);bool8 S9xNPGetROMImage (uint32 len);void S9xNPGetSRAMData (uint32 len);void S9xNPGetFreezeFile (uint32 len);unsigned long START = 0;bool8 S9xNPConnectToServer (const char *hostname, int port,                            const char *rom_name){    if (!S9xNPInitialise ())        return (FALSE);    S9xNPDisconnect ();    NetPlay.MySequenceNum = 0;    NetPlay.ServerSequenceNum = 0;    NetPlay.Connected = FALSE;    NetPlay.Abort = FALSE;    NetPlay.Player = 0;    NetPlay.Paused = FALSE;    NetPlay.PercentageComplete = 0;    NetPlay.Socket = 0;    if (NetPlay.ServerHostName)        free ((char *) NetPlay.ServerHostName);    NetPlay.ServerHostName = strdup (hostname);    if (NetPlay.ROMName)        free ((char *) NetPlay.ROMName);    NetPlay.ROMName = strdup (rom_name);    NetPlay.Port = port;    NetPlay.PendingWait4Sync = FALSE;#ifdef __WIN32__    if (GUI.ClientSemaphore == NULL)        GUI.ClientSemaphore = CreateSemaphore (NULL, 0, NP_JOYPAD_HIST_SIZE, NULL);    if (NetPlay.ReplyEvent == NULL)        NetPlay.ReplyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);    _beginthread (S9xNPClientLoop, 0, NULL);#endif    return (TRUE);}bool8 S9xNPConnect (){    struct sockaddr_in address;    struct hostent *hostinfo;    unsigned int addr;        address.sin_family = AF_INET;    address.sin_port = htons (NetPlay.Port);#ifdef NP_DEBUG    printf ("CLIENT: Looking up server's hostname (%s) @%ld\n", NetPlay.ServerHostName, S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Looking up server's hostname...");    if ((int) (addr = inet_addr (NetPlay.ServerHostName)) == -1)    {	if ((hostinfo = gethostbyname (NetPlay.ServerHostName)))	{	    memcpy ((char *)&address.sin_addr, hostinfo->h_addr,		    hostinfo->h_length);	}	else	{            S9xNPSetError ("\Unable to look up server's IP address from hostname.\n\n\Unknown hostname or may be your nameserver isn't set\n\up correctly?");	    return (FALSE);	}    }    else    {	memcpy ((char *)&address.sin_addr, &addr, sizeof (addr));    }#ifdef NP_DEBUG    printf ("CLIENT: Creating socket @%ld\n", S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Creating network socket...");    if ((NetPlay.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0)    {        S9xNPSetError ("Creating network socket failed.");	return (FALSE);    }#ifdef NP_DEBUG    printf ("CLIENT: Trying to connect to server @%ld...\n", S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Trying to connect to Snes9X server...");    if (connect (NetPlay.Socket, (struct sockaddr *) &address, sizeof (address)) < 0)    {        char buf [100];#ifdef __WIN32__        if (WSAGetLastError () == WSAECONNREFUSED)#else	if (errno == ECONNREFUSED)#endif        {            S9xNPSetError ("\Connection to remote server socket refused:\n\n\Is there actually a Snes9X NetPlay server running\n\on the remote machine on this port?");        }        else        {            sprintf (buf, "Connection to server failed with error number %d",#ifdef __WIN32__                     WSAGetLastError ()#else		     errno#endif		     );            S9xNPDisconnect ();        }	return (FALSE);    }    NetPlay.Connected = TRUE;#ifdef NP_DEBUG    printf ("CLIENT: Sending 'HELLO' message @%ld...\n", S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Sending 'HELLO' message...");    /* Send the server a HELLO packet*/    int len = 7 + 4 + strlen (NetPlay.ROMName) + 1;    uint8 *tmp = new uint8 [len];    uint8 *ptr = tmp;    *ptr++ = NP_CLNT_MAGIC;    *ptr++ = NetPlay.MySequenceNum++;    *ptr++ = NP_CLNT_HELLO;    WRITE_LONG (ptr, len);    ptr += 4;#ifdef __WIN32__    uint32 ft = Settings.FrameTime * 1000;    WRITE_LONG (ptr, ft);#else    WRITE_LONG (ptr, Settings.FrameTime);#endif    ptr += 4;    strcpy ((char *) ptr, NetPlay.ROMName);    if (!S9xNPSendData (NetPlay.Socket, tmp, len))    {        S9xNPSetError ("Sending 'HELLO' message failed.");	S9xNPDisconnect ();	delete tmp;	return (FALSE);    }    delete tmp;#ifdef NP_DEBUG    printf ("CLIENT: Waiting for 'WELCOME' reply from server @%ld...\n", S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Waiting for 'HELLO' reply from server...");    uint8 header [7];    if (!S9xNPGetData (NetPlay.Socket, header, 7) ||         header [0] != NP_SERV_MAGIC || header [1] != 0 ||         (header [2] & 0x1f) != NP_SERV_HELLO)    {        S9xNPSetError ("Error in 'HELLO' reply packet received from server.");	S9xNPDisconnect ();	return (FALSE);    }#ifdef NP_DEBUG    printf ("CLIENT: Got 'WELCOME' reply @%ld\n", S9xGetMilliTime () - START);#endif    len = READ_LONG (&header [3]);    if (len > 256)    {        S9xNPSetError ("Error in 'HELLO' reply packet received from server.");	S9xNPDisconnect ();	return (FALSE);    }    uint8 *data = new uint8 [len];    if (!S9xNPGetData (NetPlay.Socket, data, len - 7))    {        S9xNPSetError ("Error in 'HELLO' reply packet received from server.");        delete data;	S9xNPDisconnect ();	return (FALSE);    }    if (data [0] != NP_VERSION)    {        S9xNPSetError ("\The Snes9X NetPlay server implements a different\n\version of the protocol. Disconnecting.");        delete data;	S9xNPDisconnect ();        return (FALSE);    }    NetPlay.FrameCount = READ_LONG (&data [2]);    if (!(header [2] & 0x80) &&        strcmp ((char *) data + 4 + 2, NetPlay.ROMName) != 0)    {        if (!S9xNPLoadROMDialog ((char *) data + 4 + 2))        {            delete data;            S9xNPDisconnect ();            return (FALSE);        }    }    NetPlay.Player = data [1];    delete data;    NetPlay.PendingWait4Sync = TRUE;    Settings.NetPlay = TRUE;    S9xNPResetJoypadReadPos ();    NetPlay.ServerSequenceNum = 1;    #ifdef NP_DEBUG    printf ("CLIENT: Sending 'READY' to server @%ld...\n", S9xGetMilliTime () - START);#endif    S9xNPSetAction ("Sending 'READY' to the server...");    return (S9xNPSendReady ((header [2] & 0x80) ?                             NP_CLNT_WAITING_FOR_ROM_IMAGE :                             NP_CLNT_READY));}bool8 S9xNPSendReady (uint8 op){    uint8 ready [7];    uint8 *ptr = ready;    *ptr++ = NP_CLNT_MAGIC;    *ptr++ = NetPlay.MySequenceNum++;    *ptr++ = op;    WRITE_LONG (ptr, 7);    ptr += 4;    if (!S9xNPSendData (NetPlay.Socket, ready, 7))    {	S9xNPDisconnect ();        S9xNPSetError ("Sending 'READY' message failed.");	return (FALSE);    }    return (TRUE);}bool8 S9xNPSendPause (bool8 paused){#ifdef NP_DEBUG    printf ("CLIENT: Pause - %s @%ld\n", paused ? "YES" : "NO", S9xGetMilliTime () - START);#endif    uint8 pause [7];    uint8 *ptr = pause;    *ptr++ = NP_CLNT_MAGIC;    *ptr++ = NetPlay.MySequenceNum++;    *ptr++ = NP_CLNT_PAUSE | (paused ? 0x80 : 0);    WRITE_LONG (ptr, 7);    ptr += 4;    if (!S9xNPSendData (NetPlay.Socket, pause, 7))    {        S9xNPSetError ("Sending 'PAUSE' message failed.");	S9xNPDisconnect ();	return (FALSE);    }    return (TRUE);}#ifdef __WIN32__void S9xNPClientLoop (void *){    NetPlay.Waiting4EmulationThread = FALSE;    if (S9xNPConnect ())    {        S9xClearPause (PAUSE_NETPLAY_CONNECT);        while (NetPlay.Connected)        {            if (S9xNPWaitForHeartBeat ())            {                LONG prev;                if (!ReleaseSemaphore (GUI.ClientSemaphore, 1, &prev))                {#ifdef NP_DEBUG                    printf ("CLIENT: ReleaseSemaphore failed - already hit max count (%d) %ld\n", NP_JOYPAD_HIST_SIZE, S9xGetMilliTime () - START);#endif                    S9xNPSetWarning ("NetPlay: Client may be out of sync with server.");                }                else                {                    if (!NetPlay.Waiting4EmulationThread &&                         prev == (int) NetPlay.MaxBehindFrameCount)                    {                        NetPlay.Waiting4EmulationThread = TRUE;                        S9xNPSendPause (TRUE);                    }                }            }            else                S9xNPDisconnect ();        }    }    else    {        S9xClearPause (PAUSE_NETPLAY_CONNECT);    }#ifdef NP_DEBUG    printf ("CLIENT: Client thread exiting @%ld\n", S9xGetMilliTime () - START);#endif}#endifbool8 S9xNPWaitForHeartBeat (){    uint8 header [3 + 4 + 4 * 5];    while (S9xNPGetData (NetPlay.Socket, header, 3 + 4))    {        if (header [0] != NP_SERV_MAGIC)        {            S9xNPSetError ("Bad magic value from server while waiting for heart-beat message\n");            S9xNPDisconnect ();            return (FALSE);        }        if (header [1] != NetPlay.ServerSequenceNum)        {            char buf [200];            sprintf (buf, "Unexpected message sequence number from server, expected %d, got %d\n", NetPlay.ServerSequenceNum, header [1]);            S9xNPSetWarning (buf);            NetPlay.ServerSequenceNum = header [1] + 1;        }        else            NetPlay.ServerSequenceNum++;                if ((header [2] & 0x1f) == NP_SERV_JOYPAD)        {            // Top 2 bits + 1 of opcode is joypad data count.            int num = (header [2] >> 6) + 1;            if (num)            {                if (!S9xNPGetData (NetPlay.Socket, header + 3 + 4, num * 4))                {                    S9xNPSetError ("Error while receiving 'JOYPAD' message.");                    S9xNPDisconnect ();                    return (FALSE);                }            }            NetPlay.Frame [NetPlay.JoypadWriteInd] = READ_LONG (&header [3]);            for (int i = 0; i < num; i++)            {                NetPlay.Joypads [NetPlay.JoypadWriteInd][i] =                     READ_LONG (&header [3 + 4 + i * sizeof (uint32)]);            }            NetPlay.Paused = (header [2] & 0x20) != 0;            NetPlay.JoypadWriteInd = (NetPlay.JoypadWriteInd + 1) % NP_JOYPAD_HIST_SIZE;                        if (NetPlay.JoypadWriteInd != (NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE)            {                //printf ("(%d)", (NetPlay.JoypadWriteInd - NetPlay.JoypadReadInd) % NP_JOYPAD_HIST_SIZE); fflush (stdout);            }//printf ("CLIENT: HB: @%d\n", S9xGetMilliTime () - START);            return (TRUE);        }        else        {            uint32 len = READ_LONG (&header [3]);	    switch (header [2] & 0x1f)	    {	    case NP_SERV_RESET:#ifdef NP_DEBUG                printf ("CLIENT: RESET received @%ld\n", S9xGetMilliTime () - START);#endif                S9xNPDiscardHeartbeats ();		S9xReset ();                NetPlay.FrameCount = READ_LONG (&header [3]);                S9xNPResetJoypadReadPos ();                S9xNPSendReady ();                break;	    case NP_SERV_PAUSE:                NetPlay.Paused = (header [2] & 0x20) != 0;                break;            case NP_SERV_LOAD_ROM:#ifdef NP_DEBUG                printf ("CLIENT: LOAD_ROM received @%ld\n", S9xGetMilliTime () - START);#endif                S9xNPDiscardHeartbeats ();                if (S9xNPLoadROM (len - 7))                    S9xNPSendReady (NP_CLNT_LOADED_ROM);                break;            case NP_SERV_ROM_IMAGE:#ifdef NP_DEBUG                printf ("CLIENT: ROM_IMAGE received @%ld\n", S9xGetMilliTime () - START);#endif                S9xNPDiscardHeartbeats ();                if (S9xNPGetROMImage (len - 7))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -