frontport r8667

"Rewrite the stupid file transfer routines.
* It will now only send the file to the person that needs it.

* Adds abort code to the file routines as well, and also tries to detect when the Host is using a malformed filename to host a map.

* Make sure user can't hit the 'ready' button when the map transfer is ongoing.

* Get rid of the silly delays (Much faster transfers)

NOTE: we are still capped by fps. 
fixes ticket:1128
fixes ticket:1127
refs ticket:215 (still can't transfer 'map packs')"

git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@8734 4a71c877-e1ca-e34f-864e-861f7616d084
master
Buginator 2009-12-19 00:23:37 +00:00 committed by Git SVN Gateway
parent 87802afa73
commit 38f66c5f9e
7 changed files with 211 additions and 136 deletions

View File

@ -202,8 +202,6 @@ typedef struct
Socket** fds; Socket** fds;
} SocketSet; } SocketSet;
#define PLAYER_HOST 1
// //////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// Variables // Variables
@ -2309,6 +2307,7 @@ BOOL NETbcast(NETMSG *msg)
tcp_socket = NULL; tcp_socket = NULL;
NetPlay.players[NetPlay.hostPlayer].heartbeat = false; // mark host as dead NetPlay.players[NetPlay.hostPlayer].heartbeat = false; // mark host as dead
//Game is pretty much over --should just end everything when HOST dies. //Game is pretty much over --should just end everything when HOST dies.
setLobbyError(ERROR_HOSTDROPPED);
return false; return false;
} }
} }
@ -2720,78 +2719,52 @@ BOOL NETsetupTCPIP(const char *machine)
// //////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// File Transfer programs. // File Transfer programs.
/** Send file. It returns % of file sent when 100 it's complete. Call until it returns 100. /** Send file. It returns % of file sent when 100 it's complete. Call until it returns 100.
* @TODO Needs to be rewritten. See issue #215. */ * @TODO: more error checking (?) different file types (?)
* Maybe should close file handle, and seek each time?
*
* @NOTE: MAX_FILE_TRANSFER_PACKET is set to 2k per packet since 7*2 = 14K which is pretty
* much our limit. Don't screw with that without having a bigger buffer!
* NET_BUFFER_SIZE is at 16k. (also remember text chat, plus all the other cruff)
*/
#define MAX_FILE_TRANSFER_PACKET 2048 #define MAX_FILE_TRANSFER_PACKET 2048
UBYTE NETsendFile(BOOL newFile, char *fileName, UDWORD player) UBYTE NETsendFile(char *fileName, UDWORD player)
{ {
static int32_t currPos; int32_t bytesRead = 0;
static PHYSFS_sint64 fileSize_64; uint8_t sendto = 0;
static PHYSFS_sint32 fileSize_32; // we don't support 64bit nettypes yet. char inBuff[MAX_FILE_TRANSFER_PACKET];
static PHYSFS_file *pFileHandle;
int32_t bytesRead; // We are not the host, so we don't care. (in fact, this would be a error)
char inBuff[MAX_FILE_TRANSFER_PACKET]; if(!NetPlay.isHost)
uint8_t sendto = 0; {
return true;
}
memset(inBuff, 0x0, sizeof(inBuff)); memset(inBuff, 0x0, sizeof(inBuff));
if (newFile)
{
// open the file.
pFileHandle = PHYSFS_openRead(fileName); // check file exists
debug(LOG_NET, "Sending [directory: %s] %s to client", PHYSFS_getRealDir(fileName), fileName);
if (pFileHandle == NULL)
{
debug(LOG_ERROR, "Failed to open %s for reading: %s", fileName, PHYSFS_getLastError());
return 0; // failed
}
// get the file's size.
fileSize_64 = PHYSFS_fileLength(pFileHandle);
fileSize_32 = (int32_t) fileSize_64; // we don't support 64bit int nettypes.
currPos = 0;
}
// read some bytes. // read some bytes.
if (!pFileHandle) bytesRead = PHYSFS_read(NetPlay.players[player].wzFile.pFileHandle, inBuff,1, MAX_FILE_TRANSFER_PACKET);
{ sendto = (uint8_t) player;
debug(LOG_ERROR, "No filehandle");
return 0; // failed
}
bytesRead = PHYSFS_read(pFileHandle, inBuff,1, MAX_FILE_TRANSFER_PACKET);
if (player == 0) NETbeginEncode(NET_FILE_PAYLOAD, sendto);
{ // FIXME: why would you send (map) file to everyone ?? NETint32_t(&NetPlay.players[player].wzFile.fileSize_32); // total bytes in this file. (we don't support 64bit yet)
// even if they already have it? multiplay.c 1529 & 1550 are both NETint32_t(&bytesRead); // bytes in this packet
// NETsendFile(true,mapStr,0); & NETsendFile(false,game.map,0); NETint32_t(&NetPlay.players[player].wzFile.currPos); // start byte
// so we ALWAYS send it, it seems? NETstring(fileName, 256); //256 = max filename size
// NOTE: we send to everyone since there is no way to signal the host NETbin(inBuff, bytesRead);
// to stop sending the map. Which means that everytime a player joins
// that doesn't have the map, it will send to all players again.
// We also are limited by fps(!) to the amount of time the loop runs.
NETbeginEncode(FILEMSG, NET_ALL_PLAYERS); // send it.
}
else
{
sendto = (uint8_t) player;
NETbeginEncode(FILEMSG,sendto);
}
// form a message
NETint32_t(&fileSize_32); // total bytes in this file. (we don't support 64bit yet)
NETint32_t(&bytesRead); // bytes in this packet
NETint32_t(&currPos); // start byte
NETstring(fileName, 256); //256 = max filename size
NETbin(inBuff, bytesRead);
NETend(); NETend();
currPos += bytesRead; // update position! NetPlay.players[player].wzFile.currPos += bytesRead; // update position!
if(currPos == fileSize_64) if(NetPlay.players[player].wzFile.currPos == NetPlay.players[player].wzFile.fileSize_32)
{ {
PHYSFS_close(pFileHandle); PHYSFS_close(NetPlay.players[player].wzFile.pFileHandle);
NetPlay.players[player].wzFile.isSending = false; // we are done sending to this client.
NetPlay.players[player].needFile = false;
} }
return (currPos * 100) / fileSize_64; return (NetPlay.players[player].wzFile.currPos * 100) / NetPlay.players[player].wzFile.fileSize_32;
} }
/* @TODO Needs to be rewritten. See issue #215. */ /* @TODO more error checking (?) different file types (?) */
// recv file. it returns % of the file so far recvd. // recv file. it returns % of the file so far recvd.
UBYTE NETrecvFile(void) UBYTE NETrecvFile(void)
{ {
@ -2799,18 +2772,17 @@ UBYTE NETrecvFile(void)
char fileName[256]; char fileName[256];
char outBuff[MAX_FILE_TRANSFER_PACKET]; char outBuff[MAX_FILE_TRANSFER_PACKET];
static PHYSFS_file *pFileHandle; static PHYSFS_file *pFileHandle;
static bool isLoop = false;
memset(fileName, 0x0, sizeof(fileName)); memset(fileName, 0x0, sizeof(fileName));
memset(outBuff, 0x0, sizeof(outBuff)); memset(outBuff, 0x0, sizeof(outBuff));
//read incoming bytes. //read incoming bytes.
NETbeginDecode(FILEMSG); NETbeginDecode(NET_FILE_PAYLOAD);
NETint32_t(&fileSize); // total bytes in this file. NETint32_t(&fileSize); // total bytes in this file.
NETint32_t(&bytesRead); // bytes in this packet NETint32_t(&bytesRead); // bytes in this packet
NETint32_t(&currPos); // start byte NETint32_t(&currPos); // start byte
NETstring(fileName, 256); // read filename (only valid on 1st packet)
// read filename
NETstring(fileName, 256); // Ugh. 256 = max array size
debug(LOG_NET, "Creating new file %s, position is %d", fileName, currPos); debug(LOG_NET, "Creating new file %s, position is %d", fileName, currPos);
if (currPos == 0) // first packet! if (currPos == 0) // first packet!
@ -2823,21 +2795,38 @@ UBYTE NETrecvFile(void)
fsize = PHYSFS_fileLength(fin); fsize = PHYSFS_fileLength(fin);
if ((int32_t) fsize == fileSize) if ((int32_t) fsize == fileSize)
{ {
// NOTE: we would send a abort message to host, but since we can't, uint32_t reason = ALREADY_HAVE_FILE;
// we won't. debug(LOG_NET, "We already have the file %s! ", fileName);
#ifdef DEBUG PHYSFS_close(fin);
debug(LOG_NET, "We already have the file %s.", fileName); NETend();
#endif
// NOTE: we can't abort out, since the host ALWAYS sends the data until done NETbeginEncode(NET_FILE_CANCELLED, NET_HOST_ONLY);
// PHYSFS_close(fin); NETuint32_t(&selectedPlayer);
// NETend(); NETuint32_t(&reason);
// return 100; NETend();
if (!isLoop)
{
isLoop = true;
}
else
{
uint32_t reason = STUCK_IN_FILE_LOOP;
NETend();
// we should never get here, it means, that the game can't detect the level, but we have the file.
// so we kick this player out.
NETbeginEncode(NET_FILE_CANCELLED, NET_HOST_ONLY);
NETuint32_t(&selectedPlayer);
NETuint32_t(&reason);
NETend();
debug(LOG_FATAL, "Something is really wrong with the file's (%s) data, game can't detect it?", fileName);
return 100;
}
} }
PHYSFS_close(fin); PHYSFS_close(fin);
#ifdef DEBUG
debug(LOG_NET, "We have the same named file, but different size. Redownloading %s", fileName); debug(LOG_NET, "We already have the file %s, but different size %d vs %d. Redownloading", fileName, (int32_t) fsize, fileSize);
#endif
} }
pFileHandle = PHYSFS_openWrite(fileName); // create a new file. pFileHandle = PHYSFS_openWrite(fileName); // create a new file.
} }

View File

@ -27,6 +27,7 @@
#define _netplay_h #define _netplay_h
#include "nettypes.h" #include "nettypes.h"
#include <physfs.h>
// Lobby Connection errors // Lobby Connection errors
@ -40,7 +41,8 @@ typedef enum
ERROR_WRONGVERSION, ERROR_WRONGVERSION,
ERROR_WRONGPASSWORD, // NOTE WRONG_PASSWORD results in conflict ERROR_WRONGPASSWORD, // NOTE WRONG_PASSWORD results in conflict
ERROR_HOSTDROPPED, ERROR_HOSTDROPPED,
ERROR_WRONGDATA ERROR_WRONGDATA,
ERROR_UNKNOWNFILEISSUE
} LOBBY_ERROR_TYPES; } LOBBY_ERROR_TYPES;
@ -92,7 +94,7 @@ typedef enum
NET_DROIDDISEMBARK, //43 droid disembarked from a Transporter NET_DROIDDISEMBARK, //43 droid disembarked from a Transporter
NET_RESEARCHSTATUS, //44 research state. NET_RESEARCHSTATUS, //44 research state.
NET_LASSAT, //45 lassat firing. NET_LASSAT, //45 lassat firing.
NET_REQUESTMAP, //46 dont have map, please send it. NET_UNUSED_46, //46 old map request, now unused.
NET_AITEXTMSG, //47 chat between AIs NET_AITEXTMSG, //47 chat between AIs
NET_TEAMS_ON, //48 locked teams mode NET_TEAMS_ON, //48 locked teams mode
NET_BEACONMSG, //49 place beacon NET_BEACONMSG, //49 place beacon
@ -114,6 +116,12 @@ typedef enum
NET_POSITIONREQUEST, //65 position in GUI player list NET_POSITIONREQUEST, //65 position in GUI player list
NET_DATA_CHECK, //66 Data integrity check NET_DATA_CHECK, //66 Data integrity check
NET_HOST_DROPPED, //67 Host has dropped NET_HOST_DROPPED, //67 Host has dropped
NET_FUTURE1, //68 future use
NET_FUTURE2, //69 "
NET_FUTURE3, //70 "
NET_FILE_REQUESTED, //71 Player has requested a file (map/mod/?)
NET_FILE_CANCELLED, //72 Player cancelled a file request
NET_FILE_PAYLOAD, //73 sending file to the player that needs it
NUM_GAME_PACKETS // *MUST* be last. NUM_GAME_PACKETS // *MUST* be last.
} MESSAGE_TYPES; } MESSAGE_TYPES;
@ -182,8 +190,29 @@ typedef struct {
BOOL status; // If the packet compiled or not (this is _not_ sent!) BOOL status; // If the packet compiled or not (this is _not_ sent!)
} NETMSG; } NETMSG;
#define FILEMSG 254 // a file packet typedef struct
{
PHYSFS_file *pFileHandle; // handle
PHYSFS_sint32 fileSize_32; // size
int32_t currPos; // current position
BOOL isSending; // sending to this player
BOOL isCancelled; // player cancelled
int32_t filetype; // future use (1=map 2=mod 3=...)
} WZFile;
typedef struct
{
int32_t player; // the client we sent data to
int32_t done; // how far done we are (100= finished)
int32_t byteCount; // current byte count
} wzFileStatus;
typedef enum
{
WZ_FILE_OK,
ALREADY_HAVE_FILE,
STUCK_IN_FILE_LOOP
} wzFileEnum;
// //////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// Player information. Filled when players join, never re-ordered. selectedPlayer global points to // Player information. Filled when players join, never re-ordered. selectedPlayer global points to
// currently controlled player. This array is indexed by GUI slots in pregame. // currently controlled player. This array is indexed by GUI slots in pregame.
@ -201,6 +230,8 @@ typedef struct
BOOL ready; ///< player ready to start? BOOL ready; ///< player ready to start?
uint32_t versionCheckTime; ///< Time when check sent. Uses 0xffffffff for nothing sent yet uint32_t versionCheckTime; ///< Time when check sent. Uses 0xffffffff for nothing sent yet
BOOL playerVersionFlag; ///< We kick on false BOOL playerVersionFlag; ///< We kick on false
BOOL needFile; ///< if We need a file sent to us
WZFile wzFile; ///< for each player, we keep track of map progress
} PLAYER; } PLAYER;
// //////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
@ -238,7 +269,7 @@ extern BOOL NETsend(NETMSG *msg, UDWORD player); // send to player
extern BOOL NETbcast(NETMSG *msg); // broadcast to everyone extern BOOL NETbcast(NETMSG *msg); // broadcast to everyone
extern BOOL NETrecv(uint8_t *type); // recv a message if possible extern BOOL NETrecv(uint8_t *type); // recv a message if possible
extern UBYTE NETsendFile(BOOL newFile, char *fileName, UDWORD player); // send file chunk. extern UBYTE NETsendFile(char *fileName, UDWORD player); // send file chunk.
extern UBYTE NETrecvFile(void); // recv file chunk extern UBYTE NETrecvFile(void); // recv file chunk
extern int NETclose(void); // close current game extern int NETclose(void); // close current game

View File

@ -152,16 +152,8 @@ UDWORD hashBuffer(uint8_t *pData, uint32_t size)
{ {
val = (uint32_t *)(NewData+pt); val = (uint32_t *)(NewData+pt);
// original: hashval ^= (*val);
//hashval = SDL_SwapBE32(hashval ^ SDL_SwapBE32((*val))); // I hope this is correct...can't test since no PPC machine
// Next time, ask someone who does, or at least get some someone to double-check your math. ;)
// Here is a solution that makes BE archs binary-compatible with the LE output of the above
hashval = SDL_Swap32(hashval ^ SDL_Swap32(*val));
// Here is the solution that the above was probably intended to do:
//hashval ^= (*val); // no endianness enforcement, since it'll be done by whatever handles its output
// spams a ton--but useful for debugging. // spams a ton--but useful for debugging.
// debug(LOG_NET, "hash %08x pt %08x val is %08x", hashval, pt, *val); // debug(LOG_NET, "hash %08x pt %08x val is %08x", hashval, pt, *val);
pt += 4; pt += 4;
@ -175,6 +167,8 @@ UDWORD hashBuffer(uint8_t *pData, uint32_t size)
return hashval; return hashval;
} }
// create the hash for that data block.
// Data should be converted to Network byte order
void calcDataHash(uint8_t *pBuffer, uint32_t size, uint32_t index) void calcDataHash(uint8_t *pBuffer, uint32_t size, uint32_t index)
{ {
if (!bMultiPlayer) if (!bMultiPlayer)
@ -182,18 +176,9 @@ void calcDataHash(uint8_t *pBuffer, uint32_t size, uint32_t index)
return; return;
} }
// create the hash for that data block. DataHash[index] ^= SDL_SwapBE32(hashBuffer(pBuffer, size));
// Here is the original solution: debug(LOG_NET, "DataHash[%2u] = %08x", index, DataHash[index]);
//DataHash[index] = SDL_SwapBE32(DataHash[index] ^ hashBuffer(pBuffer, size)); // check endian issues?
// Here is a solution that makes BE archs binary-compatible with the LE output of the above
DataHash[index] = SDL_Swap32(DataHash[index] ^ SDL_SwapLE32(hashBuffer(pBuffer, size)));
// Here is the solution that the above was probably intended to do:
//DataHash[index] ^= SDL_SwapBE32(hashBuffer(pBuffer, size));
debug(LOG_NET, "DataHash[%2u] = %08x\n", index, DataHash[index]);
return; return;
} }

View File

@ -837,6 +837,11 @@ static void addGames(void)
case ERROR_WRONGDATA: case ERROR_WRONGDATA:
txt = _("Wrong data/mod detected by Host."); txt = _("Wrong data/mod detected by Host.");
break; break;
// AFAIK, the only way this can really happy is if the Host's file is named wrong, or a client side error.
case ERROR_UNKNOWNFILEISSUE:
txt = _("Host couldn't send file?");
debug(LOG_POPUP, "Warzone couldn't complete a file request.\n\nPossibly, Host's file is incorrect. Check your logs for more details.");
break;
case ERROR_WRONGPASSWORD: case ERROR_WRONGPASSWORD:
txt = _("Incorrect Password!"); txt = _("Incorrect Password!");
break; break;
@ -1577,6 +1582,13 @@ BOOL recvReadyRequest()
return false; return false;
} }
// do not allow players to select 'ready' if we are sending a map too them!
// TODO: make a new icon to show this state?
if (NetPlay.players[player].wzFile.isSending)
{
return false;
}
return changeReadyStatus((UBYTE)player, bReady); return changeReadyStatus((UBYTE)player, bReady);
} }
@ -2695,11 +2707,11 @@ void frontendMultiMessages(void)
// Copy the message to the global one used by the new NET API // Copy the message to the global one used by the new NET API
switch(type) switch(type)
{ {
case NET_REQUESTMAP: case NET_FILE_REQUESTED:
recvMapFileRequested(); recvMapFileRequested();
break; break;
case FILEMSG: case NET_FILE_PAYLOAD:
widgSetButtonState(psWScreen, MULTIOP_MAP_BUT, 1); // turn preview button off widgSetButtonState(psWScreen, MULTIOP_MAP_BUT, 1); // turn preview button off
if (recvMapFileData()) if (recvMapFileData())
{ {
@ -2707,6 +2719,34 @@ void frontendMultiMessages(void)
} }
break; break;
case NET_FILE_CANCELLED: // host only routine
{
uint32_t reason;
uint32_t victim;
NETbeginDecode(NET_FILE_CANCELLED);
NETuint32_t(&victim);
NETuint32_t(&reason);
NETend();
switch (reason)
{
case STUCK_IN_FILE_LOOP:
debug(LOG_WARNING, "Received file cancel request from player %u, They are stuck in a loop?", victim);
kickPlayer(victim, "couldn't upload file for some reason. ", ERROR_UNKNOWNFILEISSUE);
NetPlay.players[victim].wzFile.isCancelled = true;
NetPlay.players[victim].wzFile.isSending = false;
break;
case ALREADY_HAVE_FILE:
default:
debug(LOG_WARNING, "Received file cancel request from player %u, They already have the file ?", victim);
NetPlay.players[victim].wzFile.isCancelled = true;
NetPlay.players[victim].wzFile.isSending = false;
break;
}
}
break;
case NET_OPTIONS: // incoming options file. case NET_OPTIONS: // incoming options file.
recvOptions(); recvOptions();
ingame.localOptionsReceived = true; ingame.localOptionsReceived = true;
@ -2848,8 +2888,8 @@ void frontendMultiMessages(void)
void runMultiOptions(void) void runMultiOptions(void)
{ {
static UDWORD lastrefresh=0; static UDWORD lastrefresh = 0;
UDWORD id,value;//,i; UDWORD id, value, i;
char sTemp[128]; char sTemp[128];
PLAYERSTATS playerStats; PLAYERSTATS playerStats;
W_CONTEXT context; W_CONTEXT context;
@ -2859,10 +2899,13 @@ void runMultiOptions(void)
frontendMultiMessages(); frontendMultiMessages();
// keep sending the map if required. for (i = 0; i < MAX_PLAYERS; i++)
if(bSendingMap)
{ {
sendMap(); // send it for each player that needs it
if (NetPlay.players[i].wzFile.isSending)
{
sendMap();
}
} }
// update boxes? // update boxes?

View File

@ -220,7 +220,7 @@ void recvOptions()
debug(LOG_NET, "Map was not found, requesting map %s from host.", game.map); debug(LOG_NET, "Map was not found, requesting map %s from host.", game.map);
// Request the map from the host // Request the map from the host
NETbeginEncode(NET_REQUESTMAP, NET_HOST_ONLY); NETbeginEncode(NET_FILE_REQUESTED, NET_HOST_ONLY);
NETuint32_t(&player); NETuint32_t(&player);
NETend(); NETend();

View File

@ -80,8 +80,6 @@ UBYTE bDisplayMultiJoiningStatus;
MULTIPLAYERGAME game; //info to describe game. MULTIPLAYERGAME game; //info to describe game.
MULTIPLAYERINGAME ingame; MULTIPLAYERINGAME ingame;
BOOL bSendingMap = false; // map broadcasting.
char beaconReceiveMsg[MAX_PLAYERS][MAX_CONSOLE_STRING_LENGTH]; //beacon msg for each player char beaconReceiveMsg[MAX_PLAYERS][MAX_CONSOLE_STRING_LENGTH]; //beacon msg for each player
char playerName[MAX_PLAYERS][MAX_STR_LENGTH]; //Array to store all player names (humans and AIs) char playerName[MAX_PLAYERS][MAX_STR_LENGTH]; //Array to store all player names (humans and AIs)
BOOL bPlayerReadyGUI[MAX_PLAYERS] = {false}; BOOL bPlayerReadyGUI[MAX_PLAYERS] = {false};
@ -1558,20 +1556,32 @@ BOOL recvDestroyFeature()
BOOL recvMapFileRequested() BOOL recvMapFileRequested()
{ {
char mapStr[256],mapName[256],fixedname[256]; char mapStr[256],mapName[256],fixedname[256];
uint32_t player;
// another player is requesting the map PHYSFS_sint64 fileSize_64;
PHYSFS_file *pFileHandle;
// We are not the host, so we don't care. (in fact, this would be a error)
if(!NetPlay.isHost) if(!NetPlay.isHost)
{ {
return true; return true;
} }
// start sending the map to the other players. // Check to see who wants the file
if(!bSendingMap) NETbeginDecode(NET_FILE_REQUESTED);
NETuint32_t(&player);
NETend();
if (!NetPlay.players[player].wzFile.isSending)
{ {
NetPlay.players[player].needFile = true;
NetPlay.players[player].wzFile.isCancelled = false;
NetPlay.players[player].wzFile.isSending = true;
memset(mapStr,0,256); memset(mapStr,0,256);
memset(mapName,0,256); memset(mapName,0,256);
memset(fixedname,0,256); memset(fixedname,0,256);
bSendingMap = true;
addConsoleMessage("Map was requested: SENDING MAP!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); addConsoleMessage("Map was requested: SENDING MAP!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
sstrcpy(mapName, game.map); sstrcpy(mapName, game.map);
@ -1592,38 +1602,55 @@ BOOL recvMapFileRequested()
snprintf(mapStr, sizeof(mapStr), "%dc-%s.wz", game.maxPlayers, mapName); snprintf(mapStr, sizeof(mapStr), "%dc-%s.wz", game.maxPlayers, mapName);
snprintf(fixedname, sizeof(fixedname), "maps/%s", mapStr); //We know maps are in /maps dir...now. fix for linux -Q snprintf(fixedname, sizeof(fixedname), "maps/%s", mapStr); //We know maps are in /maps dir...now. fix for linux -Q
sstrcpy(mapStr, fixedname); sstrcpy(mapStr, fixedname);
debug(LOG_NET, "Map was requested. Sending %s", mapStr); debug(LOG_NET, "Map was requested. Looking for %s", mapStr);
// NOTE: should we check if file exsists before trying to send it ?
NETsendFile(true,mapStr,0); // Checking to see if file is available...
pFileHandle = PHYSFS_openRead(mapStr);
if (pFileHandle == NULL)
{
debug(LOG_ERROR, "Failed to open %s for reading: %s", mapStr, PHYSFS_getLastError());
debug(LOG_FATAL, "You have a map (%s) that can't be located.\n\nMake sure it is in the correct directory and or format!", mapStr);
// NOTE: if we get here, then the game is basically over, The host can't send the file for whatever reason...
// Which also means, that we can't continue.
debug(LOG_NET, "***Host has a file issue, and is being forced to quit!***");
NETbeginEncode(NET_HOST_DROPPED, NET_ALL_PLAYERS);
NETend();
abort();
} }
// get the file's size.
fileSize_64 = PHYSFS_fileLength(pFileHandle);
debug(LOG_NET, "File is valid, sending [directory: %s] %s to client %u", PHYSFS_getRealDir(mapStr), mapStr, player);
NetPlay.players[player].wzFile.pFileHandle = pFileHandle;
NetPlay.players[player].wzFile.fileSize_32 = (int32_t) fileSize_64; //we don't support 64bit int nettypes.
NetPlay.players[player].wzFile.currPos = 0;
NETsendFile(mapStr, player);
}
return true; return true;
} }
// continue sending the map // continue sending the map
UBYTE sendMap(void) void sendMap(void)
{ {
int i = 0;
UBYTE done; UBYTE done;
static UDWORD lastCall;
for (i = 0; i < MAX_PLAYERS; i++)
if(lastCall > gameTime)lastCall= 0;
if ( (gameTime - lastCall) <200)
{ {
return 0; if (NetPlay.players[i].wzFile.isSending)
}
lastCall = gameTime;
done = NETsendFile(false,game.map,0);
if(done == 100)
{ {
done = NETsendFile(game.map, i);
if (done == 100)
{
addConsoleMessage("MAP SENT!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); addConsoleMessage("MAP SENT!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
bSendingMap = false; debug(LOG_NET, "=== File has been sent to player %d ===", i);
NetPlay.players[i].wzFile.isSending = false;
NetPlay.players[i].needFile = false;
}
}
} }
return done;
} }
// Another player is broadcasting a map, recv a chunk. Returns false if not yet done. // Another player is broadcasting a map, recv a chunk. Returns false if not yet done.
@ -1634,6 +1661,7 @@ BOOL recvMapFileData()
{ {
addConsoleMessage("MAP DOWNLOADED!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); addConsoleMessage("MAP DOWNLOADED!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
sendTextMessage("MAP DOWNLOADED",true); //send sendTextMessage("MAP DOWNLOADED",true); //send
debug(LOG_NET, "=== File has been received. ===");
// clear out the old level list. // clear out the old level list.
levShutDown(); levShutDown();

View File

@ -147,8 +147,7 @@ extern BOOL sendAIMessage (char *pStr, UDWORD player, UDWORD to); //send AI mes
extern BOOL turnOffMultiMsg (BOOL bDoit); extern BOOL turnOffMultiMsg (BOOL bDoit);
extern UBYTE sendMap (void); extern void sendMap(void);
extern BOOL multiplayerWinSequence(BOOL firstCall); extern BOOL multiplayerWinSequence(BOOL firstCall);
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////