Merge branch 'public_next'

# Conflicts:
#	src/d_clisrv.c
#	src/r_things.c
This commit is contained in:
Monster Iestyn 2017-01-07 15:03:59 +00:00
commit 12ae6bb22a
27 changed files with 1915 additions and 1399 deletions

View File

@ -376,6 +376,14 @@ endif
OPTS:=-fno-exceptions $(OPTS)
ifdef MOBJCONSISTANCY
OPTS+=-DMOBJCONSISTANCY
endif
ifdef PACKETDROP
OPTS+=-DPACKETDROP
endif
ifdef DEBUGMODE
# build with debugging information
@ -385,7 +393,7 @@ ifdef GCC48
else
CFLAGS+=-O0
endif
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
else

File diff suppressed because it is too large Load Diff

View File

@ -59,7 +59,7 @@ typedef enum
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
// allows HSendPacket(,true,,) to return false.
// allows HSendPacket(*, true, *, *) to return false.
// In addition, this packet can't occupy all the available slots.
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
@ -76,11 +76,16 @@ typedef enum
NUMPACKETTYPE
} packettype_t;
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#if defined(_MSC_VER)
#pragma pack(1)
#endif
// client to server packet
// Client to server packet
typedef struct
{
UINT8 client_tic;
@ -89,7 +94,7 @@ typedef struct
ticcmd_t cmd;
} ATTRPACK clientcmd_pak;
// splitscreen packet
// Splitscreen packet
// WARNING: must have the same format of clientcmd_pak, for more easy use
typedef struct
{
@ -110,16 +115,16 @@ typedef struct
UINT8 starttic;
UINT8 numtics;
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
} ATTRPACK servertics_pak;
// sent to client when all consistency data
// Sent to client when all consistency data
// for players has been restored
typedef struct
{
UINT32 randomseed;
//ctf flag stuff
// CTF flag stuff
SINT8 flagplayer[2];
INT32 flagloose[2];
INT32 flagflags[2];
@ -127,11 +132,11 @@ typedef struct
fixed_t flagy[2];
fixed_t flagz[2];
UINT32 ingame; // spectator bit for each player
UINT32 ctfteam; // if not spectator, then which team?
UINT32 ingame; // Spectator bit for each player
UINT32 ctfteam; // If not spectator, then which team?
// Resynch game scores and the like all at once
UINT32 score[MAXPLAYERS]; // Everyone's score.
UINT32 score[MAXPLAYERS]; // Everyone's score
INT16 numboxes[MAXPLAYERS];
INT16 totalring[MAXPLAYERS];
tic_t realtime[MAXPLAYERS];
@ -140,14 +145,14 @@ typedef struct
typedef struct
{
//player stuff
// Player stuff
UINT8 playernum;
// Do not send anything visual related.
// Only send data that we need to know for physics.
UINT8 playerstate; //playerstate_t
UINT32 pflags; //pflags_t
UINT8 panim; //panim_t
UINT8 playerstate; // playerstate_t
UINT32 pflags; // pflags_t
UINT8 panim; // panim_t
angle_t aiming;
INT32 currentweapon;
@ -176,9 +181,9 @@ typedef struct
UINT8 charability;
UINT8 charability2;
UINT32 charflags;
UINT32 thokitem; //mobjtype_t
UINT32 spinitem; //mobjtype_t
UINT32 revitem; //mobjtype_t
UINT32 thokitem; // mobjtype_t
UINT32 spinitem; // mobjtype_t
UINT32 revitem; // mobjtype_t
fixed_t actionspd;
fixed_t mindash;
fixed_t maxdash;
@ -234,7 +239,7 @@ typedef struct
INT32 onconveyor;
//player->mo stuff
UINT8 hasmo; //boolean
UINT8 hasmo; // Boolean
INT32 health;
angle_t angle;
@ -262,10 +267,10 @@ typedef struct
typedef struct
{
UINT8 version; // different versions don't work
UINT8 subversion; // contains build version
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
// server launch stuffs
// Server launch stuffs
UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@ -279,18 +284,18 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
SINT8 adminplayer; // needs to be signed
SINT8 adminplayer; // Needs to be signed
char server_context[8]; // unique context id, generated at server startup.
char server_context[8]; // Unique context id, generated at server startup.
UINT8 varlengthinputs[0]; // playernames and netvars
UINT8 varlengthinputs[0]; // Playernames and netvars
} ATTRPACK serverconfig_pak;
typedef struct {
UINT8 fileid;
UINT32 position;
UINT16 size;
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
} ATTRPACK filetx_pak;
#ifdef _MSC_VER
@ -299,14 +304,14 @@ typedef struct {
typedef struct
{
UINT8 version; // different versions don't work
UINT8 subversion; // contains build version
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
UINT8 localplayers;
UINT8 mode;
} ATTRPACK clientconfig_pak;
#define MAXSERVERNAME 32
// this packet is too large
// This packet is too large
typedef struct
{
UINT8 version;
@ -372,45 +377,45 @@ typedef struct
} ATTRPACK plrconfig;
//
// Network packet data.
// Network packet data
//
typedef struct
{
UINT32 checksum;
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
UINT8 ackreturn; // the return of the ack number
UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
UINT8 ackreturn; // The return of the ack number
UINT8 packettype;
UINT8 reserved; // padding
UINT8 reserved; // Padding
union
{
clientcmd_pak clientpak; // 144 bytes
client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes
serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; //
resynch_pak resynchpak; //
UINT8 resynchgot; //
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes
serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes
askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
clientcmd_pak clientpak; // 144 bytes
client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; //
resynch_pak resynchpak; //
UINT8 resynchgot; //
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes
serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
#ifdef NEWPING
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
#endif
} u; // this is needed to pack diff packet types data together
} u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
#define MAXSERVERLIST 64 // depends only on the display
#define MAXSERVERLIST 64 // Depends only on the display
typedef struct
{
SINT8 node;
@ -421,7 +426,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern INT32 mapchangepending;
// points inside doomcom
// Points inside doomcom
extern doomdata_t *netbuffer;
extern consvar_t cv_playbackspeed;
@ -442,7 +447,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8
extern boolean server;
extern boolean dedicated; // for dedicated server
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
@ -457,11 +462,11 @@ extern UINT32 playerpingtable[MAXPLAYERS];
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
// used in d_net, the only dependence
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low);
void D_ClientServerInit(void);
// initialise the other field
// Initialise the other field
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
@ -479,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
// is there a game running
// Is there a game running
boolean Playing(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? how many ticks to run?
//? How many ticks to run?
void TryRunTics(tic_t realtic);
// extra data for lmps

View File

@ -31,15 +31,15 @@
//
// NETWORKING
//
// gametic is the tic about to be (or currently being) run
// server:
// gametic is the tic about to (or currently being) run
// Server:
// maketic is the tic that hasn't had control made for it yet
// nettics: is the tic for each node
// firsttictosend: is the lowest value of nettics
// client:
// neededtic: is the tic needed by the client to run the game
// firsttictosend: is used to optimize a condition
// normally maketic >= gametic > 0
// nettics is the tic for each node
// firstticstosend is the lowest value of nettics
// Client:
// neededtic is the tic needed by the client to run the game
// firstticstosend is used to optimize a condition
// Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000
tic_t connectiontimeout = (15*TICRATE);
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
// -----------------------------------------------------------------
// Some structs and functions for acknowledgement of packets
// -----------------------------------------------------------------
#define MAXACKPACKETS 96 // minimum number of nodes
#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
#define MAXACKTOSEND 96
#define URGENTFREESLOTENUM 10
#define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET
@ -139,10 +139,10 @@ typedef struct
{
UINT8 acknum;
UINT8 nextacknum;
UINT8 destinationnode;
tic_t senttime;
UINT16 length;
UINT16 resentnum;
UINT8 destinationnode; // The node to send the ack to
tic_t senttime; // The time when the ack was sent
UINT16 length; // The packet size
UINT16 resentnum; // The number of
union {
SINT8 raw[MAXPACKETLENGTH];
doomdata_t data;
@ -212,11 +212,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
return d;
}
// return a free acknum and copy netbuffer in the ackpak table
/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
*
* \param freeack The address to store the free acknum at
* \param lowtimer ???
* \return True if a free acknum was found
*/
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{
node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslote = 0;
INT32 i, numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{
@ -227,10 +232,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
// for low priority packet, make sure let freeslotes so urgents packets can be sent
numfreeslote++;
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
continue;
// For low priority packets, make sure to let freeslots so urgent packets can be sent
if (netbuffer->packettype >= PT_CANFAIL)
{
numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
ackpak[i].acknum = node->nextacknum;
ackpak[i].nextacknum = node->nextacknum;
@ -241,7 +249,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
ackpak[i].length = doomcom->datalength;
if (lowtimer)
{
// lowtime mean can't be sent now so try it soon as possible
// Lowtime means can't be sent now so try it as soon as possible
ackpak[i].senttime = 0;
ackpak[i].resentnum = 1;
}
@ -254,7 +262,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*freeack = ackpak[i].acknum;
sendackpacket++; // for stat
sendackpacket++; // For stat
return true;
}
@ -266,14 +274,14 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false;
}
// Get a ack to send in the queu of this node
// Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node)
{
nodes[node].lasttimeacktosend_sent = I_GetTime();
return nodes[node].firstacktosend;
}
static void Removeack(INT32 i)
static void RemoveAck(INT32 i)
{
INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING
@ -294,27 +302,27 @@ static void Removeack(INT32 i)
Net_CloseConnection(node);
}
// we have got a packet proceed the ack request and ack return
// We have got a packet, proceed the ack request and ack return
static boolean Processackpak(void)
{
INT32 i;
boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode];
// received an ack return, so remove the ack in the list
// Received an ack return, so remove the ack in the list
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
{
node->remotefirstack = netbuffer->ackreturn;
// search the ackbuffer and free it
// Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{
Removeack(i);
RemoveAck(i);
}
}
// received a packet with ack, queue it to send the ack back
// Received a packet with ack, queue it to send the ack back
if (netbuffer->ack)
{
UINT8 ack = netbuffer->ack;
@ -323,23 +331,23 @@ static boolean Processackpak(void)
{
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
duppacket++;
goodpacket = false; // discard packet (duplicate)
goodpacket = false; // Discard packet (duplicate)
}
else
{
// check if it is not already in the queue
// Check if it is not already in the queue
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
if (node->acktosend[i] == ack)
{
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
duppacket++;
goodpacket = false; // discard packet (duplicate)
goodpacket = false; // Discard packet (duplicate)
break;
}
if (goodpacket)
{
// is a good packet so increment the acknowledge number,
// then search for a "hole" in the queue
// Is a good packet so increment the acknowledge number,
// Then search for a "hole" in the queue
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
if (!nextfirstack)
nextfirstack = 1;
@ -383,10 +391,10 @@ static boolean Processackpak(void)
}
}
}
else // out of order packet
else // Out of order packet
{
// don't increment firsacktosend, put it in asktosend queue
// will be incremented when the nextfirstack comes (code above)
// Don't increment firsacktosend, put it in asktosend queue
// Will be incremented when the nextfirstack comes (code above)
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
if (newhead != node->acktosend_tail)
@ -394,8 +402,8 @@ static boolean Processackpak(void)
node->acktosend[node->acktosend_head] = ack;
node->acktosend_head = newhead;
}
else // buffer full discard packet, sender will resend it
{ // we can admit the packet but we will not detect the duplication after :(
else // Buffer full discard packet, sender will resend it
{ // We can admit the packet but we will not detect the duplication after :(
DEBFILE("no more freeackret\n");
goodpacket = false;
}
@ -430,25 +438,24 @@ static void GotAcks(void)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
Removeack(i);
else
// nextacknum is first equal to acknum, then when receiving bigger ack
// there is big chance the packet is lost
// when resent, nextacknum = nodes[node].nextacknum
// will redo the same but with different value
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
&& ackpak[i].senttime > 0)
{
ackpak[i].senttime--; // hurry up
}
RemoveAck(i);
// nextacknum is first equal to acknum, then when receiving bigger ack
// there is big chance the packet is lost
// When resent, nextacknum = nodes[node].nextacknum
// will redo the same but with different value
else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
&& ackpak[i].senttime > 0)
{
ackpak[i].senttime--; // hurry up
}
}
}
#endif
static inline void Net_ConnectionTimeout(INT32 node)
{
// send a very special packet to self (hack the reboundstore queue)
// main code will handle it
// Send a very special packet to self (hack the reboundstore queue)
// Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
reboundstore[rebound_head].ack = 0;
reboundstore[rebound_head].ackreturn = 0;
@ -456,12 +463,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
rebound_head = (rebound_head+1) % MAXREBOUND;
// do not redo it quickly (if we do not close connection it is
// Do not redo it quickly (if we do not close connection it is
// for a good reason!)
nodes[node].lasttimepacketreceived = I_GetTime();
}
// resend the data if needed
// Resend the data if needed
void Net_AckTicker(void)
{
#ifndef NONET
@ -497,7 +504,7 @@ void Net_AckTicker(void)
ackpak[i].senttime = I_GetTime();
ackpak[i].resentnum++;
ackpak[i].nextacknum = node->nextacknum;
retransmit++; // for stat
retransmit++; // For stat
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
(size_t)(ackpak[i].length - BASEPACKETSIZE));
}
@ -505,11 +512,11 @@ void Net_AckTicker(void)
for (i = 1; i < MAXNETNODES; i++)
{
// this is something like node open flag
// This is something like node open flag
if (nodes[i].firstacktosend)
{
// we haven't sent a packet for a long time
// acknowledge packet if needed
// We haven't sent a packet for a long time
// Acknowledge packet if needed
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i);
@ -523,9 +530,9 @@ void Net_AckTicker(void)
#endif
}
// remove last packet received ack before resending the ackret
// Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgPacket(INT32 node)
void Net_UnAcknowledgePacket(INT32 node)
{
#ifdef NONET
(void)node;
@ -564,20 +571,29 @@ void Net_UnAcknowledgPacket(INT32 node)
#endif
}
boolean Net_AllAckReceived(void)
{
#ifndef NONET
/** Checks if all acks have been received
*
* \return True if all acks have been received
*
*/
static boolean Net_AllAcksReceived(void)
{
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum)
return false;
#endif
return true;
}
#endif
// wait for all ackreturns with timeout in seconds
/** Waits for all ackreturns
*
* \param timeout Timeout in seconds
*
*/
void Net_WaitAllAckReceived(UINT32 timeout)
{
#ifdef NONET
@ -587,7 +603,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
timeout = tictac + timeout*NEWTICRATE;
HGetPacket();
while (timeout > I_GetTime() && !Net_AllAckReceived())
while (timeout > I_GetTime() && !Net_AllAcksReceived())
{
while (tictac == I_GetTime())
I_Sleep();
@ -598,18 +614,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
#endif
}
static void InitNode(INT32 node)
static void InitNode(node_t *node)
{
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
node->acktosend_head = node->acktosend_tail = 0;
#ifndef NEWPING
nodes[node].ping = PINGDEFAULT;
nodes[node].varping = VARPINGDEFAULT;
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
node->ping = PINGDEFAULT;
node->varping = VARPINGDEFAULT;
node->timeout = TIMEOUT(node->ping, node->varping);
#endif
nodes[node].firstacktosend = 0;
nodes[node].nextacknum = 1;
nodes[node].remotefirstack = 0;
nodes[node].flags = 0;
node->firstacktosend = 0;
node->nextacknum = 1;
node->remotefirstack = 0;
node->flags = 0;
}
static void InitAck(void)
@ -622,9 +638,14 @@ static void InitAck(void)
#endif
for (i = 0; i < MAXNETNODES; i++)
InitNode(i);
InitNode(&nodes[i]);
}
/** Removes all acks of a given packet type
*
* \param packettype The packet type to forget
*
*/
void Net_AbortPacketType(UINT8 packettype)
{
#ifdef NONET
@ -676,8 +697,8 @@ void Net_CloseConnection(INT32 node)
ackpak[i].acknum = 0;
}
InitNode(node);
AbortSendFiles(node);
InitNode(&nodes[node]);
SV_AbortSendFiles(node);
I_NetFreeNodenum(node);
#endif
}
@ -729,9 +750,15 @@ static void fprintfstring(char *s, size_t len)
}
if (mode)
fprintf(debugfile, "]");
}
static void fprintfstringnewline(char *s, size_t len)
{
fprintfstring(s, len);
fprintf(debugfile, "\n");
}
/// \warning Keep this up-to-date if you add/remove/rename packet types
static const char *packettypename[NUMPACKETTYPE] =
{
"NOTHING",
@ -749,15 +776,22 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKINFO",
"SERVERINFO",
"PLAYERINFO",
"REQUESTFILE",
"ASKINFOVIAMS",
"PLAYERCONFIGS",
"RESYNCHEND",
"RESYNCHGET",
"FILEFRAGMENT",
"TEXTCMD",
"TEXTCMD2",
"CLIENTJOIN",
"NODETIMEOUT",
"RESYNCHING",
#ifdef NEWPING
"PING"
#endif
};
static void DebugPrintpacket(const char *header)
@ -770,20 +804,29 @@ static void DebugPrintpacket(const char *header)
{
case PT_ASKINFO:
case PT_ASKINFOVIAMS:
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) );
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
break;
case PT_CLIENTJOIN:
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
netbuffer->u.clientcfg.mode);
break;
case PT_SERVERTICS:
{
servertics_pak *serverpak = &netbuffer->u.serverpak;
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics];
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd;
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
netbuffer->u.serverpak.numtics,
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
fprintfstring((char *)cmd, 3);
if (ntxtcmd > 4)
{
fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
}
fprintf(debugfile, "\n");
break;
}
case PT_CLIENTCMD:
case PT_CLIENT2CMD:
case PT_CLIENTMIS:
@ -797,7 +840,8 @@ static void DebugPrintpacket(const char *header)
case PT_TEXTCMD:
case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
break;
case PT_SERVERCFG:
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
@ -813,7 +857,7 @@ static void DebugPrintpacket(const char *header)
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
netbuffer->u.serverinfo.fileneedednum,
(UINT32)LONG(netbuffer->u.serverinfo.time));
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
break;
@ -827,20 +871,100 @@ static void DebugPrintpacket(const char *header)
break;
case PT_REQUESTFILE:
default: // write as a raw packet
fprintfstring((char *)netbuffer->u.textcmd,
fprintfstringnewline((char *)netbuffer->u.textcmd,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
break;
}
}
#endif
#ifdef PACKETDROP
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
static INT32 packetdroprate = 0;
void Command_Drop(void)
{
INT32 packetquantity;
const char *packetname;
size_t i;
if (COM_Argc() < 2)
{
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
"drop reset: cancel all packet drops");
return;
}
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
{
memset(packetdropquantity, 0, sizeof(packetdropquantity));
return;
}
if (COM_Argc() >= 3)
{
packetquantity = atoi(COM_Argv(2));
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
{
CONS_Printf("Invalid quantity\n");
return;
}
}
else
packetquantity = -1;
packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity;
else
{
for (i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i]))
{
packetdropquantity[i] = packetquantity;
return;
}
CONS_Printf("Unknown packet name\n");
}
}
void Command_Droprate(void)
{
INT32 droprate;
if (COM_Argc() < 2)
{
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
return;
}
droprate = atoi(COM_Argv(1));
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
{
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
return;
}
packetdroprate = droprate;
}
static boolean ShouldDropPacket(void)
{
return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
}
#endif
//
// HSendPacket
//
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
{
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
if (node == 0) // packet is to go back to us
if (node == 0) // Packet is to go back to us
{
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
{
@ -871,7 +995,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
(void)reliable;
(void)acknum;
#else
// do this before GetFreeAcknum because this function backup
// do this before GetFreeAcknum because this function backups
// the current packet
doomcom->remotenode = (INT16)node;
if (doomcom->datalength <= 0)
@ -884,7 +1008,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
return false;
}
if (node < MAXNETNODES) // can be a broadcast
if (node < MAXNETNODES) // Can be a broadcast
netbuffer->ackreturn = GetAcktosend(node);
else
netbuffer->ackreturn = 0;
@ -905,20 +1029,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
netbuffer->ack = acknum;
netbuffer->checksum = NetbufferChecksum();
sendbytes += packetheaderlength + doomcom->datalength; // for stat
sendbytes += packetheaderlength + doomcom->datalength; // For stat
// simulate internet :)
if (true || rand()<(INT32)RAND_MAX/5)
#ifdef PACKETDROP
// Simulate internet :)
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
if (!ShouldDropPacket())
{
#endif
#ifdef DEBUGFILE
if (debugfile)
DebugPrintpacket("SEND");
DebugPrintpacket("SENT");
#endif
I_NetSend();
#ifdef PACKETDROP
}
else
{
if (packetdropquantity[netbuffer->packettype] > 0)
packetdropquantity[netbuffer->packettype]--;
#ifdef DEBUGFILE
else if (debugfile)
DebugPrintpacket("NOTSEND");
if (debugfile)
DebugPrintpacket("NOT SENT");
#endif
}
#endif
#endif // ndef NONET
@ -933,7 +1067,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
//
boolean HGetPacket(void)
{
// get a packet from self
// Get a packet from self
if (rebound_tail != rebound_head)
{
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
@ -963,11 +1097,11 @@ boolean HGetPacket(void)
if (doomcom->remotenode == -1)
return false;
getbytes += packetheaderlength + doomcom->datalength; // for stat
getbytes += packetheaderlength + doomcom->datalength; // For stat
if (doomcom->remotenode >= MAXNETNODES)
{
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
continue;
}
@ -1230,4 +1364,6 @@ void D_CloseConnection(void)
netgame = false;
addedtogame = false;
}
D_ResetTiccmds();
}

View File

@ -18,10 +18,10 @@
#ifndef __D_NET__
#define __D_NET__
// Max computers in a game.
// Max computers in a game
#define MAXNETNODES 32
#define BROADCASTADDR MAXNETNODES
#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
#define STATLENGTH (TICRATE*2)
@ -32,17 +32,16 @@ extern float lostpercent, duppercent, gamelostpercent;
extern INT32 packetheaderlength;
boolean Net_GetNetStat(void);
extern INT32 getbytes;
extern INT64 sendbytes; // realtime updated
extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES];
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
void Net_AckTicker(void);
boolean Net_AllAckReceived(void);
// if reliable return true if packet sent, 0 else
// If reliable return true if packet sent, 0 else
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength);
boolean HGetPacket(void);
@ -52,9 +51,10 @@ void D_SaveBan(void);
#endif
boolean D_CheckNetGame(void);
void D_CloseConnection(void);
void Net_UnAcknowledgPacket(INT32 node);
void Net_UnAcknowledgePacket(INT32 node);
void Net_CloseConnection(INT32 node);
void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout);
#endif

View File

@ -365,6 +365,35 @@ boolean splitscreen = false;
boolean circuitmap = false;
INT32 adminplayer = -1;
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
{
"NAMEANDCOLOR",
"WEAPONPREF",
"KICK",
"NETVAR",
"SAY",
"MAP",
"EXITLEVEL",
"ADDFILE",
"PAUSE",
"ADDPLAYER",
"TEAMCHANGE",
"CLEARSCORES",
"LOGIN",
"VERIFIED",
"RANDOMSEED",
"RUNSOC",
"REQADDFILE",
"DELFILE",
"SETMOTD",
"SUICIDE",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
#endif
};
// =========================================================================
// SERVER STARTUP
// =========================================================================
@ -3960,7 +3989,7 @@ static void Command_Archivetest_f(void)
}
// assign mobjnum
i = 0;
i = 1;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
((mobj_t *)th)->mobjnum = i++;

View File

@ -162,6 +162,8 @@ typedef enum
MAXNETXCMD
} netxcmd_t;
extern const char *netxcmdnames[MAXNETXCMD - 1];
#if defined(_MSC_VER)
#pragma pack(1)
#endif

View File

@ -62,34 +62,37 @@
#include <errno.h>
static void SendFile(INT32 node, const char *filename, UINT8 fileid);
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
// sender structure
// Sender structure
typedef struct filetx_s
{
INT32 ram;
char *filename; // name of the file or ptr of the data in ram
UINT32 size;
union {
char *filename; // Name of the file
char *ram; // Pointer to the data in RAM
} id;
UINT32 size; // Size of the file
UINT8 fileid;
INT32 node; // destination
struct filetx_s *next; // a queue
INT32 node; // Destination
struct filetx_s *next; // Next file in the list
} filetx_t;
// current transfers (one for each node)
// Current transfers (one for each node)
typedef struct filetran_s
{
filetx_t *txlist;
UINT32 position;
FILE *currentfile;
filetx_t *txlist; // Linked list of all files for the node
UINT32 position; // The current position in the file
FILE *currentfile; // The file currently being sent/received
} filetran_t;
static filetran_t transfer[MAXNETNODES];
// read time of file: stat _stmtime
// write time of file: utime
// Read time of file: stat _stmtime
// Write time of file: utime
// receiver structure
INT32 fileneedednum;
fileneeded_t fileneeded[MAX_WADFILES];
// Receiver structure
INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
char downloaddir[256] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN
@ -100,6 +103,7 @@ INT32 lastfilenum = 0;
/** Fills a serverinfo packet with information about wad files loaded.
*
* \todo Give this function a better name since it is in global scope.
*
*/
UINT8 *PutFileNeeded(void)
{
@ -111,19 +115,19 @@ UINT8 *PutFileNeeded(void)
for (i = 0; i < numwadfiles; i++)
{
// if it has only music/sound lumps, mark it as unimportant
// If it has only music/sound lumps, mark it as unimportant
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
filestatus = 0;
else
filestatus = 1; // important
filestatus = 1; // Important
// Store in the upper four bits
if (!cv_downloading.value)
filestatus += (2 << 4); // won't send
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
filestatus += (0 << 4); // won't send
filestatus += (0 << 4); // Won't send
else
filestatus += (1 << 4); // will send if requested
filestatus += (1 << 4); // Will send if requested
bytesused += (nameonlylength(wadfilename) + 22);
@ -144,7 +148,12 @@ UINT8 *PutFileNeeded(void)
return p;
}
// parse the serverinfo packet and fill fileneeded table on client
/** Parses the serverinfo packet and fills the fileneeded table on client
*
* \param fileneedednum_parm The number of files needed to join the server
* \param fileneededstr The memory block containing the list of needed files
*
*/
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
{
INT32 i;
@ -155,14 +164,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
p = (UINT8 *)fileneededstr;
for (i = 0; i < fileneedednum; i++)
{
fileneeded[i].status = FS_NOTFOUND;
filestatus = READUINT8(p);
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].important = (UINT8)(filestatus & 3);
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p);
fileneeded[i].phandle = NULL;
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
READMEM(p, fileneeded[i].md5sum, 16);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
}
}
@ -171,13 +180,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
fileneedednum = 1;
fileneeded[0].status = FS_REQUESTED;
fileneeded[0].totalsize = UINT32_MAX;
fileneeded[0].phandle = NULL;
fileneeded[0].file = NULL;
memset(fileneeded[0].md5sum, 0, 16);
strcpy(fileneeded[0].filename, tmpsave);
}
/** Checks the server to see if we CAN download all the files,
* before starting to create them and requesting.
*
* \return True if we can download all the files
*
*/
boolean CL_CheckDownloadable(void)
{
@ -239,8 +251,12 @@ boolean CL_CheckDownloadable(void)
return false;
}
/** Send requests for files in the ::fileneeded table with a status of
/** Sends requests for files in the ::fileneeded table with a status of
* ::FS_NOTFOUND.
*
* \return True if the packet was successfully sent
* \note Sends a PT_REQUESTFILE packet
*
*/
boolean CL_SendRequestFile(void)
{
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
SendFile(node, wad, id);
SV_SendFile(node, wad, id);
}
}
// client check if the fileneeded aren't already loaded or on the disk
/** Checks if the files needed aren't already loaded or on the disk
*
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
*
*/
INT32 CL_CheckFiles(void)
{
INT32 i, j;
@ -333,7 +355,7 @@ INT32 CL_CheckFiles(void)
}
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
{
// unimportant on our side. still don't care.
// Unimportant on our side. still don't care.
++j;
continue;
}
@ -343,11 +365,11 @@ INT32 CL_CheckFiles(void)
if (i >= fileneedednum || j >= numwadfiles)
return 2;
// for the sake of speed, only bother with a md5 check
// For the sake of speed, only bother with a md5 check
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
return 2;
// it's accounted for! let's keep going.
// It's accounted for! let's keep going.
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
fileneeded[i].status = FS_OPEN;
++i;
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
{
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// check in allready loaded files
// Check in already loaded files
for (j = 1; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
return ret;
}
// load it now
// Load it now
void CL_LoadServerFiles(void)
{
INT32 i;
@ -394,7 +416,7 @@ void CL_LoadServerFiles(void)
for (i = 1; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
continue; // already loaded
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename, NULL);
@ -423,133 +445,200 @@ void CL_LoadServerFiles(void)
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
}
else if (fileneeded[i].important)
I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
fileneeded[i].status);
{
const char *s;
switch(fileneeded[i].status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_REQUESTED:
s = "FS_REQUESTED";
break;
case FS_DOWNLOADING:
s = "FS_DOWNLOADING";
break;
default:
s = "unknown";
break;
}
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
fileneeded[i].status, s);
}
}
}
// little optimization to test if there is a file in the queue
static INT32 filetosend = 0;
// Number of files to send
// Little optimization to quickly test if there is a file in the queue
static INT32 filestosend = 0;
static void SendFile(INT32 node, const char *filename, UINT8 fileid)
/** Adds a file to the file list for a node
*
* \param node The node to send the file to
* \param filename The file to send
* \param fileid ???
* \sa SV_SendRam
*
*/
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{
filetx_t **q;
filetx_t *p;
filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request
INT32 i;
char wadfilename[MAX_WADPATH];
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
// Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
if (p)
memset(p, 0, sizeof (filetx_t));
else
I_Error("SendFile: No more ram\n");
p->filename = (char *)malloc(MAX_WADPATH);
if (!p->filename)
I_Error("SendFile: No more ram\n");
if (!p)
I_Error("SV_SendFile: No more memory\n");
// a minimum of security, can get only file in srb2 direcory
strlcpy(p->filename, filename, MAX_WADPATH);
nameonly(p->filename);
// Initialise with zeros
memset(p, 0, sizeof (filetx_t));
// check first in wads loaded the majority of case
// Allocate the file name
p->id.filename = (char *)malloc(MAX_WADPATH);
if (!p->id.filename)
I_Error("SV_SendFile: No more memory\n");
// Set the file name and get rid of the path
strlcpy(p->id.filename, filename, MAX_WADPATH);
nameonly(p->id.filename);
// Look for the requested file through all loaded files
for (i = 0; wadfiles[i]; i++)
{
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
nameonly(wadfilename);
if (!stricmp(wadfilename, p->filename))
if (!stricmp(wadfilename, p->id.filename))
{
// copy filename with full path
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
// Copy file name with full path
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
break;
}
}
// Handle non-loaded file requests
if (!wadfiles[i])
{
DEBFILE(va("%s not found in wadfiles\n", filename));
// this formerly checked if (!findfile(p->filename, NULL, true))
// This formerly checked if (!findfile(p->id.filename, NULL, true))
// not found
// don't inform client (probably hacker)
// Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
DEBFILE(va("Client %d request %s: not found\n", node, filename));
free(p->filename);
free(p->id.filename);
free(p);
*q = NULL;
return;
}
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// too big
// don't inform client (client sucks, man)
// Too big
// Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
free(p->filename);
free(p->id.filename);
free(p);
*q = NULL;
return;
}
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
p->ram = SF_FILE;
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
p->fileid = fileid;
p->next = NULL; // end of list
filetosend++;
p->next = NULL; // End of list
filestosend++;
}
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
/** Adds a memory block to the file list for a node
*
* \param node The node to send the memory block to
* \param data The memory block to send
* \param size The size of the block in bytes
* \param freemethod How to free the block after it has been sent
* \param fileid ???
* \sa SV_SendFile
*
*/
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
{
filetx_t **q;
filetx_t *p;
filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
// Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
if (p)
memset(p, 0, sizeof (filetx_t));
else
I_Error("SendRam: No more ram\n");
p->ram = freemethod;
p->filename = data;
if (!p)
I_Error("SV_SendRam: No more memory\n");
// Initialise with zeros
memset(p, 0, sizeof (filetx_t));
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
p->id.ram = data;
p->size = (UINT32)size;
p->fileid = fileid;
p->next = NULL; // end of list
p->next = NULL; // End of list
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
filetosend++;
filestosend++;
}
static void EndSend(INT32 node)
/** Stops sending a file for a node, and removes the file request from the list,
* either because the file has been fully sent or because the node was disconnected
*
* \param node The destination
*
*/
static void SV_EndFileSend(INT32 node)
{
filetx_t *p = transfer[node].txlist;
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
switch (p->ram)
{
case SF_FILE:
case SF_FILE: // It's a file, close it and free its filename
if (transfer[node].currentfile)
fclose(transfer[node].currentfile);
free(p->filename);
free(p->id.filename);
break;
case SF_Z_RAM:
Z_Free(p->filename);
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
Z_Free(p->id.ram);
break;
case SF_RAM:
free(p->filename);
case SF_NOFREERAM:
case SF_RAM: // It's a memory block allocated with malloc, use free
free(p->id.ram);
case SF_NOFREERAM: // Nothing to free
break;
}
// Remove the file request from the list
transfer[node].txlist = p->next;
transfer[node].currentfile = NULL;
free(p);
filetosend--;
// Indicate that the transmission is over
transfer[node].currentfile = NULL;
filestosend--;
}
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
void FiletxTicker(void)
/** Handles file transmission
*
*
*/
void SV_FileSendTicker(void)
{
static INT32 currentnode = 0;
filetx_pak *p;
@ -557,12 +646,12 @@ void FiletxTicker(void)
filetx_t *f;
INT32 packetsent = PACKETPERTIC, ram, i;
if (!filetosend)
if (!filestosend)
return;
if (!packetsent)
packetsent++;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filetosend != 0)
while (packetsent-- && filestosend != 0)
{
for (i = currentnode, ram = 0; ram < MAXNETNODES;
i = (i+1) % MAXNETNODES, ram++)
@ -571,24 +660,25 @@ void FiletxTicker(void)
goto found;
}
// no transfer to do
I_Error("filetosend=%d but no filetosend found\n", filetosend);
I_Error("filestosend=%d but no file to send found\n", filestosend);
found:
currentnode = (i+1) % MAXNETNODES;
f = transfer[i].txlist;
ram = f->ram;
if (!transfer[i].currentfile) // file not already open
// Open the file if it isn't open yet, or
if (!transfer[i].currentfile)
{
if (!ram)
if (!ram) // Sending a file
{
long filesize;
transfer[i].currentfile =
fopen(f->filename, "rb");
fopen(f->id.filename, "rb");
if (!transfer[i].currentfile)
I_Error("File %s does not exist",
f->filename);
f->id.filename);
fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile);
@ -596,45 +686,48 @@ void FiletxTicker(void)
// Nobody wants to transfer a file bigger
// than 4GB!
if (filesize >= LONG_MAX)
I_Error("filesize of %s is too large", f->filename);
if (-1 == filesize)
I_Error("Error getting filesize of %s", f->filename);
I_Error("filesize of %s is too large", f->id.filename);
if (filesize == -1)
I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET);
}
else
transfer[i].currentfile = (FILE *)1;
else // Sending RAM
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
transfer[i].position = 0;
}
// Build a packet containing a file fragment
p = &netbuffer->u.filetxpak;
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
if (f->size-transfer[i].position < size)
size = f->size-transfer[i].position;
if (ram)
M_Memcpy(p->data, &f->filename[transfer[i].position], size);
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
p->position = LONG(transfer[i].position);
// put flag so receiver know the totalsize
// Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
p->position |= LONG(0x80000000);
p->fileid = f->fileid;
p->size = SHORT((UINT16)size);
netbuffer->packettype = PT_FILEFRAGMENT;
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
{ // not sent for some odd reason, retry at next call
if (!ram)
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
// exit the while (can't send this one so why should i send the next?)
break;
// Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
{ // Success
transfer[i].position = (UINT32)(transfer[i].position + size);
if (transfer[i].position == f->size) // Finish?
SV_EndFileSend(i);
}
else // success
{
transfer[i].position = (UINT32)(size+transfer[i].position);
if (transfer[i].position == f->size) // finish ?
EndSend(i);
else
{ // Not sent for some odd reason, retry at next call
if (!ram)
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
// Exit the while (can't send this one so why should i send the next?)
break;
}
}
}
@ -646,16 +739,18 @@ void Got_Filetxpak(void)
if (filenum >= fileneedednum)
{
DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
return;
}
if (fileneeded[filenum].status == FS_REQUESTED)
{
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
if (fileneeded[filenum].file)
I_Error("Got_Filetxpak: already open file\n");
fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb");
if (!fileneeded[filenum].file)
I_Error("Can't create file %s: %s", fileneeded[filenum].filename, strerror(errno));
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
fileneeded[filenum].currentsize = 0;
fileneeded[filenum].status = FS_DOWNLOADING;
}
@ -664,24 +759,24 @@ void Got_Filetxpak(void)
{
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
// use a special tric to know when file is finished (not allways used)
// WARNING: filepak can arrive out of order so don't stop now !
// Use a special trick to know when the file is complete (not always used)
// WARNING: file fragments can arrive out of order so don't stop yet!
if (pos & 0x80000000)
{
pos &= ~0x80000000;
fileneeded[filenum].totalsize = pos + size;
}
// we can receive packet in the wrong order, anyway all os support gaped file
fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
// We can receive packet in the wrong order, anyway all os support gaped file
fseek(fileneeded[filenum].file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1)
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file)));
fileneeded[filenum].currentsize += size;
// finished?
// Finished?
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
{
fclose(fileneeded[filenum].phandle);
fileneeded[filenum].phandle = NULL;
fclose(fileneeded[filenum].file);
fileneeded[filenum].file = NULL;
fileneeded[filenum].status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
fileneeded[filenum].filename);
@ -689,8 +784,8 @@ void Got_Filetxpak(void)
}
else
I_Error("Received a file not requested\n");
// send ack back quickly
// Send ack back quickly
if (++filetime == 3)
{
Net_SendAcks(servernode);
@ -702,33 +797,39 @@ void Got_Filetxpak(void)
#endif
}
void AbortSendFiles(INT32 node)
/** Cancels all file requests for a node
*
* \param node The destination
* \sa SV_EndFileSend
*
*/
void SV_AbortSendFiles(INT32 node)
{
while (transfer[node].txlist)
EndSend(node);
SV_EndFileSend(node);
}
void CloseNetFile(void)
{
INT32 i;
// is sending?
// Is sending?
for (i = 0; i < MAXNETNODES; i++)
AbortSendFiles(i);
SV_AbortSendFiles(i);
// receiving a file?
// Receiving a file?
for (i = 0; i < MAX_WADFILES; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{
fclose(fileneeded[i].phandle);
// file is not complete delete it
fclose(fileneeded[i].file);
// File is not complete delete it
remove(fileneeded[i].filename);
}
// remove FILEFRAGMENT from acknledge list
// Remove PT_FILEFRAGMENT from acknowledge list
Net_AbortPacketType(PT_FILEFRAGMENT);
}
// functions cut and pasted from doomatic :)
// Functions cut and pasted from Doomatic :)
void nameonly(char *s)
{

View File

@ -29,21 +29,21 @@ typedef enum
FS_FOUND,
FS_REQUESTED,
FS_DOWNLOADING,
FS_OPEN, // is opened and used in w_wad
FS_OPEN, // Is opened and used in w_wad
FS_MD5SUMBAD
} filestatus_t;
typedef struct
{
UINT8 important;
UINT8 willsend; // is the server willing to send it?
UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH];
UINT8 md5sum[16];
// used only for download
FILE *phandle;
// Used only for download
FILE *file;
UINT32 currentsize;
UINT32 totalsize;
filestatus_t status; // the value returned by recsearch
filestatus_t status; // The value returned by recsearch
} fileneeded_t;
extern INT32 fileneedednum;
@ -58,28 +58,24 @@ UINT8 *PutFileNeeded(void);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
void CL_PrepareDownloadSaveGame(const char *tmpsave);
// check file list in wadfiles return 0 when a file is not found
// 1 if all file are found
// 2 if you cannot connect (different wad version or
// no enought space to download files)
INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void);
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid);
void FiletxTicker(void);
void SV_FileSendTicker(void);
void Got_Filetxpak(void);
boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void);
void Got_RequestFilePak(INT32 node);
void AbortSendFiles(INT32 node);
void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void);
boolean fileexist(char *filename, time_t ptime);
// search a file in the wadpath, return FS_FOUND when found
// Search a file in the wadpath, return FS_FOUND when found
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);

View File

@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (gr_backsector)
{
INT32 gr_toptexture, gr_bottomtexture;
// two sided line
if (gr_backsector->heightsec != -1)
{
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
}
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
// check TOP TEXTURE
if ((
#ifdef ESLOPE
worldhighslope < worldtopslope ||
#endif
worldhigh < worldtop
) && texturetranslation[gr_sidedef->toptexture])
) && gr_toptexture)
{
if (drawtextured)
{
fixed_t texturevpegtop; // top
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
grTex = HWR_GetTexture(gr_toptexture);
// PEGGING
if (gr_linedef->flags & ML_DONTPEGTOP)
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegtop += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS;
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#ifdef ESLOPE
worldlowslope > worldbottomslope ||
#endif
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
{
if (drawtextured)
{
fixed_t texturevpegbottom = 0; // bottom
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
grTex = HWR_GetTexture(gr_bottomtexture);
// PEGGING
#ifdef ESLOPE
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegbottom += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS;
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
FBITFIELD blendmode;
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else
{
// Single sided line... Deal only with the middletexture (if one exists)
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
if (drawtextured)
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE //backsides
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;

View File

@ -790,6 +790,14 @@ boolean HU_Responder(event_t *ev)
}
else // if chat_on
{
// Ignore modifier keys
// Note that we do this here so users can still set
// their chat keys to one of these, if they so desire.
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
return true;
c = (UINT8)ev->data1;
// use console translations

View File

@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
case sector_ceilingheight:
lua_pushfixed(L, sector->ceilingheight);
return 1;
case sector_floorpic: { // floorpic
levelflat_t *levelflat;
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
case sector_floorpic: // floorpic
lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
return 1;
}
case sector_ceilingpic: { // ceilingpic
levelflat_t *levelflat;
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
case sector_ceilingpic: // ceilingpic
lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
return 1;
}
case sector_lightlevel:
lua_pushinteger(L, sector->lightlevel);
return 1;
@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
return 0;
}
// help function for P_LoadSectors, find a flat in the active wad files,
// allocate an id for it, and set the levelflat (to speedup search)
//
static INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
static int sector_set(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));

View File

@ -46,41 +46,6 @@ typedef INT32 fixed_t;
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
/** \brief The TMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\param e a parameter of type fixed_t
\param f a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
+ ((INT64)e * (INT64)f)) >> 16); \
}
/** \brief The DMulScale16 function
\param a a parameter of type fixed_t
\param b a parameter of type fixed_t
\param c a parameter of type fixed_t
\param d a parameter of type fixed_t
\return fixed_t
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
{ \
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
}
#if defined (__WATCOMC__) && FRACBITS == 16
#pragma aux FixedMul = \
"imul ebx", \
@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part
const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x != INT32_MIN)
return x-f; // return largest integral value not greater than argument
{ // return rounded down to nearest whole number
if (x > 0)
return x-f;
else
return x-(FRACUNIT-f);
}
return INT32_MIN;
}
@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part
const fixed_t f = a-i; // cut out the integral part
if (x != INT32_MIN)
{ // return rounded to nearest whole number, towards zero
if (x > 0)
@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part
const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN)
return INT32_MIN;
else if (x < FixedFloor(INT32_MAX))
return x+(FRACUNIT-f); // return smallest integral value not less than argument
{ // return rounded up to nearest whole number
if (x > 0)
return x+(FRACUNIT-f);
else
return x+f;
}
return INT32_MAX;
}
@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part
const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN)
return INT32_MIN;
else if (x < FixedFloor(INT32_MAX))

View File

@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight;
fixed_t texmid, delta1, delta2;
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
// Get the midtexture's height
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
if (texnum) {
// Get the midtexture's height
texheight = textures[texnum]->height << FRACBITS;
// Set texbottom and textop to the Z coordinates of the texture's boundaries
// Set texbottom and textop to the Z coordinates of the texture's boundaries
#if 0 // #ifdef POLYOBJECTS
// don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
} else
// don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
} else
#endif
{
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = openbottom + side->rowoffset;
textop = opentop + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = openbottom + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = opentop + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
{
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = openbottom + side->rowoffset;
textop = opentop + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = openbottom + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = opentop + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
}
}
texmid = texbottom+(textop-texbottom)/2;
texmid = texbottom+(textop-texbottom)/2;
delta1 = abs(mobj->z - texmid);
delta2 = abs(thingtop - texmid);
delta1 = abs(mobj->z - texmid);
delta2 = abs(thingtop - texmid);
if (delta1 > delta2) { // Below
if (opentop > texbottom)
opentop = texbottom;
} else { // Above
if (openbottom < textop)
openbottom = textop;
if (delta1 > delta2) { // Below
if (opentop > texbottom)
opentop = texbottom;
} else { // Above
if (openbottom < textop)
openbottom = textop;
}
}
}

View File

@ -519,10 +519,9 @@ static void P_NetArchiveWorld(void)
//
// flats
//
// P_AddLevelFlat should not add but just return the number
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
diff |= SD_FLOORPIC;
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
diff |= SD_CEILPIC;
if (ss->lightlevel != SHORT(ms->lightlevel))
@ -762,12 +761,12 @@ static void P_NetUnArchiveWorld(void)
sectors[i].ceilingheight = READFIXED(get);
if (diff & SD_FLOORPIC)
{
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
get += 8;
}
if (diff & SD_CEILPIC)
{
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
get += 8;
}
if (diff & SD_LIGHT)
@ -3306,7 +3305,7 @@ void P_SaveNetGame(void)
{
thinker_t *th;
mobj_t *mobj;
INT32 i = 0;
INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
CV_SaveNetVars(&save_p);
P_NetArchiveMisc();

View File

@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
return (INT32)i;
}
// help function for Lua and $$$.sav reading
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
// help function for $$$.sav checking
// this simply returns the flat # for the name given
//
INT32 P_CheckLevelFlat(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
if (i == numlevelflats)
return 0; // ??? flat was not found, this should not happen!
// level flat id
return (INT32)i;
}
static void P_LoadSectors(lumpnum_t lumpnum)
{
UINT8 *data;

View File

@ -47,6 +47,8 @@ typedef struct
extern size_t numlevelflats;
extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
INT32 P_AddLevelFlatRuntime(const char *flatname);
INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings;
extern mapthing_t *mapthings;

View File

@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
static sector_t tempsec; // Deep water hack
extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap;
fixed_t floorcenterz, ceilingcenterz;
#ifdef RANGECHECK
if (num >= numsubsectors)
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors)
{
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
sub->sector->moved = frontsector->moved = false;
}
light = R_GetPlaneLight(frontsector,
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight, false);
light = R_GetPlaneLight(frontsector, floorcenterz, false);
if (frontsector->floorlightsec == -1)
floorlightlevel = *frontsector->lightlist[light].lightlevel;
floorcolormap = frontsector->lightlist[light].extra_colormap;
light = R_GetPlaneLight(frontsector,
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight, false);
light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
if (frontsector->ceilinglightsec == -1)
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
{
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, frontsector->f_slope
#endif
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, frontsector->c_slope
#endif
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
if (frontsector->ffloors)
{
ffloor_t *rover;
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
{
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
ffloor[numffloors].polyobj = NULL;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
heightcheck =
#ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, *rover->b_slope
#endif
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, *rover->t_slope
#endif
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL;
if (polysec->floorheight <= frontsector->ceilingheight
&& polysec->floorheight >= frontsector->floorheight
if (polysec->floorheight <= ceilingcenterz
&& polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight))
{
fixed_t xoff, yoff;
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
polysec->floorpic_angle-po->angle,
NULL,
NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po;
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
if (polysec->ceilingheight >= frontsector->floorheight
&& polysec->ceilingheight <= frontsector->ceilingheight
if (polysec->ceilingheight >= floorcenterz
&& polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight))
{
fixed_t xoff, yoff;
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
NULL, NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight;

View File

@ -360,6 +360,32 @@ done:
return blocktex;
}
//
// R_GetTextureNum
//
// Returns the actual texture id that we should use.
// This can either be texnum, the current frame for texnum's anim (if animated),
// or 0 if not valid.
//
INT32 R_GetTextureNum(INT32 texnum)
{
if (texnum < 0 || texnum >= numtextures)
return 0;
return texturetranslation[texnum];
}
//
// R_CheckTextureCache
//
// Use this if you need to make sure the texture is cached before R_GetColumn calls
// e.g.: midtextures and FOF walls
//
void R_CheckTextureCache(INT32 tex)
{
if (!texturecache[tex])
R_GenerateTexture(tex);
}
//
// R_GetColumn
//

View File

@ -67,6 +67,9 @@ extern CV_PossibleValue_t Color_cons_t[];
void R_LoadTextures(void);
void R_FlushTextureCache(void);
INT32 R_GetTextureNum(INT32 texnum);
void R_CheckTextureCache(INT32 tex);
// Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col);

View File

@ -203,6 +203,7 @@ typedef struct r_lightlist_s
fixed_t heightstep;
fixed_t botheight;
fixed_t botheightstep;
fixed_t startheight; // for repeating midtextures
INT16 lightlevel;
extracolormap_t *extra_colormap;
lighttable_t *rcolormap;
@ -224,15 +225,6 @@ typedef struct linechain_s
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
typedef struct secplane_t
{
// the plane is defined as a*x + b*y + c*z + d = 0
// ic is 1/c, for faster Z calculations
fixed_t a, b, c, d, ic;
} secplane_t;
// Slopes
#ifdef ESLOPE
typedef enum {

View File

@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y);
}
/***************************************
*** Zdoom C++ to Legacy C conversion ***
****************************************/
// Utility to find the Z height at an XY location in a sector (for slopes)
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
{
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
}
// Returns the value of z at (x,y) if d is equal to dist
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
{
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
}
// Flips the plane's vertical orientiation, so that if it pointed up,
// it will point down, and vice versa.
void R_SecplaneFlipVert(secplane_t *secplane)
{
secplane->a = -secplane->a;
secplane->b = -secplane->b;
secplane->c = -secplane->c;
secplane->d = -secplane->d;
secplane->ic = -secplane->ic;
}
// Returns true if 2 planes are the same
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
{
return original->a == other->a && original->b == other->b
&& original->c == other->c && original->d == other->d;
}
// Returns true if 2 planes are different
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
{
return original->a != other->a || original->b != other->b
|| original->c != other->c || original->d != other->d;
}
// Moves a plane up/down by hdiff units
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
{
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
}
// Returns how much this plane's height would change if d were set to oldd
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
{
return FixedMul(oldd - secplane->d, secplane->ic);
}
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
}
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
}
//
// R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span)

View File

@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_PointToDist(fixed_t x, fixed_t y);
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
// ZDoom C++ to Legacy C conversion Tails 04-29-2002
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
fixed_t dist);
void R_SecplaneFlipVert(secplane_t *secplane);
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);

View File

@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE
, pslope_t *slope
#endif
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef POLYOBJECTS_PLANES
if (check->polyobj && pfloor)
continue;
if (polyobj != check->polyobj)
continue;
#endif
if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
check->viewangle = viewangle;
check->plangle = plangle;
#ifdef POLYOBJECTS_PLANES
check->polyobj = NULL;
check->polyobj = polyobj;
#endif
#ifdef ESLOPE
check->slope = slope;
@ -720,7 +725,11 @@ void R_DrawPlanes(void)
continue;
}
if (pl->ffloor != NULL)
if (pl->ffloor != NULL
#ifdef POLYOBJECTS_PLANES
|| pl->polyobj != NULL
#endif
)
continue;
R_DrawSinglePlane(pl);

View File

@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE
, pslope_t *slope
#endif

View File

@ -309,7 +309,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
curline = ds->curline;
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = texturetranslation[curline->sidedef->midtexture];
texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9)
@ -353,6 +353,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
@ -408,6 +411,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = light->extra_colormap;
rlight->flags = light->flags;
@ -501,6 +505,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
if (dc_numlights)
{ // reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
}
#ifndef ESLOPE
@ -771,7 +783,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline;
backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = wallcolfunc;
@ -779,7 +791,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
if (pfloor->flags & FF_TRANSLUCENT)
@ -1049,6 +1061,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid += offsetvalue;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes)
@ -1969,14 +1984,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!backsector)
{
fixed_t texheight;
// single sided line
midtexture = texturetranslation[sidedef->midtexture];
midtexture = R_GetTextureNum(sidedef->midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
#ifdef ESLOPE
if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM)
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else
rw_midtexturemid = frontsector->ceilingheight - viewz;
}
@ -1985,10 +2002,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (linedef->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide;
#else
vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom
rw_midtexturemid = vtop - viewz;
#endif
@ -2220,76 +2237,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#endif
)
{
fixed_t texheight;
// top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff)
{
// Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]];
toptexture = texturetranslation[def->toptexture];
toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = texturetranslation[sidedef->toptexture];
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[def->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
else
{
toptexture = texturetranslation[sidedef->toptexture];
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + texheight;
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + texheight;
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
}
}
// check BOTTOM TEXTURE
@ -2300,7 +2291,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
) //seulement si VISIBLE!!!
{
// bottom texture
bottomtexture = texturetranslation[sidedef->bottomtexture];
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@ -2585,7 +2576,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i;
}
if (sidedef->midtexture)
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{
// masked midtexture
if (!ds_p->thicksidecol)
@ -3197,12 +3188,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
}
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
{
ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
}
ds_p++;
}

View File

@ -1885,21 +1885,25 @@ static void R_CreateDrawNodes(void)
entry->ffloor = ds->thicksides[i];
}
}
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
plane = ds->curline->polyseg->visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
;
else {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
entry->seg = ds;
}
ds->curline->polyseg->visplane = NULL;
}
#endif
if (ds->maskedtexturecol)
{
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = ds->curline->polyseg->visplane;
entry->seg = ds;
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
ds->curline->polyseg->visplane = NULL;
}
#endif
entry = R_CreateDrawNode(&nodehead);
entry->seg = ds;
}
@ -1942,6 +1946,29 @@ static void R_CreateDrawNodes(void)
}
}
#ifdef POLYOBJECTS_PLANES
// find all the remaining polyobject planes and add them on the end of the list
// probably this is a terrible idea if we wanted them to be sorted properly
// but it works getting them in for now
for (i = 0; i < numPolyObjects; i++)
{
if (!PolyObjects[i].visplane)
continue;
plane = PolyObjects[i].visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
{
PolyObjects[i].visplane = NULL;
continue;
}
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
// note: no seg is set, for what should be obvious reasons
PolyObjects[i].visplane = NULL;
}
#endif
if (visspritecount == 0)
return;
@ -1998,13 +2025,16 @@ static void R_CreateDrawNodes(void)
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
for (i = x1; i <= x2; i++)
if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
{
if (r2->seg->frontscale[i] > rover->sortscale)
break;
for (i = x1; i <= x2; i++)
{
if (r2->seg->frontscale[i] > rover->sortscale)
break;
}
if (i > x2)
continue;
}
if (i > x2)
continue;
entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry;