Logo Search packages:      
Sourcecode: fceux version File versions  Download package

netplay.cpp

/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
*  Copyright (C) 2002 Xodnizel
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h> //mbg merge 7/17/06 removed

#include <zlib.h>

#include "types.h"
#include "file.h"
#include "utils/endian.h"
#include "netplay.h"
#include "fceu.h"
#include "state.h"
#include "cheat.h"
#include "input.h"
#include "driver.h"

int FCEUnetplay=0;

static uint8 netjoy[4]; // Controller cache.
static int numlocal;
static int netdivisor;
static int netdcount;

//NetError should only be called after a FCEUD_*Data function returned 0, in the function
//that called FCEUD_*Data, to prevent it from being called twice.

static void NetError(void)
{
      FCEU_DispMessage("Network error/connection lost!");
      FCEUD_NetworkClose();
}

void FCEUI_NetplayStop(void)
{
      if(FCEUnetplay)
      {
            FCEUnetplay = 0;
            FCEU_FlushGameCheats(0,1);  //Don't save netplay cheats.
            FCEU_LoadGameCheats(0);    //Reload our original cheats.
      }
      else puts("Check your code!");
}

int FCEUI_NetplayStart(int nlocal, int divisor)
{
      FCEU_FlushGameCheats(0, 0);  //Save our pre-netplay cheats.
      FCEU_LoadGameCheats(0);    // Load them again, for pre-multiplayer action.
      
      FCEUnetplay = 1;
      memset(netjoy,0,sizeof(netjoy));
      numlocal = nlocal;
      netdivisor = divisor;
      netdcount = 0;
      return(1);
}

int FCEUNET_SendCommand(uint8 cmd, uint32 len)
{
      //mbg merge 7/17/06 changed to alloca
      //uint8 buf[numlocal + 1 + 4];
      uint8 *buf = (uint8*)alloca(numlocal+1+4);


      buf[0] = 0xFF;
      FCEU_en32lsb(&buf[numlocal], len);
      buf[numlocal + 4] = cmd;
      if(!FCEUD_SendData(buf,numlocal + 1 + 4)) 
      {
            NetError();
            return(0);
      }
      return(1);
}

void FCEUI_NetplayText(uint8 *text)
{
      uint32 len;

      len = strlen((char*)text); //mbg merge 7/17/06 added cast

      if(!FCEUNET_SendCommand(FCEUNPCMD_TEXT,len)) return;

      if(!FCEUD_SendData(text,len))
            NetError();
}

int FCEUNET_SendFile(uint8 cmd, char *fn)
{
      uint32 len;
      uLongf clen;
      char *buf, *cbuf;
      FILE *fp;
      struct stat sb;

      if(!(fp=FCEUD_UTF8fopen(fn,"rb"))) return(0);

      fstat(fileno(fp),&sb);
      len = sb.st_size;
      buf = (char*)malloc(len); //mbg merge 7/17/06 added cast
      fread(buf, 1, len, fp);
      fclose(fp);

      cbuf = (char*)malloc(4 + len + len / 1000 + 12); //mbg merge 7/17/06 added cast
      FCEU_en32lsb((uint8*)cbuf, len); //mbg merge 7/17/06 added cast
      compress2((uint8*)cbuf + 4, &clen, (uint8*)buf, len, 7); //mbg merge 7/17/06 added casts
      free(buf);

      //printf("Sending file: %s, %d, %d\n",fn,len,clen);

      len = clen + 4;

      if(!FCEUNET_SendCommand(cmd,len))
      {
            free(cbuf);
            return(0);
      }
      if(!FCEUD_SendData(cbuf, len))
      {
            NetError();
            free(cbuf);
            return(0);
      }
      free(cbuf);

      return(1);
}

static FILE *FetchFile(uint32 remlen)
{
      uint32 clen = remlen;
      char *cbuf;
      uLongf len;
      char *buf;  
      FILE *fp;

      if(clen > 500000)  // Sanity check
      {
            NetError();
            return(0);
      }

      //printf("Receiving file: %d...\n",clen);
      if(fp = tmpfile())
      {
            cbuf = (char *)malloc(clen); //mbg merge 7/17/06 added cast
            if(!FCEUD_RecvData(cbuf, clen))
            {
                  NetError();
                  fclose(fp);
                  free(cbuf);
                  return(0);
            }

            len = FCEU_de32lsb((uint8*)cbuf); //mbg merge 7/17/06 added cast
            if(len > 500000)    // Another sanity check
            {
                  NetError();
                  fclose(fp);
                  free(cbuf);
                  return(0);
            }
            buf = (char *)malloc(len); //mbg merge 7/17/06 added cast
            uncompress((uint8*)buf, &len, (uint8*)cbuf + 4, clen - 4); //mbg merge 7/17/06 added casts

            fwrite(buf, 1, len, fp);
            free(buf);
            fseek(fp, 0, SEEK_SET);
            return(fp);
      }
      return(0);
}

void NetplayUpdate(uint8 *joyp)
{
      static uint8 buf[5];  /* 4 play states, + command/extra byte */
      static uint8 joypb[4];

      memcpy(joypb,joyp,4);

      /* This shouldn't happen, but just in case.  0xFF is used as a command escape elsewhere. */
      if(joypb[0] == 0xFF) 
            joypb[0] = 0xF;
      if(!netdcount)
            if(!FCEUD_SendData(joypb,numlocal))
            {
                  NetError();
                  return;
            }

      if(!netdcount)
      {
            do
            {
                  if(!FCEUD_RecvData(buf,5))
                  {
                        NetError();
                        return;
                  }

                  switch(buf[4])
                  {
                  default: FCEU_DoSimpleCommand(buf[4]);break;
                  case FCEUNPCMD_TEXT:
                        {
                              uint8 *tbuf;
                              uint32 len = FCEU_de32lsb(buf);

                              if(len > 100000)  // Insanity check!
                              {
                                    NetError();
                                    return;
                              }
                              tbuf = (uint8*)malloc(len + 1); //mbg merge 7/17/06 added cast
                              tbuf[len] = 0;
                              if(!FCEUD_RecvData(tbuf, len))
                              {
                                    NetError();
                                    free(tbuf);
                                    return;
                              }
                              FCEUD_NetplayText(tbuf);
                              free(tbuf);
                        }
                        break;
                  case FCEUNPCMD_SAVESTATE:     
                        {
                              //mbg todo netplay
                              //char *fn;
                              //FILE *fp;

                              ////Send the cheats first, then the save state, since
                              ////there might be a frame or two in between the two sendfile
                              ////commands on the server side.

                              //fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());

                              ////why??????
                              ////if(!
                              //    FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn);
                              //// {
                              ////  free(fn);
                              ////  return;
                              //// }

                              //free(fn);
                              //if(!FCEUnetplay) return;

                              //fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str());
                              //fp = fopen(fn, "wb");
                              //if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION))
                              //{
                              //    fclose(fp);
                              //    if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn))
                              //    {
                              //          unlink(fn);
                              //          free(fn);
                              //          return;
                              //    }
                              //    unlink(fn);
                              //    free(fn);
                              //}
                              //else
                              //{
                              //    fclose(fp);
                              //    FCEUD_PrintError("File error.  (K)ill, (M)aim, (D)estroy?  Now!");
                              //    unlink(fn);
                              //    free(fn);
                              //    return;
                              //}

                        }
                        break;
                  case FCEUNPCMD_LOADCHEATS:
                        {
                              FILE *fp = FetchFile(FCEU_de32lsb(buf));
                              if(!fp) return;
                              FCEU_FlushGameCheats(0,1);
                              FCEU_LoadGameCheats(fp);
                        }
                        break;
                        //mbg 6/16/08 - netplay doesnt work right now anyway
                        /*case FCEUNPCMD_LOADSTATE:
                        {
                        FILE *fp = FetchFile(FCEU_de32lsb(buf));
                        if(!fp) return;
                        if(FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP))
                   {
                   fclose(fp);                        
                   FCEU_DispMessage("Remote state loaded.");
                   } else FCEUD_PrintError("File error.  (K)ill, (M)aim, (D)estroy?");
                   }
                   break;*/
                  }
            } while(buf[4]);

            netdcount=(netdcount+1)%netdivisor;

            memcpy(netjoy,buf,4);
            *(uint32 *)joyp=*(uint32 *)netjoy;
      }
}

Generated by  Doxygen 1.6.0   Back to index