Jump to content

Home

Q3 Engine Game Bugs / JA bugs


ensiform

Recommended Posts

haha, great minds think alike. I fixed several of those errors at well. However, I did them a little differently. As always, all OJP bugfixes are available thru the OJP CVS repository.

 

invisibility vehicle driver bug FIX

The real source of that problem is the unghostrider function not being called for disconnected players. I just made the unghostrider function always apply since there's no reason not to.

 

unlock door exploit FIX

I just relocked the doors after the Use_BinaryMover but that works too. :)

 

I haven't actually fixed the last one yet.

Link to comment
Share on other sites

  • Replies 229
  • Created
  • Last Reply

I just relocked the doors after the Use_BinaryMover but that works too.

 

yes i did that in my first fix because i saw a similar coding in the basejka code somewhere else...

 

but i prefered to recoder another function...

i didn't think it was good to unlock the doors then call the function and then reclock the doors...

Link to comment
Share on other sites

  • 2 weeks later...
  • 1 month later...

yay more fixes! :

 

1. Voice Commands show up in the notify box as well as chat box when console is not up?

 

Easy Client Fix:

(this also escapes the rest of line to white after name)

 

cg_event.c

 

look for this line:

 

char vchatstr[1024];

 

change the 3 lines below it to look like this:

strcpy(vchatstr, va("<%s^7: %s>", ci->name, descr));
CG_Printf( "*%s\n", vchatstr );
CG_ChatBox_AddString(vchatstr);

 

2. CTF Messages dont escape to white after player names:

 

cg_event.c

 

CG_PrintCTFMessage

 

Com_sprintf(printMsg, sizeof(printMsg), "%s ", ci->name);

 

should be:

 

Com_sprintf(printMsg, sizeof(printMsg), "%s^7 ", ci->name);

 

and

 

Com_sprintf(printMsg, sizeof(printMsg), "%s %s", ci->name, psStringEDString);

 

should be:

 

Com_sprintf(printMsg, sizeof(printMsg), "%s^7 %s", ci->name, psStringEDString);

 

3. New security bug out for quake 3 engine, thought it wasnt fixable without engine?

 

add this somewhere in bg_misc.c:

 

/*
============
COM_StripExtensionSafe
============
*/
void COM_StripExtensionSafe( const char *in, char *out, int destsize ) {
int             length;

Q_strncpyz(out, in, destsize);

length = strlen(out)-1;
while (length > 0 && out[length] != '.')
{
	length--;
	if (out[length] == '/')
		return;		// no extension
}
if (length)
	out[length] = 0;
}

 

and declare it somewhere in bg_public.h:

 

void COM_StripExtensionSafe( const char *in, char *out, int destsize );

 

now replace all instances of COM_StripExtension in your source with

 

COM_StripExtensionSafe and the destsize should be sizeof(change me to the char of out)

 

ie:

 

COM_StripExtensionSafe(fileptr, configname, sizeof(configname));

 

even more...

 

cg_servercmds.c:

 

look for "remapShader" command in the function CG_ServerCommand and replace that whole if statement for remapShader to:

 

	if ( Q_stricmp (cmd, "remapShader") == 0 )
{
	if (trap_Argc() == 4)
	{
		char shader1[MAX_QPATH];
		char shader2[MAX_QPATH];
		char shader3[MAX_QPATH];

		Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1));
		Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2));
		Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3));

		trap_R_RemapShader(shader1, shader2, shader3);
	}

	return;
}

 

last file in cgame for this bugfix, cg_syscalls.c:

 

comment out or delete the trap_R_RemapShader function and replace it with this:

 

void	trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
char oldShaderTMP[MAX_QPATH];
char newShaderTMP[MAX_QPATH];
Q_strncpyz(oldShaderTMP, oldShader, sizeof(oldShaderTMP));
Q_strncpyz(newShaderTMP, newShader, sizeof(newShaderTMP));
COM_StripExtensionSafe(oldShaderTMP, oldShaderTMP, sizeof(oldShaderTMP));
COM_StripExtensionSafe(newShaderTMP, newShaderTMP, sizeof(newShaderTMP));
syscall( CG_R_REMAP_SHADER, oldShaderTMP, newShaderTMP, timeOffset );
}

 

k now open up ui_syscalls.c:

 

do the same thing for ui_syscalls.c as cg_syscalls.c only the syscall itself is changed ( UI_R_REMAP_SHADER ):

 

void	trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
char oldShaderTMP[MAX_QPATH];
char newShaderTMP[MAX_QPATH];
Q_strncpyz(oldShaderTMP, oldShader, sizeof(oldShaderTMP));
Q_strncpyz(newShaderTMP, newShader, sizeof(newShaderTMP));
COM_StripExtensionSafe(oldShaderTMP, oldShaderTMP, sizeof(oldShaderTMP));
COM_StripExtensionSafe(newShaderTMP, newShaderTMP, sizeof(newShaderTMP));
syscall( UI_R_REMAP_SHADER, oldShaderTMP, newShaderTMP, timeOffset );
}

 

now ui_atoms.c:

 

look for this line:

 

if ( Q_stricmp (cmd, "postgame") == 0 ) {

 

above it add:

 

	if ( Q_stricmp (cmd, "remapShader") == 0 ) {
	if (trap_Argc() == 4) {
		char shader1[MAX_QPATH];
		char shader2[MAX_QPATH];
		char shader3[MAX_QPATH];

		Q_strncpyz(shader1, UI_Argv(1), sizeof(shader1));
		Q_strncpyz(shader2, UI_Argv(2), sizeof(shader2));
		Q_strncpyz(shader3, UI_Argv(3), sizeof(shader3));

		trap_R_RemapShader(shader1, shader2, shader3);
		return qtrue;
	}
}

 

i think that is all for this bug.

 

Source of bug:

 

http://www.gamer.nl/doc/32206

 

Translated by Babelfish:

 

Gamers which still old, on the Quake 3 Engine play based games have been warned. Are not only slow you desperately, also a serious leak in the engine as a result of which can computer offenders, crackers and other gajes take over your PC'tje, has been discovered.

 

The leak is caused by "boundary error" during the processing of the "remapShader" commando. This can lead to a buffer overflow, as a result of which the attacker can carry out in question random commandos and software on the vulnerable PC..

 

If this is all too technical for your, then you must remember simply to make no connection with "malicious servers". An attacker must to abuse the leak, as it happens, by means of its server a command to the PC. send.

 

Enemy Territory 2.60, return to Castle Wolfenstein 1.41 and Quake III and 1.32b is vulnerable, but also other versions its probable leak.

 

4. Limbs dont take team color if u have a custom rgb model

 

g_combat.c:

 

in function G_Dismember:

 

	limb->s.customRGBA[0] = ent->s.customRGBA[0];
limb->s.customRGBA[1] = ent->s.customRGBA[1];
limb->s.customRGBA[2] = ent->s.customRGBA[2];
limb->s.customRGBA[3] = ent->s.customRGBA[3];

should be:

 

	if (g_gametype.integer >= GT_TEAM) {
	switch(ent->client->sess.sessionTeam)
	{
	case TEAM_RED:
		limb->s.customRGBA[0] = 255;
		limb->s.customRGBA[1] = 0;
		limb->s.customRGBA[2] = 0;
		break;
	case TEAM_BLUE:
		limb->s.customRGBA[0] = 0;
		limb->s.customRGBA[1] = 0;
		limb->s.customRGBA[2] = 255;
		break;
	default:
		limb->s.customRGBA[0] = ent->s.customRGBA[0];
		limb->s.customRGBA[1] = ent->s.customRGBA[1];
		limb->s.customRGBA[2] = ent->s.customRGBA[2];
		limb->s.customRGBA[3] = ent->s.customRGBA[3];
		break;
	}
} else {
	limb->s.customRGBA[0] = ent->s.customRGBA[0];
	limb->s.customRGBA[1] = ent->s.customRGBA[1];
	limb->s.customRGBA[2] = ent->s.customRGBA[2];
	limb->s.customRGBA[3] = ent->s.customRGBA[3];
}

 

5. weird tint for the meters and values when playing ffa or on blue team

 

cg_draw.c

 

look for this:

 

if (cgs.gametype >= GT_TEAM && cgs.gametype != GT_SIEGE)
{	// tint the hud items based on team
	if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED )
		hudTintColor = redhudtint;
	else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
		hudTintColor = bluehudtint;
	else // If we're not on a team for whatever reason, leave things as they are.
		hudTintColor = colorTable[CT_WHITE];
}
else
{	// tint the hud items white (dont' tint)
	hudTintColor = colorTable[CT_WHITE];
}

 

replace it with:

 

hudTintColor = redhudtint;	// always use red because blue and white screws it up

 

6. flag icons have a dark tint when you are in scope because raven forgets to do trap_R_SetColor(NULL) after every change in color thats not needed anymore.

 

cg_draw.c again:

 

CG_DrawFlagStatus

 

above the !cg.snap line add:

 

trap_R_SetColor( NULL );

 

also CG_DrawPowerupIcons

 

add

 

trap_R_SetColor( NULL );

 

same spot as flagstatus

Link to comment
Share on other sites

  • 2 months later...

This code in G_SayTo doesn't really work and it is kinda pointless to disable chat, it would make more sense to write something better that disables the voice chat instead.

 

if (g_gametype.integer == GT_SIEGE &&
	ent->client && (ent->client->tempSpectate >= level.time || ent->client->sess.sessionTeam == TEAM_SPECTATOR) &&
	other->client->sess.sessionTeam != TEAM_SPECTATOR &&
	other->client->tempSpectate < level.time)
{ //siege temp spectators should not communicate to ingame players
	return;
}

 

if you still use the base method of voice_cmd add this in Cmd_VoiceCommand_f:

 

	if ( g_gametype.integer == GT_SIEGE && 
		ent->client->tempSpectate >= level.time ) {
	return;
}

 

otherwise add it to G_Voice.

Link to comment
Share on other sites

don't show the cursor during map load:

 

ui_main.c in function _UI_Refresh:

 

look for this piece of code:

 

	// draw cursor
UI_SetColor( NULL );
if (Menu_Count() > 0) {
	UI_DrawHandlePic( uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory, 48, 48, uiInfo.uiDC.Assets.cursor);
}

 

change it to:

 

	// draw cursor
UI_SetColor( NULL );
if (Menu_Count() > 0) {
	uiClientState_t	cstate;
	trap_GetClientState( &cstate );
	if(cstate.connState <= CA_DISCONNECTED || cstate.connState >= CA_ACTIVE) {
		UI_DrawHandlePic( uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory, 48, 48, uiInfo.uiDC.Assets.cursor);
	}
}

Link to comment
Share on other sites

k so this one is kind of raven's fault, they forgot many many many checks for their EF_DOUBLE_AMMO, thus tech's cannot give you ammo > than the normal max and you cannot pickup ammo > normal max (this is usually for siege).

 

Open up g_items.c and Change the function "Add_Ammo" to look like this:

 

void Add_Ammo (gentity_t *ent, int weapon, int count)
{
if ( ent->client->ps.eFlags & EF_DOUBLE_AMMO ) {
	if ( ent->client->ps.ammo[weapon] < ammoData[weapon].max*2 )
	{
		ent->client->ps.ammo[weapon] += count;
		if ( ent->client->ps.ammo[weapon] > ammoData[weapon].max*2 )
		{
			ent->client->ps.ammo[weapon] = ammoData[weapon].max*2;
		}
	}
} else {
	if ( ent->client->ps.ammo[weapon] < ammoData[weapon].max )
	{
		ent->client->ps.ammo[weapon] += count;
		if ( ent->client->ps.ammo[weapon] > ammoData[weapon].max )
		{
			ent->client->ps.ammo[weapon] = ammoData[weapon].max;
		}
	}
}
}

 

Open up g_utils.c and look for the function "G_UseDispenserOn":

 

change the else if statement for ammodisp to:

 

	else if (dispType == HI_AMMODISP)
{
	if (ent->client->medSupplyDebounce < level.time)
	{ //do the next increment
		//increment based on the amount of ammo used per normal shot.
		target->client->ps.ammo[weaponData[target->client->ps.weapon].ammoIndex] += weaponData[target->client->ps.weapon].energyPerShot;

		if ( target->client->ps.eFlags & EF_DOUBLE_AMMO ) {
			if (target->client->ps.ammo[weaponData[target->client->ps.weapon].ammoIndex] > ammoData[weaponData[target->client->ps.weapon].ammoIndex].max*2)
			{ //cap it off
				target->client->ps.ammo[weaponData[target->client->ps.weapon].ammoIndex] = ammoData[weaponData[target->client->ps.weapon].ammoIndex].max*2;
			}
		} else {
			if (target->client->ps.ammo[weaponData[target->client->ps.weapon].ammoIndex] > ammoData[weaponData[target->client->ps.weapon].ammoIndex].max)
			{ //cap it off
				target->client->ps.ammo[weaponData[target->client->ps.weapon].ammoIndex] = ammoData[weaponData[target->client->ps.weapon].ammoIndex].max;
			}
		}

		//base the next supply time on how long the weapon takes to fire. Seems fair enough.
		ent->client->medSupplyDebounce = level.time + weaponData[target->client->ps.weapon].fireTime;
	}
	target->client->isMedSupplied = level.time + 500;
}

 

next function down "G_CanUseDispOn":

 

 

change the else if statement for ammodisp to:

 

	else if (dispType == HI_AMMODISP)
{
	if (ent->client->ps.weapon <= WP_NONE || ent->client->ps.weapon > LAST_USEABLE_WEAPON)
	{ //not a player-useable weapon
		return 0;
	}

	if ( ent->client->ps.eFlags & EF_DOUBLE_AMMO ) {
		if (ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex] < ammoData[weaponData[ent->client->ps.weapon].ammoIndex].max*2)
		{ //needs more ammo for current weapon
			return 1;
		}
	} else {
		if (ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex] < ammoData[weaponData[ent->client->ps.weapon].ammoIndex].max)
		{ //needs more ammo for current weapon
			return 1;
		}
	}

	//needs none
	return 0;
}

 

I think that is all.

Link to comment
Share on other sites

This code in G_SayTo doesn't really work and it is kinda pointless to disable chat, it would make more sense to write something better that disables the voice chat instead.

I think the point was to prevent dead/spectators from revealing information to live players in the game.

Link to comment
Share on other sites

this bug is kinda funny, raven forgot to put a tempSpec check in /follow and followprev/next.

 

Cmd_Follow_f add this below the other spectator check:

 

	// can't follow another spectator
if ( level.clients[ i ].tempSpectate >= level.time ) {
	return;
}

 

Cmd_FollowCycle_f add this below the other spectator check in the do while loop:

 

		// can't follow another spectator
	if ( level.clients[ clientnum ].tempSpectate >= level.time ) {
		continue;
	}

 

also, there are some pieces in the code that check if tempSpectate > level.time, it should always be >= level.time because level.time and above means you are tempSpectate, less than means you are not.

Link to comment
Share on other sites

if you are a real spectator (team s) and watching a siege game and someone who is "dead" (tempSpectator) you follow them around while they are in tempSpectate mode. This fixes it so that you don't follow them while they are moving freely.

 

 

Btw, I have figured out a way to make spectators move through most entities now even doors, and the security walls on desert and even the red forcefield on hoth. This way spectators do not have to rely on using the crappy teleport thing which doesn't always work if the map has a forced trigger or sometimes it teleports you out of the level causing you to be in the void. :/ If you want me to post this its a bit of a hack in some trace code on server and client for slight stability but it works very well.

Link to comment
Share on other sites

Also, somewhat of a bug: There should only be 3 places where ps.clientNum should be used on the game module, anything else can potentially cause troubles with specators. For example, your code for auto balance in ojp will sometimes spam to the spectator "You were switched" message. Or even use the spectator's name in messages, or in the duel/pduel check code it could potentially pick a spectator when it didn't mean to.

 

You should only have these lines:

 

Near Top of ClientUserInfoChanged:

 

client->ps.clientNum = clientNum;

 

Here in ClientSpawn:

 

	client->ps.clientNum = index;
//give default weapons
client->ps.stats[sTAT_WEAPONS] = ( 1 << WP_NONE );

 

and...

 

In Stop Following:

 

ent->client->ps.clientNum = ent - g_entities;

 

Use gentity_t->s.number or gentity_t - g_entities.

 

(gentity_t being the entity you want the number from)

 

anything ps->clientNum (meaning something from pmove usually) and client-side is required that it be used but the server no.

Link to comment
Share on other sites

I don't really want to describe it however its hard to explain why it is a bug:

 

- Play hoth until you gain the access codes

- Get the codes

- Bring them to AT-ST and get in and type this in console without the quotes but the space:

" /reconnect"

- Even though the player may not be still visible, the objective item never was told the client wasn't 'inuse'. / disconnected.

 

Add this to ClientDisconnect just below this line:

 

ent->r.contents = 0;

 

	if (ent->client->holdingObjectiveItem > 0)
{ //carrying a siege objective item - make sure it updates and removes itself from us now in case this is an instant death-respawn situation
	gentity_t *objectiveItem = &g_entities[ent->client->holdingObjectiveItem];

	if (objectiveItem->inuse && objectiveItem->think)
	{
           objectiveItem->think(objectiveItem);
	}
}

Link to comment
Share on other sites

Minor bug when pressing fire on a speeder that allows the speeder to still fire if only 1 of two sabers are on or if 1 blade of staff is on.

 

Open up g_active.c and just above G_CheapWeaponFire function extern this:

 

extern qboolean BG_SabersOff( playerState_t *ps );

 

then inside the function the following line should be repleaced:

 

(rider->client->ps.weapon != WP_SABER || !rider->client->ps.saberHolstered))

 

with:

 

(rider->client->ps.weapon != WP_SABER || !BG_SabersOff(&rider->client->ps)))

Link to comment
Share on other sites

Anybody ever heard of the "speeder lag 'bug'" ?

 

I think I've got a theory as to why. I was playing siege earlier today and I had originally though, well hell maybe they forgot to clear ent->client->ps.m_iVehicleNum in StopFollowing because somebody had mentioned that it only occurs after spectating somebody.

 

This code is untested but I'm just wondering if maybe forcing the spectator to exit the vehicle if they were in one.

 

StopFollowing (g_cmds.c):

 

	if (ent->client->ps.m_iVehicleNum)
{ //tell it I'm getting off
	gentity_t *veh = &g_entities[ent->client->ps.m_iVehicleNum];

	if (veh->inuse && veh->client && veh->m_pVehicle)
	{
		veh->m_pVehicle->m_pVehicleInfo->Eject(veh->m_pVehicle, (bgEntity_t *)ent, qtrue);
	}
}

 

note: make sure you put this above where it clears ent->client->ps.m_iVehicleNum.

Link to comment
Share on other sites

zomg this bug is really annoying: http://www.lucasforums.com/showthread.php?t=168805

 

Why should arena files not load on the server if bot_enable is off? :smash:

 

Open up these 2 files: g_bot.c, g_main.c

 

First make G_LoadArenas not static.

 

Then extern G_LoadArenas above G_InitGame in g_main.c.

 

Then change this if statement (G_InitGame):

 

	if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
	BotAISetup( restart );
	BotAILoadMap( restart );
	G_InitBots( restart );
}

 

to this:

 

	if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
	BotAISetup( restart );
	BotAILoadMap( restart );
	G_InitBots( restart );
} else {
	// We still want to load arenas even if bot_enable is off so that 
	// g_autoMapCycle can work let alone any other code that relies on 
	// using arena information that normally wouldn't be loaded :Nervous
	G_LoadArenas();
}

Link to comment
Share on other sites

Not sure why this happens but here's how to test it:

 

Make sure you are in siege.

Have a Rancor grab you so he is in your hands, then change your siegeclass before he kills you. You will die, but he will be in an infinite loop of trying to kill you and it won't let you spawn until you /team s.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.


×
×
  • Create New...