Forum archive
Development (multiple RTS): sending a string to other users to process it & bugs
- Hello,
I´ve been programming since the last week, based on the source code of jONOF. I´m very anxious to test a new approach, that is, multiple RTS support :). Its a very ancient dream of mine. You can have up to 100 RTS files in one dir, and when pressed ALT+F11, everyone will change their RTS automatically (in a transparent mode, of course), based on the person which activated ALT+F11.
The problem is, if a given person has different RTS, I would like to let him listen nothing at all, except when the user which activated ALT+F11 sent the filename that is equal to him (matching RTS). For this to work, I have to send the actual filename I´m listening on, at every ALT+F11 call (like ´NOW HEARING DUKE2.RTS´ -> so I send the string "DUKE2.RTS" and the user will receive this info and COMPARE with their list (also a tempRTS.dat will be there, as its updated at every game start).
In other words, if I press ALT+F11, the next RTS, being loaded for me, must be sent to the other users (only the name, because they are supposed to have it. It not, they listen nothing at all. I know how to receive information by ´getpackets()'; But I dont understand how to handle the sendpacket, in the second IF inside 'if( SHIFTS_IS_PRESSED || ALT_IS_PRESSED )´ area, around line 6510~6550 of game.c.
There it is:
-----------------------
for(ch=connecthead;ch>=0;ch=connectpoint2[ch])
{
if (ch != myconnectindex) sendpacket(ch,tempbuf,i);
if ((!networkmode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
}
-------------------------------
The problem is, how to use myconnectindex in order to send the correct info and then catch it? and how about tempbuf? I´ve spent more than 2 hours only in these lines, but to no avail :-[ That´s because game.c also includes network coding.
Thanks really :) Some info is greatly appreciated. Until now, the RTS files must be equal for all users for this to work (and worse, EVERYONE must press ALT+F11), because this code above only send the SOUND, not the keypresses.
:'(
IvanEdited by ivanrolim at Re: Development question: sending a string to other users to process it
Here, I use this code to send the filename of usermaps in multiplayer in EDuke32:
void sendboardname(void)
{
if (ud.multimode > 1)
{
int j;
int ch;
tempbuf[0] = 9;
tempbuf[1] = 0;
j = Bstrlen(boardfilename);
boardfilename[j] = 0;
Bstrcat(tempbuf+1,boardfilename);
for (ch=connecthead;ch >= 0;ch=connectpoint2[ch])
{
if (ch != myconnectindex) sendpacket(ch,tempbuf,j+1);
if ((!networkmode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
}
}
}
void getpackets(void)
{
...
case 9:
//slaves in M/S mode only send to master
if (myconnectindex == connecthead)
{
//Master re-transmits message to all others
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
if (i != other)
sendpacket(i,packbuf,packbufleng);
}
Bstrcpy(boardfilename,packbuf+1);
boardfilename[packbufleng-1] = 0;
if (boardfilename[0] != 0)
{
if ((i = kopen4load(boardfilename,0)) < 0)
{
Bmemset(boardfilename,0,sizeof(boardfilename));
sendboardname();
}
else kclose(i);
}
if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0)
ud.m_level_number = 0;
break;
...- Thank you really, TX :)
I´ve been trying out this two pieces of code to send only the name of the RTS (to compare to):
'if i=11' tell that if the user press ALT+F11 it will SEND the filename NAME (not its contents) to tempbufRTS (a string
with 50 positions). But I think I´m not supposed to use Bstrcpy nor Bstrcmp because its used in boardnames (files that is opened and read), I can guess.
RTSActualFile is a short int (only to point to the RTSFileList[51][513], that is, the actual file listed into it. It supports up to 512 RTS files with 50 chars each (hmm not so needed because DOS file names is 8:3). Anyway, RTSFileList is populated with a temp file (its already working), tempRTS.dat. Its a list file, like:
--------------
DUKE.RTS
SUPER.RTS
JAMES.RTS
ASTRO.RTS
--------------
(It has a blank like due to sscanf.)
if(ud.lockout == 0)
if(SoundToggle && ALT_IS_PRESSED && ( RTS_NumSounds() > 0 ) && rtsplaying == 0 && VoiceToggle )
{
rtsptr = (char *)RTS_GetSound (i-1);
if(*rtsptr == 'C')
FX_PlayVOC3D( rtsptr,0,0,0,255,-i);
else FX_PlayWAV3D( rtsptr,0,0,0,255,-i);
rtsplaying = 7;
// Code change starts here
if(i == 11)
{ if (RTSActualFile < RTSFileLength ) RTSActualFile++;
if (RTSActualFile == RTSFileLength ) RTSActualFile=0;
//if, before filename changing, it gets to the last item, go back to the first in the array.
RTS_Init(RTSFileList[RTSActualFile]);
strcpy(&tempbuf[0], RTSFileList[RTSActualFile]);
strcpy(&fta_quotes[26][0],&tempbuf[0]);
FTA(26,&ps[myconnectindex]);
//these lines just tell the user the new RTS loaded (locally).
}
if(ud.multimode > 1)
{
tempbuf[0] = 7;
tempbuf[1] = i;
strcat(tempbuf+1,RTSFileList[RTSActualFile]);
//I send the filename as the remaining of tempbuf (tempbuf[2], tempbuf[3]..)
for(ch=connecthead;ch>=0;ch=connectpoint2[ch])
{
if(ch != myconnectindex) sendpacket(ch,tempbuf,53); //2 of the default tempbuf[1] and [2], + 50 chars (max size) of the filename
if ((!networkmode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
}
}
pus = NUMPAGES;
pub = NUMPAGES;
return;
}
The second code is in regard to the user receiving this information:
RTSActualFile is a INDEX (short)
case 7:
//slaves in M/S mode only send to master
//Master re-transmits message to all others
if ((!networkmode) && (myconnectindex == connecthead))
for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
if (i != other) sendpacket(i,packbuf,packbufleng);
if(numlumps == 0) break;
if (SoundToggle == 0 || ud.lockout == 1 || FXDevice < 0 )
break;
/////////////////////////RTS /////////////////////////////////////////
strcpy(tempbufRTS,packbuf+1);
//tempbufRTS[packbufleng-1] = 0;
//ALT+F11 was pressed in the other PC, but the RTSActualFile here didnt change yet.
for (RTSi=0; RTSi<=RTSFileLength;RTSi++)
//lets travel on the list for 1 cycle (RTSFileLength, that is, if I have 6 rts files, RTSFileLength is 5)
{
if (strcmp(RTSFileList[RTSi],tempbufRTS)!=0 )
{
if (RTSActualFile < RTSFileLength ) RTSActualFile++;
if (RTSActualFile == RTSFileLength ) RTSActualFile=0;
}
else //If the compare is equal, RTSActualFile is already pointing at it.
RTS_Init (RTSFileList[RTSActualFile]); //so this player will change its RTS.
}
if (strcmp(RTSFileList[RTSi],tempbufRTS)!=0)
{strcpy(&tempbuf[3], "RTS changed, but you dont have it");
strcpy(&fta_quotes[26][0],&tempbuf[3]);
FTA(26,&ps[myconnectindex]);
}
//////////////////////////////////////////////////////////
rtsptr = (char *)RTS_GetSound(packbuf[1]-1);
if (*rtsptr == 'C')
FX_PlayVOC3D(rtsptr,0,0,0,255,-packbuf[1]);
else
FX_PlayWAV3D(rtsptr,0,0,0,255,-packbuf[1]);
rtsplaying = 7;
break;
Thanks really :) This will be really a very interesting add on, so I´m gathering all my efforts to it :)Edited by ivanrolim at - Ok, I decided to use
strcpy(&tempbuf[3], tempbufRTS);
instead of
{strcpy(&tempbuf[3], "RTS changed, but you dont have it");
next to the end of the second code.
My pal is receiving
KE.SUPER.RTS
ER.JAMES.RTS
ES.ASTRO.RTS
So I only have to clean up tempbufRTS. I´m correcting this. :)
Update (1 hour later): YES!! Working! Soon I´ll be giving the patch to JONATHON and whoever wants it :) But I´m still working a bit with cosmetic updates (because you need to have CAPILIZED RTS.....like TEST, DUKE and JAMES, not James, james, TeSt.....) just a string update :)Edited by ivanrolim at - Well......... ::) After some days programming activelly to load and unload RTs due to a ´63 damned limit´, that is, the game crashes when I try to 'exchange' to a '63th' RTS (using original functions that uses kopenforload), I´ve made a function before ´RTS_INIT(filename)´, which tries to close the handle of the former RTS loaded. Thats because, in a long dukematch, we players can change 200, 400, 1000 times, nobody knows the amount of RTS repertories we want to use...
So This was created in an attempt to kill a given RTS From memory, and then load another with RTS_INIT (the default)
int32 RTS_RemoveFile (char *filename)
{
// We need to close the handle, free pointers, and so on
int32 length;
free (&lumpcache);
free (&length);
FX_StopAllSounds();
clearsoundlocks();
kclose (filename); //THIS CRASHES IMMEDIATELLY
return 0;
}
Before, I just tried with kclose. Of course, the game crashes due to a conflict, interruption error, memory locks and so on :(.
Now, even with clearsoundlocks(), and such, I get nowhere. If I have 6 RTS, and just use RTS_Init at every new file, the 63th action (ALT+F11), that changes them along a list more than 10 times, will cause the game to crash.
Perhaps someone have an idea how to handle this?
The functions that handle RTS are:
//RTS_Init call this function in the second function below
int32 RTS_AddFile (char *filename)
{
wadinfo_t header;
lumpinfo_t *lump_p;
uint32 i;
static int32 handle, length;
int32 startlump;
filelump_t *fileinfo, *fileinfoo;
// read the entire file in
// FIXME: shared opens
handle = kopen4load(filename, 0);
if (handle < 0) {
initprintf("Arquivo de RTS %s nao encontrado\n",filename);
return -1;
}
startlump = numlumps;
// WAD file
initprintf(" Adding RTS %s.\n",filename);
kread( handle, &header, sizeof( header ) );
if (strncmp(header.identification,"IWAD",4)) {
initprintf("RTS file %s does not have ID (WAD)\n",filename);
kclose(handle);
return -1;
}
header.numlumps = IntelLong(header.numlumps);
header.infotableofs = IntelLong(header.infotableofs);
length = header.numlumps*sizeof(filelump_t);
fileinfo = fileinfoo = (filelump_t*)malloc (length);
if (!fileinfo) {
initprintf("RTS - no header alocation\n");
kclose(handle);
return -1;
}
klseek (handle, header.infotableofs, SEEK_SET);
kread(handle, fileinfo, length);
// Fill in lumpinfo
lump_p = realloc(lumpinfo, (numlumps + header.numlumps)*sizeof(lumpinfo_t));
if (!lump_p) {
kclose(handle);
return -1;
}
lumpinfo = lump_p;
numlumps += header.numlumps;
lump_p = &lumpinfo[startlump];
for (i=startlump ; i<(uint32)numlumps ; i++,lump_p++, fileinfo++)
{
lump_p->handle = handle;
lump_p->position = IntelLong(fileinfo->filepos);
lump_p->size = IntelLong(fileinfo->size);
strncpy (lump_p->name, fileinfo->name, 8);
}
free(fileinfoo);
return 0;
}
/*
====================
= RTS_Init
= Files with a .rts extension are idlink files with multiple lumps
====================
*/
void RTS_Init (char *filename)
{
int32 length;
length=0; //I tried to include this to no avail
free(lumpcache); //I tried to include this to no avail
RTS_Started = false; //I tried to include this to no avail
// open all the files, load headers, and count lumps
numlumps = 0;
lumpinfo = NULL; // will be realloced as lumps are added
initprintf("Starting RTS manager.\n");
if (RTS_AddFile (filename)) return;
if (!numlumps) return;
//
// set up caching
//
length = (numlumps) * sizeof( *lumpcache );
lumpcache = malloc(length);
memset(lumpcache,0,length);
RTS_Started = true;
}
I have a clue about that memset. If I could kill/erase/free this area, RTS_Init might start a new clean RTS. free(lumpcache) appears not to work either.
Thanks, really. I´m not a C skilled programmer but I really need to close these new files properly :(Edited by ivanrolim at - Um, you should be passing kclose the handle of the file, not the filename. Of course it crashes...
- TX, I´ve also tried the correct way :(
int32 RTS_RemoveFile (char *filename)
{
//AEDUKE - Fechar a HANDLE existente
int32 length, handle;
free (&lumpcache);
free (&length);
FX_StopAllSounds();
clearsoundlocks();
kclose (handle);
Somethin *hidden* is eating up memory in RTS_Addfile. Even closing handles, freeing pointers and so on, the 63th RTS change is fatal: game crashes back to windows.
Of course I dont want to ´start a new RTS manager´ at every exchange, but rather than trying to use RTS_Addfile alone (which does not work due to some memory allocations), I preferred to try to close the main handlers and pointers and start the manager again. I´m still strugging agains this, and tonight I will make more efforts :)
Anyway, The duke3d.log says:
(more than 50 RTS calls with success)
.
.
.
Starting RTS manager.
Adding DUKE.RTS.
Starting RTS manager.
Adding JAMES.RTS.
Starting RTS manager.
Adding APOLLO.RTS.
Starting RTS manager.
Adding ASTRO.RTS.
Starting RTS manager.
Adding DUKE.RTS.
Starting RTS manager.
Adding JAMES.RTS.
Starting RTS manager.
Uninitialising DirectDraw... //a crash after 63th RTS
- Releasing DirectDraw object
- Unloading DDRAW.DLL
Uninitialising DirectInput...
- Releasing keyboard device
- Releasing mouse device
- Releasing DirectInput object
- Unloading DINPUT.DLL
I´ve already found the line that is culprit with a debugger:
"handle = kopen4load(filename, 0);"
Obviously, it´s opening a given filename with kpen4load for the 63th time. Hmm maybe handle is being appended! Anyway I dont like to suppose things, this is unprofessional, so I will be researching about the time that handle fatally receives a new kpen4load command for the 63th time! :oEdited by ivanrolim at Re: FIXED! ( I think)
Yes, I did it :)
But more tests are needed.
I will be releasing the file changes :)
game.c
rts.c
The changes involved a new function in rts.c:
int32 RTS_Substitute (char *filename)
{
wadinfo_t header;
lumpinfo_t *lump_p;
uint32 i;
int32 handle, length;
int32 startlump;
filelump_t *fileinfo, *fileinfoo;
numlumps = 0;
lumpinfo = NULL; // will be realloced as lumps are added
//without this, exchanging RTS files will lead to the SAME pointer and cache location (no RTS change)
// read the entire file in
// FIXME: shared opens
handle = RTSopen4load(filename, 0); //open a new RTS and allocate memory to it
//Here it used to crash at the 63th exchange because of a limit
//imposed by MAXOPENFILES. This functions try to be best at reallocating
//new info at the same handler!
if (handle < 0) {
initprintf("RTS %s not found\n",filename);
return -1;
}
startlump = numlumps;
// WAD file
initprintf(" Adding %s.\n",filename);
kread( handle, &header, sizeof( header ) );
if (strncmp(header.identification,"IWAD",4)) {
initprintf("RTS File %s does not have a id (WAD)\n",filename);
kclose(handle);
return -1;
}
header.numlumps = IntelLong(header.numlumps);
header.infotableofs = IntelLong(header.infotableofs);
length = header.numlumps*sizeof(filelump_t);
fileinfo = fileinfoo = (filelump_t*)malloc (length);
if (!fileinfo) {
initprintf("RTS file error - not header allocation\n");
kclose(handle);
return -1;
}
klseek (handle, header.infotableofs, SEEK_SET);
kread(handle, fileinfo, length);
//
// Fill in lumpinfo
//
lump_p = realloc(lumpinfo, (numlumps + header.numlumps)*sizeof(lumpinfo_t));
if (!lump_p) {
kclose(handle);
return -1;
}
lumpinfo = lump_p;
numlumps += header.numlumps;
lump_p = &lumpinfo[startlump];
for (i=startlump ; i<(uint32)numlumps ; i++,lump_p++, fileinfo++)
{
lump_p->handle = handle;
lump_p->position = IntelLong(fileinfo->filepos);
lump_p->size = IntelLong(fileinfo->size);
strncpy (lump_p->name, fileinfo->name, 8);
}
free(fileinfoo);
//
// reset up caching // I get it from RTS_INIT, because actually, RTS_Init called RTS_AddFIle and then used these below.
//
length = (numlumps) * sizeof( *lumpcache );
lumpcache = malloc(length);
memset(lumpcache,0,length);
return 0;
}
Of course, game.c also needed to be changed. I now call RTS_Substitute() rather than RTS_Init again and again, as done in the second post of myself. The last RTS_Init (next to the end of game.c) was kept untouched because when the game starts, the first RTS really need to be called this way for a proper...aaann..initialization of course :)Edited by ivanrolim at