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-861f7616d084master
parent
87802afa73
commit
38f66c5f9e
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
25
src/data.c
25
src/data.c
|
@ -152,15 +152,7 @@ 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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue