r1ch.net forums
* Home Help Search Login Register
r1ch.net  |  General  |  General Discussion  |  Topic: Trying to fix the Siamese Twins problem...
Pages: 1 2 3 [All]
Print
Author Topic: Trying to fix the Siamese Twins problem...  (Read 37455 times)
hajas
Member

Posts: 44



« on: June 04, 2007, 11:43:15 am »

WTH is Siamese Twins problem?

in RA2 sometimes we have 2 or more players been spawned at the same spawnpoint, then they start glued and can't move!

. this only happens in some maps
. all default maps are FREE of this bug
. yes, we have more spawnpoints than players

seams that I found the cause of the siamese twins problem with help of a mapper friend.

the only difference in the maps that happens this problem to the maps that didn't are the spawnpoints in the buggy maps are a little below the floor, seams created to hide the spawnpoint mark on the floor.

we made thousands of tests, and created a map from zero to test this....

we made a small map with only 4 spawnpoints... and playing with 6 players.

1st try:

spawnpoints in default way, appears a mark, like a step on the floor (like q2dm1)

NEVER happen the problem, everything is 100% right! even with more players than spawnpoints.

2nd try:

we put the spawn a little below the floor, but the mark still appearing on the floor aside in the same level.

sometimes the players born glued, but jumping and with hook we can go away from each other.

3rd try:

we put the spawn a little more on the floor, so don't appear any spawn mark on the floor.

then we got the siamese twins problem... 

Maps That have this bug

Almost the most beautiful ones... here few classics: tltf, tltf2, marics33 & marics37

Solution:

I think if I can spawn the players a little above the point they are marked to spawn, will fix this problem in all the maps... what do you think?

My Try

well, I tryed... but nothing really changed... here the code that I changed (BOLD lines) in p_client.c

Quote
/*
===========
PutClientInServer

Called when a player connects to a server or respawns in
a deathmatch.
============
*/
void PutClientInServer (edict_t *ent)
{
vec3_t mins = {-16, -16, -24};
vec3_t maxs = {16, 16, 32}; <--------------------------------------------------------- Is this the max values of XYZ???
int index;
vec3_t spawn_origin, spawn_angles;
gclient_t *client;
int i;
client_persistant_t saved;
client_respawn_t resp;

// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
SelectSpawnPoint (ent, spawn_origin, spawn_angles);

index = ent-g_edicts-1;
client = ent->client;

// deathmatch wipes most client data every spawn
if (deathmatch->value)
{
char userinfo[MAX_INFO_STRING];

resp = client->resp;
memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
InitClientPersistant (client);
ClientUserinfoChanged (ent, userinfo);
}
else if (coop->value)
{
// int n;
char userinfo[MAX_INFO_STRING];

resp = client->resp;
memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
// this is kind of ugly, but it's how we want to handle keys in coop
// for (n = 0; n < game.num_items; n++)
// {
// if (itemlist[n].flags & IT_KEY)
// resp.coop_respawn.inventory[n] = client->pers.inventory[n];
// }
resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged;
resp.coop_respawn.helpchanged = client->pers.helpchanged;
client->pers = resp.coop_respawn;
ClientUserinfoChanged (ent, userinfo);
if (resp.score > client->pers.score)
client->pers.score = resp.score;
}
else
{
memset (&resp, 0, sizeof(resp));
}

// clear everything but the persistant data
saved = client->pers;
memset (client, 0, sizeof(*client));
client->pers = saved;
if (client->pers.health <= 0)
InitClientPersistant(client);
client->resp = resp;

// copy some data from the client to the entity
FetchClientEntData (ent);

// clear entity values
ent->groundentity = NULL;
ent->client = &game.clients[index];
ent->takedamage = DAMAGE_AIM;
ent->movetype = MOVETYPE_WALK;
ent->viewheight = 22;
ent->inuse = true;
ent->classname = "player";
ent->mass = 200;
ent->solid = SOLID_BBOX;
ent->deadflag = DEAD_NO;
ent->air_finished = level.time + 12;
ent->clipmask = MASK_PLAYERSOLID;
ent->model = "players/male/tris.md2";
ent->pain = player_pain;
ent->die = player_die;
ent->waterlevel = 0;
ent->watertype = 0;
ent->flags &= ~FL_NO_KNOCKBACK;
ent->svflags &= ~SVF_DEADMONSTER;

VectorCopy (mins, ent->mins);
VectorCopy (maxs, ent->maxs);
VectorClear (ent->velocity);

// clear playerstate values
memset (&ent->client->ps, 0, sizeof(client->ps));

client->ps.pmove.origin[0] = spawn_origin[0]*8;
client->ps.pmove.origin[1] = spawn_origin[1]*8;
client->ps.pmove.origin[2] = spawn_origin[2]*8; <--------------------------------------------------------- I tryed (spawn_origin[2]+15)*8

if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
{
client->ps.fov = 90;
}
else
{
client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
if (client->ps.fov < 1)
client->ps.fov = 90;
else if (client->ps.fov > 160)
client->ps.fov = 160;
}

client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);

// clear entity state values
ent->s.effects = 0;
ent->s.modelindex = 255; // will use the skin specified model
ent->s.modelindex2 = 255; // custom gun model
// sknum is player num and weapon number
// weapon number will be added in changeweapon
ent->s.skinnum = ent - g_edicts - 1;

ent->s.frame = 0;
VectorCopy (spawn_origin, ent->s.origin);
ent->s.origin[2] += 1; // make sure off ground <--------------------------------------------------------- tryed change 1 for 5, 15, 20, 200, 2000...
VectorCopy (ent->s.origin, ent->s.old_origin);

// set the delta angle
for (i=0 ; i<3 ; i++)
{
client->ps.pmove.delta_angles = ANGLE2SHORT(spawn_angles - client->resp.cmd_angles);
}

ent->s.angles[PITCH] = 0;
ent->s.angles[YAW] = spawn_angles[YAW];
ent->s.angles[ROLL] = 0;
VectorCopy (ent->s.angles, client->ps.viewangles);
VectorCopy (ent->s.angles, client->v_angle);

// spawn a spectator
if (client->pers.spectator) {
client->chase_target = NULL;

client->resp.spectator = true;

ent->movetype = MOVETYPE_NOCLIP;
ent->solid = SOLID_NOT;
ent->svflags |= SVF_NOCLIENT;
ent->client->ps.gunindex = 0;
gi.linkentity (ent);
return;
} else
client->resp.spectator = false;

if (!KillBox (ent))
{ // could't spawn in?
}

gi.linkentity (ent);

// force the current weapon up
client->newweapon = client->pers.weapon;
ChangeWeapon (ent);
}



well, all my tries seams ignored.... am I in the wrong place?Huh

or worst, the only way to fix is via the MOD source?

thanks again!
Logged
QwazyWabbit
Member

Posts: 402


« Reply #1 on: June 05, 2007, 08:16:37 am »

The pads are 8 units tall. If they are buried they might be 1 or more units below the ground. Players are held in place briefly upon spawn and it may be a race condition between spawn events when having more players than pads. I don't know why it would happen more often if the pads are buried.

Seems to me ent->s.origin[2] += 9; should do it.

This is a really old problem and it would be nice to finally see it fixed.
Logged
hajas
Member

Posts: 44



« Reply #2 on: June 05, 2007, 11:25:58 am »

I made it! but was only tested in DM... I'll need to work more on it... the problem was at this line:

Quote
vec3_t maxs = {16, 16, 32};

I was thinking was that (like I asked in every forum but no one seams to know that) but I'm was afraid to change and make the game abort or something....

well, to hell with fear! I'll change to see! then I changed to a a very high value!

Quote
vec3_t maxs = {16, 16, 1000};

then changed the line

Quote
ent->s.origin[2] += 1; // make sure off ground

to

Quote
ent->s.origin[2] += 900; // make sure off ground


then, I was be spawned really higher! in some maps out of the map! hehehe Cheesy
or inside the wall that was above the spawn, etc...

well, the importand that I found the point that do that.... Cheesy

after many tests I found this values:

Quote
vec3_t maxs = {16, 16, 50};
ent->s.origin[2] += 30;

and is working PERFECT in DM! Cheesy

soon as I have a free time, I'll try with RA2!!! Tongue

I'm only afraid that RA2 have his own spawn code, not only find a spot and spawn the player...
and since I don't have their source, I'll be lost! Sad

let's pray! Cheesy

well, r1ch... you have here the answer to fix this bug in DM/TDM... and probally CTF too...  wink
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #3 on: June 05, 2007, 11:46:23 am »

Uh, if you change the mins or maxs, you do realize you are changing the players bounding box? You probably don't want to do that.
Logged
hajas
Member

Posts: 44



« Reply #4 on: June 05, 2007, 11:48:36 am »

yes! was why I was afraid to do... but if you didn't, you can't spawn them little above...got it?
Logged
hajas
Member

Posts: 44



« Reply #5 on: June 05, 2007, 11:50:22 am »

that's why my first try was ignored! Cheesy
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #6 on: June 05, 2007, 12:05:08 pm »

The origin is the only thing that alters the players position, adjusting mins or maxs simply changes their size.
Logged
hajas
Member

Posts: 44



« Reply #7 on: June 05, 2007, 12:47:22 pm »

well, I think I'm with the same size... and spawning a little higher...  wink

if I don't change this value, I can't be spawned above, because I'll pass through the box, so is ignored...
then I turn the box a little bigger in the Z, then works.

if what you are saying was right, so when I add 1000 to the size, should I become a japanese monster? but this not what happened.

when I was testing I found the size to born before the box size... I was with 1000/30 values... and was spawning right...
I only turn the value down to avoid some other problems in game... which I didn't tested enough like I sad above.

if with my final values I only become a little higher, I'll not see me falling when spawned... right?

well, I really don't have 100% sure that I got the same size with 50 on the box, but with 1000 I'm sure that had the same size of 50...
I think nothing was changed about the size of player... well, I'll test more anyway...  cheesy

so why not try for yourself? and you'll see if that really works and if your size will be the SAME! Cheesy

take a shot!  grin
Logged
hajas
Member

Posts: 44



« Reply #8 on: June 05, 2007, 01:06:23 pm »

hmmm... I did a fast test here at work... and we both are 50% right and 50% wrong...   huh

so we only need to change this line to fix the spawn problem in DM/TDM/CTF:

Quote
ent->s.origin[2] += 30;

so you don't need to change this one:

Quote
vec3_t maxs = {16, 16, 32};

but that one don't make difference in your size, is just about your box what I see...

well, I was testing with RA2 at home, and was not working... then I tested here and changed this values and start to work, than I thought was that but I'm wrong...

so my deepest fear become true...  cry angry

seams is ignored because RA2 have his own spawn...  shocked

so I gonna jump into the lava...  grin
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #9 on: June 05, 2007, 03:11:45 pm »

Unless you have the RA2 mod source you can't fix this in RA2.

If you only need to increase the origin, it's possible to edit the RA2 binary directly assuming the code still exists to lift the players origin. This will then cause problems for maps that have properly positioned teleporters with low ceilings. The bug isn't really with RA2, it's with the maps that try and hide teleporters. You can probably fix the maps using R1Q2 .override support.
Logged
hajas
Member

Posts: 44



« Reply #10 on: June 05, 2007, 04:15:39 pm »

Quote
If you only need to increase the origin, it's possible to edit the RA2 binary directly assuming the code still exists to lift the players origin. This will then cause problems for maps that have properly positioned teleporters with low ceilings.

I tested with this value until below very low ceilings, and works great... probally a less number like 15 or even 10 will be already enough to fix this problem.... about edit the binary you mean with a hex editor? or how?

Quote
The bug isn't really with RA2, it's with the maps that try and hide teleporters.

sure! I know that! I only want to try to fix that without fix map by map... Sad

Quote
You can probably fix the maps using R1Q2 .override support.

hmmm... tell more about it?  rolleyes
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #11 on: June 05, 2007, 07:02:04 pm »

Yes, you can use a hex editor / disassembler to find the appropriate place to change in the binary. If you post the .so or .dll you are using, I can point it out.

See here for more information on .override files: http://www.r1ch.net/forum/index.php?topic=1072.0
Logged
hajas
Member

Posts: 44



« Reply #12 on: June 05, 2007, 07:18:01 pm »

I found about the override....

Quote
Server-side entity replacement and map overriding support. Using this you can create "virtual" maps that exist only as a .override file on the server, but load up an existing map with a modified entity string. Example: q2dm1.bsp is your normal q2dm1. To add some excitement, you want to put a quad in the map, but don't want clients to have to download a whole new .bsp. So you edit the entity string for q2dm1 to include a quad, then generate a .override file specifying "maps/q2dm1.bsp" as the map to load with the new entity string. Then you save the .override file as 'maps/q2dm1-quad.bsp.override' and you can use 'q2dm1-quad' as if it were a valid map, eg in map rotations, 'gamemap q2dm1-quad', etc. Upon loading it, the server will change the real map back to q2dm1 and use the modified entity string specified in the .override file.

The .override file format is a proprietary R1Q2 binary format including a bitfield specifying what is present. This allows it to be extended at a later date without breaking compatibility. I've created a PHP script to generate a .override file since explaining the format here would take too long. Generate the .override file at http://r-1.ch/r1q2gen.php. If you don't know how to get an entity string from a .bsp, try entdump: http://r-1.ch/entdump.c (Win32 binary: http://r-1.ch/entdump.exe, runs from cmd prompt, eg entdump q2dm1.bsp > q2dm1.txt). Note that the server will very likely crash if you use a bad .override file so be careful! Please don't ask me about this feature if you aren't sure how to use it, it's pretty complicated and amazingly hacky but it does work. I think.

sounds very cleaver m8...

I generated this with our small test map....

Quote
{
"classname" "worldspawn"
}
{
"origin" "-256 248 16"
"classname" "info_player_deathmatch"
}
{
"classname" "info_player_deathmatch"
"origin" "248 256 16"
}
{
"origin" "248 -256 16"
"classname" "info_player_deathmatch"
}
{
"classname" "info_player_deathmatch"
"origin" "-264 -256 16"
}
{
"origin" "-176 -200 24"
"classname" "weapon_rocketlauncher"
}
{
"classname" "weapon_rocketlauncher"
"origin" "-184 192 24"
}
{
"origin" "168 184 24"
"classname" "weapon_rocketlauncher"
}
{
"origin" "-184 -264 24"
"classname" "ammo_rockets"
}
{
"classname" "ammo_rockets"
"origin" "192 -256 24"
}
{
"origin" "184 128 24"
"classname" "ammo_rockets"
}
{
"classname" "ammo_rockets"
"origin" "-184 128 24"
}
{
"origin" "216 -192 24"
"classname" "weapon_rocketlauncher"
}
{
"light" "400"
"origin" "-8 0 208"
"classname" "light"
}

so is just put this code on the override file generator on your site at http://r-1.ch/r1q2gen.php

then change the Z from the spawns then generate a override file.

then when people connect will spawn a little above? sounds good... the biggest problem is that I'll need to add this feature in our Q2E Sever...

and you remember, r1q2 not worked well with Q2E... unfortunately... Sad
« Last Edit: June 05, 2007, 07:20:45 pm by hajas » Logged
hajas
Member

Posts: 44



« Reply #13 on: June 05, 2007, 07:22:31 pm »

Quote
Yes, you can use a hex editor / disassembler to find the appropriate place to change in the binary. If you post the .so or .dll you are using, I can point it out.

wow! thanks m8! are the RA2 files...

well, I'll zip them and host at my site, 1 min!  wink
Logged
hajas
Member

Posts: 44



« Reply #14 on: June 05, 2007, 07:27:21 pm »

here all the files, server/client inclued

http://q2a.hajas.org/files/arena.zip

which program do you use for that?

thanks again!
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #15 on: June 05, 2007, 08:30:18 pm »

Do you use the Win32 or Linux binary?
Logged
hajas
Member

Posts: 44



« Reply #16 on: June 05, 2007, 09:31:45 pm »

omg! I sent you both! sorry... I use win32 m8!  cheesy
Logged
QwazyWabbit
Member

Posts: 402


« Reply #17 on: June 06, 2007, 04:13:57 am »

If you leave maxs at 16 16 50 won't that leave the bounding box large? The player figure won't be resized but the target bounding box will make it possible to shoot the player when aiming high. Reducing Z of the bounding box is done to make the player figure crouch. Setting back to 32 makes him stand. To test target box size, aim high above the figure with the rail, I think you will find he can be fragged.

I think you will have to reset the Z back to 32 once the player is properly spawned.
Logged
Snake
Member

Posts: 184


« Reply #18 on: June 06, 2007, 04:50:55 am »

I tested with this value until below very low ceilings, and works great... probally a less number like 15 or even 10 will be already enough to fix this problem....

Buried spawnpads are typically buried 7 units or thereabout. Too bad Q2 didn't come with the ability to hide the damn things, some mods provide that option tho.
Logged
hajas
Member

Posts: 44



« Reply #19 on: June 06, 2007, 01:33:38 pm »

in this meantime, I was thinking in another way to fix this problem...

well, I tryed to move up and spawn, and change the killbox... boths will work if I could change the RA2 source.

but in fact, this isn't a RA2 bug, is a mapping problem... that appears more in round based games.

so if we try to fix the maps via code? and not the spawns? could be a clean solution?

I was taking a look at cmodel.c at quake2... in CM_LoadMap

and also was thinking about your override stuff... so could be only server side, so no need to download again all maps.
(great to us! because we have more than 1500 maps in rotation!)

so we could do something like this pseudocode:

Quote
in every info_player_deathmatch do
  origin (Z) += num;
end;

where num is the number that we must to up a little all spawns, this number must be calculated and tested of course.

we could do a little better like:

Quote
(creat a file with a list of all known bug maps called mapbuglist)

if map in mapbuglist do in every info_player_deathmatch
  origin (Z) += num;
end;

then will only fix the buggy ones...

or a kind of exe like you did to get the info from the map merged with your another application to calculate the override file,
so will generate only spawn infos, changed, and genarete the override to each map in that folder.

what do you think r1ch? should be the right way to fix this... aside more difficult.  sad

Logged
hajas
Member

Posts: 44



« Reply #20 on: June 06, 2007, 03:25:04 pm »

or a even better way...  cheesy

Quote
if game == 'arena' then
   do in every info_player_deathmatch do
     origin (Z) += num;
   end do;
end if;
Logged
hajas
Member

Posts: 44



« Reply #21 on: June 09, 2007, 10:22:20 am »

Here are some images of siamese twins bug in RA2...



Attention: this map have 7 spawnpoints, and was tested only with 4 players!



if you entered the map via DM, you will see this:



after up the Z (+10) of the origin of the spawnpoint via hex and do the same, here is what we can see in DM



I tested many many times, but aside the problem not happen in 2 matches of 19 rounds, in the third happend with the info_player_start, not the info_player_deathmatch... so I add more 5 than tested again for 1 hours, around 6 matches without one single problem.

Demo with the original TLTF map : Siamese Twins Problems
Demo with the fixed TLTF map: Problem Solved!
(came with the maps! need RA2 installed to view)

so I know exactly how to fix this problem, is just add +15 to Z value in each info_player_deathmatch and info_player_start, and probally info_player_team1 and info_player_team2 too when game = arena.

I'm trying to find how to do that in the code, but I'm having some problems... any suggestions?

thanks!
Logged
QwazyWabbit
Member

Posts: 402


« Reply #22 on: June 09, 2007, 05:26:18 pm »

You will find code that hacks coop spots on the basis of map names in most game code: p_client.c
In the original 3.21 game code it starts at line 28.
There are other map hacks throughout the game where they corrected the basic maps.
You will also find they are called "ugly disgusting hacks", and rightfully so.
Search the word hack in the code for even more map hacks.

You should try to avoid fixing it in code as this is backwards. If the problem is in the maps, correct the entities in the maps. But editing the maps directly will create problems for people who already have the maps since identical file names for edited maps will cause map checksum errors and kill the client connection. A better solution is to use the r1q2 override feature or any override feature in the game that will allow entities to be corrected externally with ent files or override files. This solves the spawn problem without creating map conflicts and also allows the overrides to be shared so everyone can benefit from the information.
Logged
hajas
Member

Posts: 44



« Reply #23 on: June 09, 2007, 07:07:28 pm »

sure, I want to do something like the override... but I don't need files etc, is just do the same thing to every map when the game is arena...  grin

we user Q2E, and didn't work well with r1q2 unfortunately...  cry
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #24 on: June 09, 2007, 08:55:43 pm »

You will need to either port the override feature to Q2E or add a hack in the engine before the SpawnEntities call if you want to do this without requiring new map downloads.
Logged
QwazyWabbit
Member

Posts: 402


« Reply #25 on: June 09, 2007, 10:29:21 pm »

We implemented an ent file loader for LOX. If you have source for the arena mod you can add it.

g_ent.c:
Code:
#include "g_local.h"

static char *ReadEntFile(char *filename)
{

FILE      *fp;
char      *filestring = NULL;
long int   i = 0;
int         ch;

for (;;)
{
fp = fopen(filename, "r");
if (!fp) break;

for (i=0; (ch = fgetc(fp)) != EOF; i++);

filestring = gi.TagMalloc(i+1, TAG_LEVEL);
if (!filestring) break;

fseek(fp, 0, SEEK_SET);
for (i=0; (ch = fgetc(fp)) != EOF; i++)
filestring[i] = (char) ch;
filestring[i] = '\0';
break;
}

if (fp) fclose(fp);
return(filestring);
}

char *LoadEntFile(char *mapname, char *entities)
{
char   entfilename[MAX_QPATH] = "";
char   *newentities;
int      i;
   
sprintf(entfilename, "entfiles/%s.ent", mapname);
// convert string to all lowercase (for Linux)
for (i = 0; entfilename[i]; i++)
entfilename[i] = (char) tolower(entfilename[i]);

newentities = ReadEntFile(entfilename);

if (newentities)
{   //leave these dprints active they show up in the server init console section
gi.dprintf("Entity file %s.ent found\n", mapname);
return(newentities);   // reassign the ents
}
else
{
gi.dprintf("No .ent File for %s.bsp\n", mapname);
return(entities);
}
}

Prototype in g_local.h:
char *LoadEntFile(char *mapname, char *entities);

Call from inside SpawnEntities() just before entity parsing:
    entities = LoadEntFile(mapname, entities);  /*MrG{DRGN} 10/04/2004*/


The game looks for mapname.ent in the modname/entfiles/ folder, if it exists, it loads it in place of the entities defined in the map itself. To use it, use r1ch's entdump program to dump a maps entities, then modify the file as needed.
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #26 on: June 09, 2007, 11:05:03 pm »

RA2 is closed source unfortunately.
Logged
hajas
Member

Posts: 44



« Reply #27 on: June 10, 2007, 10:50:39 am »

yeah, I don't have the RA2 source, and I think was never released to the public...  undecided

I need to make the change when the map is loaded, like the r1ch override....

I found the part on Q2E code that load the entities of the map:

Quote
=================
CM_LoadEntityString
=================
*
static void CM_LoadEntityString (const byte *data, const lump_t *l) {

cm_numEntityChars = l->fileLen;
if (cm_numEntityChars < 1)
return;
if (cm_numEntityChars > MAX_MAP_ENTSTRING)
Com_Error (ERR_DROP, "CM_LoadMap: map '%s' has too large entity lump ", cm_map);

cm_entityString = Hunk_Alloc (cm_numEntityChars + 1);
memcpy (cm_entityString and data + l->fileOfs and cm_numEntityChars);
}

so I need to manipulate the string cm_entityString to find the info_player entities and change his origins in Z axis.

r1ch, where exact you do this change on your code? I didn't found anything similar... maybe you done in another way?

thanks again!
Logged
hajas
Member

Posts: 44



« Reply #28 on: June 10, 2007, 10:56:13 am »

hmmm.... you didn't replace just the altered entities, you just replace everything right?  huh

that's why I'm not finding anything about it!  rolleyes
Logged
hajas
Member

Posts: 44



« Reply #29 on: June 10, 2007, 11:54:16 am »

well, I got this:

Quote
/*
 =================
 CM_LoadEntityString
 =================
*/
static void CM_LoadEntityString (const byte *data, const lump_t *l){

   char   *game = Cvar_VariableString("fs_game"); // declara game - Hajas

   cm_numEntityChars = l->fileLen;
   if (cm_numEntityChars < 1)
      return;
   if (cm_numEntityChars > MAX_MAP_ENTSTRING)
      Com_Error(ERR_DROP, "CM_LoadMap: map '%s' has too large entity lump", cm_map);

   cm_entityString = Hunk_Alloc(cm_numEntityChars + 1);
   memcpy(cm_entityString, data + l->fileOfs, cm_numEntityChars);

   if (!Q_stricmp(game, "arena")){
      // do string manipulation over cm_entityString
   }
}

anyone can help with string manipulation functions in C? I don't work with that for more than 8 years...  undecided

I found another problem... WTH!!!

Quote
{
"origin" "-256 248 16"
"classname" "info_player_deathmatch"
}
{
"classname" "info_player_deathmatch"
"origin" "248 256 16"
}

seams that the origin info could be below or above classname, so will be impossible to find the exact origin to each class...  angry

by the other hand, this make me think one thing... RA2 remove ALL entities from the map aside the spawnpoints.

so, we just add 15 to all origins... will not make any difference since this will only happen in RA2.

so will be a easier code to do that...  evil
Logged
hajas
Member

Posts: 44



« Reply #30 on: June 11, 2007, 09:13:29 am »

here the pseudocode of my solution...

Quote
while can find "origin" into String do {
   strReplaceFirst (String, origin, fhajas); // replace FIRST origin for fhajas in the string
   posA = find 3rd space after fhajas;
   posB = find next " after posA;
   Str1 = GetSubstring (String[0],posA);
   Str2 = GetSubstring (posB,String[size]);
   num = GetSubstring (posA, posB);
   ToNumber(num) += 15;
   String = Str1 + num + Str2;
}
strReplace (String, fhajas, origin) // replace ALL fhajas for origin in the string

any better ideas?
« Last Edit: June 11, 2007, 09:21:05 am by hajas » Logged
hajas
Member

Posts: 44



« Reply #31 on: June 11, 2007, 11:50:09 am »

well, I realize that I can't change all origins, because I'll cause problems to other classes....
so I can only change info_player_deathmatch and info_player_start classes

so here the new pseudocode to solve this:

Quote
set working = 1;
while working == 1 {
   if "{" not found{
      set working = 0;
   else{
       subs = GetSubstring(String, first {, first });
      Str1 = GetSubstring (String[0], subs[0]);
      Str2 = GetSubstring (subs[size],String[size]);
      if found (info_player_deathmatch || info_player_start) in subs {
           find "origin" location;
         posA = find 3rd space after origin location;
         posB = find next " after posA;
         Subs1 = GetSubstring (subs[0],posA);
         Subs2 = GetSubstring (posB,subs[size]);
         num = GetSubstring (posA, posB);
         ToNumber(num) += 15;
           subs = Subs1 + num + Subs2;
         ReplaceAll (subs, {, [);
         ReplaceAll (subs, }, ]);
      }
   }
}
ReplaceAll (String, [, {);
ReplaceAll (String, ], });

any inputs?
« Last Edit: June 11, 2007, 12:16:30 pm by hajas » Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #32 on: June 11, 2007, 11:53:39 am »

You may want to look in Com_Parse, Q2 already has a tokenizer you can use.
Logged
hajas
Member

Posts: 44



« Reply #33 on: June 12, 2007, 01:35:37 pm »

hmmm... very insteresting stuff...

where I set the token the string? I don't get it...

I was thinking in do something like this with strtok inside the loop:

Code:
SubString = strtok(String,'}');

correct me if I'm wrong, with that I'll have everything in the String until the } point copied to that SubString variable.

than I can work with that substring, and create another variable that will save the new string.

and when execute again will copy from the next char after last char copied first, until the next }, and goes on...

so in each passage of the loop will copy each entity to that SubString... am I right?

thanks again m8!
Logged
hajas
Member

Posts: 44



« Reply #34 on: June 13, 2007, 03:04:13 pm »

well, I quit to try find good functions, and done everything by hand... so please take a look at this code:

Code:
static void CM_LoadEntityString (const byte *data, const lump_t *l){

    char   *game = Cvar_VariableString("fs_game");
int i, j, Tam, TamNew;
int PA, PB, PC, PD, PL, L1, Num, Espaco, Aspas;
char *p, *ori, *HStr, *NewStr, *FinalStr;
char *PartA, *PartB, *PartC, *PartD;

cm_numEntityChars = l->fileLen;
if (cm_numEntityChars < 1)
return;
if (cm_numEntityChars > MAX_MAP_ENTSTRING)
Com_Error(ERR_DROP, "CM_LoadMap: map '%s' has too large entity lump", cm_map);

cm_entityString = Hunk_Alloc(cm_numEntityChars + 1);
memcpy(cm_entityString, data + l->fileOfs, cm_numEntityChars);

if (!Q_stricmp(game, "arena")){
HStr = cm_entityString; // copy the original string to mine
Tam = strlen(HStr);
      // do string manipulation over cm_entityString
i=0;
j=0;
   while (j<Tam){
   while (HStr[j] != '}'){ // copy to NewStr each Class
   NewStr[i] = HStr[j];
   i++;j++;
   }
   NewStr[i] = HStr[j]; //add '}' to the end of the class
   p = strstr(NewStr, "info_player"); //see if is a spawn class
   if (!p){
   FinalStr = strcat( FinalStr, NewStr ); //if not, save and go to the next class
   }else{
   //if yes, start the hard work
               ori = strstr(NewStr, "origin"); //find the origin position
   // than add +8 (origin" ") to that position, which will reach the numbers of the axis
   L1=ori+8; //------------------------------------------------- NEED TO CONVERT????!!!
   // find PartA from 0 to L1
   for (PA=0;PA==L1;PA++) //seta parte 1/4
   {
PartA[PA]=NewStr[PA];
   }
   PL=PA; //creat a new var to control the place in NewStr
   Espaco=0; //set to have zero spaces count
   // find PartB from start of numbers until 2nd space
   for (PB=0;Espaco!=2;PB++) //set part 2/4
   {
PL++;
PartB[PB]=NewStr[PL];
if (PartB[PB]==" ")
Espaco++;
   }
   Aspas=0; //set to plics to zero count
   // find PartC which is the Number, until reach next "
   for (PC=0;Aspas==1;PC++) //set part 3/4 = Num
   {
   PL++;
if (NewStr[PL]=='"')
Aspas = 1;
else
PartC[PC]=NewStr[PL];
   }
   TamNew = strlen(NewStr); //find the size of NewStr
   // find PartD from " after number until the end of class
   for (PD=0;PL==TamNew;PD++) //set part 4/4
   {
   PartD[PD]=NewStr[PL];
   PL++;
   }
   // Convert to Number
   Num=PartC; //------------------------------------------------- HOW TO CONVERT????!!!
   Num += 15; //add 15
   NewStr = strcat( PartA, PartB ); // make all 4 parts into one
   NewStr = strcat( NewStr, Num ); //------------------------------------------------- NEED TO CONVERT????!!!
   NewStr = strcat( NewStr, PartD );
   FinalStr = strcat( FinalStr, NewStr ); // add all NewStr to FinalStr
   }
i=0; //NewStr count to zero
j++;
NewStr=""; //erase NewStr
   }
cm_entityString = FinalStr; //replace the original by the new altered one
}
}

ok, I know need few funcions of convertions or some other thing must be done in the wrong way... please fix everything that you find not good.

thanks a lot!
« Last Edit: June 14, 2007, 09:24:08 am by hajas » Logged
hajas
Member

Posts: 44



« Reply #35 on: June 14, 2007, 08:35:47 am »

I updated the code with a more commented version fixing some small problems too.
« Last Edit: June 14, 2007, 09:27:16 am by hajas » Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #36 on: June 14, 2007, 10:49:42 am »

You can use atoi to convert a string to an integer, eg i = atoi("3") will set i to 3. To go the other way, you need to use sprintf into a buffer, eg char buff[16]; sprintf (buff, "%d", i);
Logged
hajas
Member

Posts: 44



« Reply #37 on: June 14, 2007, 11:34:41 am »

I did with atoi function... but look what I found in Q2E code (probally the same as Q2):

Code:
/*
==============
SpawnEntities

Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.
==============
*/
void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
{
edict_t *ent;
int inhibit;
char *com_token;
int i;
float skill_level;

skill_level = floor (skill->value);
if (skill_level < 0)
skill_level = 0;
if (skill_level > 3)
skill_level = 3;
if (skill->value != skill_level)
gi.cvar_forceset("skill", va("%f", skill_level));

SaveClientData ();

gi.FreeTags (TAG_LEVEL);

memset (&level, 0, sizeof(level));
memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));

strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);

// set client fields on player ents
for (i=0 ; i<game.maxclients ; i++)
g_edicts[i+1].client = game.clients + i;

ent = NULL;
inhibit = 0;

// parse ents
while (1)
{
// parse the opening brace
com_token = Com_Parse (&entities);
if (!entities)
break;
if (com_token[0] != '{')
gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

if (!ent)
ent = g_edicts;
else
ent = G_Spawn ();
entities = ED_ParseEdict (entities, ent); //--------------------------------LOOK HERE!!!

// yet another map hack
if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

// remove things (except the world) from different skill levels or deathmatch
if (ent != g_edicts)
{
if (deathmatch->value)
{
if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
{
G_FreeEdict (ent);
inhibit++;
continue;
}
}
else
{
if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
)
{
G_FreeEdict (ent);
inhibit++;
continue;
}
}

ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
}

ED_CallSpawn (ent);
}

gi.dprintf ("%i entities inhibited\n", inhibit);

#ifdef DEBUG
i = 1;
ent = EDICT_NUM(i);
while (i < globals.num_edicts) {
if (ent->inuse != 0 || ent->inuse != 1)
Com_DPrintf("Invalid entity %d\n", i);
i++, ent++;
}
#endif

G_FindTeams ();

PlayerTrail_Init ();
}

than call this

Code:
/*
====================
ED_ParseEdict

Parses an edict out of the given string, returning the new position
ed should be a properly initialized empty edict.
====================
*/
char *ED_ParseEdict (char *data, edict_t *ent)
{
qboolean init;
char keyname[256];
char *com_token;

init = false;
memset (&st, 0, sizeof(st));

// go through all the dictionary pairs
while (1)
{
// parse key
com_token = Com_Parse (&data);
if (com_token[0] == '}')
break;
if (!data)
gi.error ("ED_ParseEntity: EOF without closing brace");

strncpy (keyname, com_token, sizeof(keyname)-1);

// parse value
com_token = Com_Parse (&data);
if (!data)
gi.error ("ED_ParseEntity: EOF without closing brace");

if (com_token[0] == '}')
gi.error ("ED_ParseEntity: closing brace without data");

init = true;

// keynames with a leading underscore are used for utility comments,
// and are immediately discarded by quake
if (keyname[0] == '_')
continue;

ED_ParseField (keyname, com_token, ent);
}

if (!init)
memset (ent, 0, sizeof(*ent));

return data;
}

which call this:

Code:
/*
===============
ED_ParseField

Takes a key/value pair and sets the binary values
in an edict
===============
*/
void ED_ParseField (char *key, char *value, edict_t *ent)
{
field_t *f;
byte *b;
float v;
vec3_t vec;

for (f=fields ; f->name ; f++)
{
if (!(f->flags & FFL_NOSPAWN) && !Q_stricmp(f->name, key))
{ // found it
if (f->flags & FFL_SPAWNTEMP)
b = (byte *)&st;
else
b = (byte *)ent;

switch (f->type)
{
case F_LSTRING:
*(char **)(b+f->ofs) = ED_NewString (value);
break;
case F_VECTOR:
sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
((float *)(b+f->ofs))[0] = vec[0];
((float *)(b+f->ofs))[1] = vec[1];
((float *)(b+f->ofs))[2] = vec[2]; //-------------------------------------------- is that value what I'm looking for to update? (if was info_player)
break;
case F_INT:
*(int *)(b+f->ofs) = atoi(value);
break;
case F_FLOAT:
*(float *)(b+f->ofs) = atof(value);
break;
case F_ANGLEHACK:
v = atof(value);
((float *)(b+f->ofs))[0] = 0;
((float *)(b+f->ofs))[1] = v;
((float *)(b+f->ofs))[2] = 0;
break;
case F_IGNORE:
break;
}
return;
}
}
gi.dprintf ("%s is not a field\n", key);
}


« Last Edit: June 14, 2007, 11:37:33 am by hajas » Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #38 on: June 14, 2007, 11:37:17 am »

As I said, Q2 already has tokenizers / parsers for entity strings. You can use those, or you can make your own.
Logged
hajas
Member

Posts: 44



« Reply #39 on: June 14, 2007, 12:05:55 pm »

ok.... did you succeed in change the RA2 DLL with an Hex/Decompiler?
Logged
hajas
Member

Posts: 44



« Reply #40 on: June 14, 2007, 02:19:25 pm »

wth! will be so easy to fix that if I have the RA2 source!!!

these functions are great, but are all in DLL part, so I can't change... and if I remake then to only get the values, I will need to reconstruct the string anyway, and will be really hard to do that in that way... so my code was the best solution to do that via code until now...

please let me know if you did any progress in editing direct the RA2 DLL.

thanks m8!
Logged
hajas
Member

Posts: 44



« Reply #41 on: June 20, 2007, 03:26:36 pm »

any news r1ch?
Logged
R1CH
Administrator
Member

Posts: 2625



« Reply #42 on: June 20, 2007, 03:46:21 pm »

RA2 spawn code is quite different from vanilla Q2DM, so I wasn't able to trace where the origin is set. More specifically, the ent->s.origin[2] += 1 is not present in RA2.
Logged
hajas
Member

Posts: 44



« Reply #43 on: June 21, 2007, 07:41:14 am »

thanks m8 for try... I'm pretty close to solve the problem when read the maps...
Logged
hajas
Member

Posts: 44



« Reply #44 on: June 21, 2007, 03:29:16 pm »

Ok, I done everything that I could to fix the siamese twins bug, and I FIXED!!!! Cheesy

but I'm having a little problem.... when I quit the server the game abort, or when I change the map for the 3rd time the game abort... I still don't know why... the string was altered with perfection, but seams that I miss something, maybe I need to use memcpy too?

well, here the final code:

I commented the file recording and the ARENA test to see the spawnpoints higher even in DM, and works really perfect! no one problem about that... attached you can find the files recorded to you see that manipulation was perfect!

Code:
static void CM_LoadEntityString (const byte *data, const lump_t *l){

char *game = Cvar_VariableString("fs_game"); // declare game - Hajas
//FILE *f;
char *p, *loc, *origem;
char *ptr = malloc(151);
int i, j, k, Tam, TamNew, ori;
int PA, PB, PC, PD, PL, Num, Space, Aspas;
char HStr[MAX_MAP_ENTSTRING], FinalStr[MAX_MAP_ENTSTRING];
char NewStr[150], PartA[150], PartB[150], PartC[20], PartD[150];

cm_numEntityChars = l->fileLen;
if (cm_numEntityChars < 1)
return;
if (cm_numEntityChars > MAX_MAP_ENTSTRING)
Com_Error(ERR_DROP, "CM_LoadMap: map '%s' has too large entity lump", cm_map);

cm_entityString = Hunk_Alloc(MAX_MAP_ENTSTRING);
memcpy(cm_entityString, data + l->fileOfs, cm_numEntityChars);

//f = fopen ("entityORI.cfg", "wb");
//fprintf(f, "%s\n", cm_entityString);
//fclose(f);

//if (!Q_stricmp(game, "arena")){
// do string manipulation over cm_entityString
strcpy(HStr, cm_entityString); // copy the original string to mine
        Tam = strlen(HStr);
        j=0;
       while (j < Tam){
   i=0;
           while ((HStr[j] != '}') && (j < Tam)){ // copy to NewStr each Class
               NewStr[i] = HStr[j];
               i++;j++;
           }
   if (HStr[j] == '}'){
NewStr[i] = HStr[j]; //add '}' close the class
NewStr[i+1] = '\0'; //add '\0' to the end of the class
   }
   TamNew = strlen(NewStr); //find the size of NewStr
   p = strstr(NewStr, "info_player");
           if (!p){ //test if is a spawn class
   strcat( FinalStr, NewStr ); //if not, save and go to the next class
           }else{
   i=0; //NewStr count to zero
               //if yes, start the hard work
   strcpy(ptr,NewStr);
   origem = strstr(ptr, "origin"); //find the origin position
   loc = origem-ptr;
   free(ptr);
               ori = loc + 8; // then add +8 (origin" ") to that position, which will reach the numbers of the axis
   free(loc);
   free(origem);
               // find PartA from 0 to L1 // until ori now
               for (PA=0;PA!=ori;PA++) //seta parte 1/4
               {
                    PartA[PA]=NewStr[PA];
   }
   PartA[PA]='\0'; //close string
               PL=PA; //create a new var to control the place in NewStr
               Space=0; //set to have zero spaces count
   PB=0; //zera PB
   // find PartB from start of numbers until 2nd space
   while (Space!=2)
               {
                    PartB[PB]=NewStr[PL];
if (PartB[PB]==' '){
Space++;
}
if(Space!=2){
PB++;PL++;
}
               }
   PartB[PB+1]='\0'; //close string
               Aspas=0; //set to plics to zero count
               // find PartC which is the Number, until reach next "
               for (PC=0;Aspas==0;PC++) //set part 3/4 = Num
               {
                   PL++;
   if (NewStr[PL]=='"')
                        Aspas = 1;
   else
                        PartC[PC]=NewStr[PL];
               }
   PartC[PC]='\0';
               // find PartD from " after number until the end of class
               for (PD=0;PL <= TamNew;PD++) //set part 4/4
               {
                   PartD[PD]=NewStr[PL];
                   PL++;
               }
               Num=atoi(PartC); // Convert to Number
               Num += 15; //add 15
               strcat( FinalStr, PartA ); // make all 4 parts into one
   strcat( FinalStr, PartB);
   sprintf(PartC,"%d",Num); // Num to String
   strcat( FinalStr, PartC);
           strcat( FinalStr, PartD );
           }
   for (k=0;k<=i;k++){ //clean NewStr
NewStr[k]='\0';
   }
   j++;
   }
  strcpy(cm_entityString, FinalStr);
/*f = fopen ("FinalStr.cfg", "wb");
fprintf(f, "%s\n", cm_entityString);
fclose(f);*/
free(p);
//}
}

with or without this line, we have the SAME behavior... abort when the third map is loaded.

Code:
strcpy(cm_entityString, FinalStr);


so isn't when the cm_entityString is altered... Sad

here the log file with developer 1

Code:
*** Log file opened on Thu Jun 21 15:23:04 2007 ***

Hunk_Clear: reset the hunk, ok
OS: Windows XP
RAM: 510 MB
Detecting CPU... Found Intel Pentium 4 2391 MHz w/ MMX SSE2
Winsock Initialized
NET_UDPSocket( localhost, 27910 )
HostName: E4203
IP: 10.10.4.203
======= Quake 2 Evolved Initialized =======
Execing dm.cfg
Cvar_Set2: timelimit "1"
SV_WipeSaveGame( current )
SV_GameMap( q2dm1 )
Cvar_Set2: sv_nextServer ""
------- Server Initialization -------
Server: q2dm1
Cvar_Set2: paused "0"
Hunk_Clear: reset the hunk, ok
----- FS_Startup -----
Current search path:
C:\q2/baseq2/q2e_pak0.pk2 (594 files)
C:\q2/baseq2/q2e_extras.pk2 (106 files)
C:\q2/baseq2/pak2.pak (2 files)
C:\q2/baseq2/pak1.pak (279 files)
C:\q2/baseq2/pak0.pak (1106 files)
C:\q2/baseq2

----------------------
2087 files in PAK/PK2 files
Cvar_Set2: deathmatch "1"
Cvar_Set2: maxclients "8"
Loading DLL file q2e_gamex86.dll...
-------- Game Initialization --------
gamename: baseq2
gamedate: Jun 21 2007
CM_LoadMap( maps/q2dm1.bsp, 0 )
Cvar_Set2: sv_gravity "800"
0 entities inhibited
0 teams with 0 entities
Cvar_Set2: needpass "0"
Cvar_Set2: sv_mapName "q2dm1"
Cvar_Set2: sv_mapChecksum "80717714"
-------------------------------------
Master server at 192.246.40.32:27900
Sending heartbeat to 192.246.40.32:27900...
]map q2dm2
SV_WipeSaveGame( current )
SV_GameMap( q2dm2 )
Cvar_Set2: sv_nextServer ""
------- Server Initialization -------
Server: q2dm2
Cvar_Set2: paused "0"
Hunk_Clear: reset the hunk, ok
------- Server Shutdown -------
Sending heartbeat to 192.246.40.32:27900...
==== ShutdownGame ====
Unloading DLL file 'q2e_gamex86.dll'...
-------------------------------
----- FS_Startup -----
Current search path:
C:\q2/baseq2/q2e_pak0.pk2 (594 files)
C:\q2/baseq2/q2e_extras.pk2 (106 files)
C:\q2/baseq2/pak2.pak (2 files)
C:\q2/baseq2/pak1.pak (279 files)
C:\q2/baseq2/pak0.pak (1106 files)
C:\q2/baseq2

----------------------
2087 files in PAK/PK2 files
Cvar_Set2: deathmatch "1"
Loading DLL file q2e_gamex86.dll...
-------- Game Initialization --------
gamename: baseq2
gamedate: Jun 21 2007
CM_LoadMap( maps/q2dm2.bsp, 0 )
Cvar_Set2: sv_gravity "800"
0 entities inhibited
1 teams with 2 entities
Cvar_Set2: needpass "0"
Cvar_Set2: sv_mapName "q2dm2"
Cvar_Set2: sv_mapChecksum "2935146665"
-------------------------------------
Sending heartbeat to 192.246.40.32:27900...
]map q2dm1
SV_WipeSaveGame( current )
SV_GameMap( q2dm1 )
Cvar_Set2: sv_nextServer ""
------- Server Initialization -------
Server: q2dm1
Cvar_Set2: paused "0"
Hunk_Clear: reset the hunk, ok
------- Server Shutdown -------
Sending heartbeat to 192.246.40.32:27900...
==== ShutdownGame ====
Unloading DLL file 'q2e_gamex86.dll'...
-------------------------------
----- FS_Startup -----
Current search path:
C:\q2/baseq2/q2e_pak0.pk2 (594 files)
C:\q2/baseq2/q2e_extras.pk2 (106 files)
C:\q2/baseq2/pak2.pak (2 files)
C:\q2/baseq2/pak1.pak (279 files)
C:\q2/baseq2/pak0.pak (1106 files)
C:\q2/baseq2

----------------------
2087 files in PAK/PK2 files
Cvar_Set2: deathmatch "1"
Loading DLL file q2e_gamex86.dll...
-------- Game Initialization --------
gamename: baseq2
gamedate: Jun 21 2007
CM_LoadMap( maps/q2dm1.bsp, 0 )


when we quit the server, the game freeze with this loq:

Code:
*** Log file opened on Thu Jun 21 15:33:13 2007 ***

Hunk_Clear: reset the hunk, ok
OS: Windows XP
RAM: 510 MB
Detecting CPU... Found Intel Pentium 4 2391 MHz w/ MMX SSE2
Winsock Initialized
NET_UDPSocket( localhost, 27910 )
HostName: E4203
IP: 10.10.4.203
======= Quake 2 Evolved Initialized =======
Execing dm.cfg
Cvar_Set2: timelimit "1"
SV_WipeSaveGame( current )
SV_GameMap( q2dm1 )
Cvar_Set2: sv_nextServer ""
------- Server Initialization -------
Server: q2dm1
Cvar_Set2: paused "0"
Hunk_Clear: reset the hunk, ok
----- FS_Startup -----
Current search path:
C:\q2/baseq2/q2e_pak0.pk2 (594 files)
C:\q2/baseq2/q2e_extras.pk2 (106 files)
C:\q2/baseq2/pak2.pak (2 files)
C:\q2/baseq2/pak1.pak (279 files)
C:\q2/baseq2/pak0.pak (1106 files)
C:\q2/baseq2

----------------------
2087 files in PAK/PK2 files
Cvar_Set2: deathmatch "1"
Cvar_Set2: maxclients "8"
Loading DLL file q2e_gamex86.dll...
-------- Game Initialization --------
gamename: baseq2
gamedate: Jun 21 2007
CM_LoadMap( maps/q2dm1.bsp, 0 )
Cvar_Set2: sv_gravity "800"
0 entities inhibited
0 teams with 0 entities
Cvar_Set2: needpass "0"
Cvar_Set2: sv_mapName "q2dm1"
Cvar_Set2: sv_mapChecksum "80717714"
-------------------------------------
Master server at 192.246.40.32:27900
Sending heartbeat to 192.246.40.32:27900...
]quit
------- Server Shutdown -------
Sending heartbeat to 192.246.40.32:27900...
==== ShutdownGame ====
Unloading DLL file 'q2e_gamex86.dll'...
-------------------------------


attached are the strings (original and altered ones)... you will see that are the same, aside the altered (FinalStr) have more 15 added to his origin.Z, are the only difference between them...

and in game works very well!

now I need a little more help from you to finish this hard task! Wink

thanks a lot! Cheesy

* entityORI.txt (12.62 KB - downloaded 276 times.)
* FinalStr.txt (12.62 KB - downloaded 252 times.)
Logged
Pages: 1 2 3 [All]
Print
r1ch.net  |  General  |  General Discussion  |  Topic: Trying to fix the Siamese Twins problem...
Jump to:  

Powered by SMF 1.1.19 | SMF © 2013, Simple Machines