Quake3World.com Forums
     Programming Discussion
        Entity flags aren't being transmitted / cgame issues


Post new topicReply to topic
Login | Profile | | FAQ | Search | IRC




Print view Previous topic | Next topic 
Topic Starter Topic: Entity flags aren't being transmitted / cgame issues

Insane Quaker
Insane Quaker
Joined: 16 Sep 2010
Posts: 391
PostPosted: 06-06-2018 09:54 AM           Profile Send private message  E-mail  Edit post Reply with quote


Hello! I haven't been here in a while, but I've recently released the first version of a mod I've been working on called Uber Arena, which you can read about here: http://www.celephais.net/board/view_thread.php?id=61575

So the development of the mod has mostly been going pretty smooth so far, but I recently ran into a huge roadblock that's preventing me from implementing a very important visual clarity feature in the mod, and I've tried for 3 days coming up with various complicated attempted solutions that either don't work or present other issues.

This will be a lengthy post, so hopefully I've gotten all the relevant information in here. Anyway...

To start things off, the trademark mechanic of this mod is uberweapons, which work like this: you collect 3 of the same weapon without dying in between, and that weapon gets upgraded into its uberweapon version. The way this mechanic works in the code is that it uses a set of integer counters corresponding to each non-starter weapon, located in the gclient_s structure in g_local.h. Each time a weapon is picked up, that weapon's corresponding counter is incremented. Once the counter reaches 3, any uberweapon-specific functionality will start running. The uberweapons are not technically new, separate weapons - that would be impossible for me to do, because that would require defining 7 new weapons in weapon_t, which would exceed the MAX_WEAPONS limit of 16 as defined in q_shared.h - and of course I can't change that limit without totally screwing up the entire game. q_shared.h is pretty much untouchable for mods apart from a very few select sections.

Now, from a pure gameplay perspective, all of the uberweapon-related mechanics work just fine. But now I'm moving onto visual / audio coding, which of course involves doing a lot of work in cgame. To attempt to communicate with the client game, I defined 7 new entity flags in bg_public.h, which can be set in game and then - well, in theory anyway (more on that in a minute) - be read in cgame. Each time an uberweapon counter hits 3, the game will turn on the appropriate uberweapon flag with the intention of allowing cgame to know that the player has an uberweapon. Here are the flags and their values, respectively (they follow the hex notation format and sequencing as with the other eflags):

Code:
#define EF_UW_SHOTGUN 0x01000000 // explosive shotgun
#define EF_UW_GRENADE 0x02000000 // multi grenade
#define EF_UW_ROCKET 0x04000000 // homing rocket
#define EF_UW_LIGHTNING 0x08000000 // arc lightning
#define EF_UW_PLASMA 0x10000000 // ion plasma
#define EF_UW_RAIL 0x20000000 // toxic rail
#define EF_UW_BFG 0x40000000 // bfg30k


So when a player holds an uberweapon I want to draw a ring model with an energy orb shader that moves around the torso of the player. In theory, I should be able to do this by accessing EF_UW_SHOTGUN flag from cent->currentState.eFlags. I have the following code in the CG_Player function in cg_players.c:

Code:
if (cent->currentState.weapon == WP_SHOTGUN && (cent->currentState.eFlags & EF_UW_SHOTGUN))
{         
memcpy(&orbs, &torso, sizeof(torso));      
orbs.hModel = cgs.media.uberShotgunOrbModel;      
orbs.customSkin = 0;      
VectorCopy(torso.origin, orbs.origin);      
spinAngles[1] = cg.time * -0.2;      
AnglesToAxis(spinAngles, orbs.axis);      
trap_R_AddRefEntityToScene(&orbs);   
}


Now, without the (cent->currentState.eFlags & EF_UW_SHOTGUN) in the if condition, the game does correctly respond to the player having the shotgun currently in use or not. So it can clearly read what player the weapon is using just fine. However, with the condition checking for the EF_UW_SHOTGUN flag, the code doesn't execute at all. I did a CG_Printf test of the value returned by (cent->currentState.eFlags & EF_UW_SHOTGUN) above the if statement and it returns 0 even if I have an uberweapon, proving that the cgame code isn't responding to the changes in cent->currentState.eFlags.

I tried several methods to get this to work. Then I wrote this code in the PmoveSingle function in bg_pmove.c and it somehow started working:

Code:
if (pm->ps->stats[STAT_UBERS] & UW_SHOTGUN)
{      
pm->ps->eFlags |= EF_UW_SHOTGUN;   
}


So this kind of works, but the problem is that only -> I <- have this effect (checking with cg_thirdperson 1). But if you look at another player who is currently using an uberweapon, the effect does not show up on them, even though they too should have those flags set. I tried messing with the renderfx settings like RF_THIRD_PERSON and RF_FIRST_PERSON, but none of those have worked. I don't know why, because there's this section of Team Arena code also in the CG_Player function that controls the floating skull heads that appear when a player has Kamikaze:

Code:
if ( cent->currentState.eFlags & EF_KAMIKAZE )
{
memset( &skull, 0, sizeof(skull) );      
VectorCopy( cent->lerpOrigin, skull.lightingOrigin );      
skull.shadowPlane = shadowPlane;      
skull.renderfx = renderfx;      

if ( cent->currentState.eFlags & EF_DEAD ) {         
// one skull bobbing above the dead body         
angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;         
if (angle > M_PI * 2)            
angle -= (float)M_PI * 2;         
dir[0] = sin(angle) * 20;         
dir[1] = cos(angle) * 20;         
angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;         
dir[2] = 15 + sin(angle) * 8;      
VectorAdd(torso.origin, dir, skull.origin);
<goes on from here...>


This isn't the full code, but you can still see that also relies on flags (EF_KAMIKAZE and EF_DEAD), and it works fine there. In Team Arena, if another player has Kamikaze - in other words, they have EF_KAMIKAZE enabled, you can see the floating skulls around them, and it also reacts appropriately if the player is dead. But in my mod, if another player has an uberweapon and its respective flag enabled, I can't see their uberweapon effect, only my own (from my point of view, in cg_thirdperson 1). Why does it work in the former case, and not in my case?

Here's another problem: Even though the CG_Player function can now read (cent->currentState.eFlags & EF_UW_SHOTGUN) because of the code I put in bg_pmove.c from earlier, it doesn't seem to be reflected everywhere in cgame. In cg_ents.c, in the CG_Missile function, it seems like it can't read cent->currentState.eFlags, even though CG_Player can. In this case I want homing rockets fired from an upgraded rocket launcher to play a beeping noise. As with EF_UW_SHOTGUN, I put the following code in PmoveSingle, right underneath the one for the shotgun:

Code:
if (pm->ps->stats[STAT_UBERS] & UW_ROCKET)
{   
pm->ps->eFlags |= EF_UW_ROCKET;   
}


And here is a snippet of the missile code, with my tracking code at the bottom:

Code:
// add missile sound   
if ( weapon->missileSound )
{      
vec3_t   velocity;      
BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );      
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
// right below is my code            
if (weapon->trackSound && cent->currentState.eFlags & EF_UW_ROCKET) {         
trap_S_AddLoopingSound(cent->currentState.number, cent->lerpOrigin, velocity, weapon->trackSound);      
}   
}


It is perfectly capable of reading and retrieving values from its position and entity index (cent->currentState.pos and cent->currentState.number, respectively). However, it seems to completely ignore the entity flags I set for it (cent->currentState.eFlags & EF_UW_ROCKET). Why does it read the position / entity index properly, but not my flags? What's even stranger is that in CG_AddEntity, the function that calls CG_Missile, when I do a CG_Printf debug test to check the value of (cent->currentState.eFlags & EF_UW_ROCKET), it prints the int value of its hex constant, so it reads it properly there, just that for some reason it completely drops it when it gets passed into CG_Missile. And yes I tried stuff like assigning it to a boolean variable and passing it into CG_Missile (both by value and via a pointer to its address), but it always ends up coming out false after being passed, even if it was true in CG_AddEntity. Kind of defeats one of the main purposes of a function if it's just going to drop whatever I pass in, no?

This is a lot to take in, so I'll just summarize my goals here - I want to:

- Create a visual effect that displays on any player that is currently using an uberweapon.
- Make homing rockets play a targeting alert sound if they are fired by a player using a Homing Rocket Launcher.

Two goals that sound very simple to achieve in theory, but apparently are monstrously difficult in practice.

Thanks for any assistance in advance!



_________________
EmeraldProductions
http://emeraldproductions.weebly.com/index.html


Top
                 

Insane Quaker
Insane Quaker
Joined: 16 Sep 2010
Posts: 391
PostPosted: 06-11-2018 01:47 PM           Profile Send private message  E-mail  Edit post Reply with quote


Haven't previously, but I took the time to get one quickly set up here:
https://github.com/EmeraldTiger/Uber-Arena

(First time using GitHub to upload a real project, so forgive me if it's a bit messy :p)

Has a Visual Studio solution file provided in the /code folder.

As for the flags, I did a test by replacing the EF_UW_ROCKET flag with EF_AWARD_DENIED flag (since the game never uses it) which is below the client threshold, but it still demonstrates the same issues.



_________________
EmeraldProductions
http://emeraldproductions.weebly.com/index.html


Top
                 

Insane Quaker
Insane Quaker
Joined: 16 Sep 2010
Posts: 391
PostPosted: 06-13-2018 11:54 AM           Profile Send private message  E-mail  Edit post Reply with quote


Hey man, no problem. I really appreciate your honesty and insight, and you're absolutely right - the mod was very much built with a "solitary" mindset and much of what I wrote was simply trying to get things to work without looking at the bigger picture of maintainability or collaboration.

There's a bunch of experimental stuff that I wrote in an attempt to make the uberweapon effect code work that I ended up leaving behind. The ClientEvents stuff, for example, was one of those attempts - which kind of worked, but the player's shader effect would constantly "blink" and once the player had more than two uberweapons it would start to not render other uberweapon effects, probably because of too many events. Similar code in pmove was yet another example that didn't work out. (There's also a bunch of code for so-far failed attempts or experiments at features that never made it in, such as upside-down gravity surfaces)

As for moving the holdable code to g_active, I did this because I had to access code that was not accessible in bg_pmove.c, since that module only has access to game information common between game and cgame. I wouldn't be able to access the uberweapon Counters in bg_pmove.c, for example, because they're declared in g_local.h, which bg_pmove.c has no access to. In general I found that being in bg_pmove.c was too restrictive for my purposes, which is why I moved it. So far I haven't had any issues that would seem to stem from it, and it has worked okay for me, but I'm sure there's probably a better way of doing it (though I'm not sure what it'd be). The only other method I can think of would be keeping it in bg_pmove.c but passing in variables from g_active.c to the Pmove function, then to PmoveSingle, and then finally to PWeapon, but just straight-up moving the code seemed simpler to me.

I did use a fresh, from-scratch codebase to test the kamikaze stuff, and the skulls appear fine with EF_KAMIKAZE. But then I did a test where I replaced all instances of EF_KAMIKAZE in the source with my own custom flag (apart from the initial declaration, of course), and suddenly it stops working. Same thing happens when I replace it with the otherwise unused EF_AWARD_DENIED. Which is weird since in theory it should still work, as the only thing different is the flag being set.

I'll be the first to admit that I have never worked in a collaborative programming environment, nor have I really took the time to use a proper versioning system, use pull requests, etc. I can see now that it is something I should take more seriously, so I'll definitely make an effort to learn more about how to make a more maintainable programming environment. I was always a bit intimidated by it but hopefully it isn't as difficult as I think it is (in the long run it would make things easier, I realize).

I'll also give ioquake3 source a try and see if it may work better / solve my issues. The codebase I've been using is based on https://github.com/id-Software/Quake-III-Arena. If I can get ioquake3 set up for Visual Studio 2017 then that'd be awesome.

Once again, many thanks for your honesty and suggestions. I think a wake-up call is exactly what I needed. Even if I start from scratch it shouldn't take too long to get things back up to where they are now, but hopefully it will be a lot cleaner.

EDIT: Just downloaded the pure ioq3 source and tested the Kamikaze effect with my own entity flag as before (no other code changes). Still not showing up for any flag other than EF_KAMIKAZE. Very strange.



_________________
EmeraldProductions
http://emeraldproductions.weebly.com/index.html


Top
                 

Insane Quaker
Insane Quaker
Joined: 16 Sep 2010
Posts: 391
PostPosted: 07-26-2018 03:23 PM           Profile Send private message  E-mail  Edit post Reply with quote


(disregard; got some help over on ioquake3 for an issue related to .qvm compiling)



_________________
EmeraldProductions
http://emeraldproductions.weebly.com/index.html


Top
                 

Insane Quaker
Insane Quaker
Joined: 16 Sep 2010
Posts: 391
PostPosted: 01-24-2019 01:12 PM           Profile Send private message  E-mail  Edit post Reply with quote


Thanks for the encouragement Toku! :) Very appreciated.

The mod has made a lot of great progress since I last made this post, with a lot of cleanup of junk code in addition to new features, but sadly I am still running into the same issue of entity flags not being transmitted. To test it out, I quickly defined a flag in bg_public.h, using the established bitflag numbering scheme:

Code:
#define   EF_TELEPORT_BIT      0x00000004      // toggled every time the origin abruptly changes
#define   EF_AWARD_EXCELLENT   0x00000008      // draw an excellent sprite
#define EF_PLAYER_EVENT      0x00000010
#define   EF_BOUNCE         0x00000010      // for missiles
#define   EF_BOUNCE_HALF      0x00000020      // for missiles
#define   EF_AWARD_GAUNTLET   0x00000040      // draw a gauntlet sprite
#define   EF_NODRAW         0x00000080      // may have an event, but no model (unspawned items)
#define   EF_FIRING         0x00000100      // for lightning gun
#define   EF_KAMIKAZE         0x00000200      // UBER ARENA: repurposed for the arc lightning gun
#define   EF_MOVER_STOP      0x00000400      // will push otherwise
#define EF_AWARD_CAP      0x00000800      // draw the capture sprite
#define   EF_TALK            0x00001000      // draw a talk balloon
#define   EF_CONNECTION      0x00002000      // draw a connection trouble sprite
#define   EF_VOTED         0x00004000      // already cast a vote
#define   EF_AWARD_IMPRESSIVE   0x00008000      // draw an impressive sprite
#define   EF_AWARD_DEFEND      0x00010000      // draw a defend sprite
#define   EF_AWARD_ASSIST      0x00020000      // draw a assist sprite
#define EF_AWARD_TYRANT      0x00040000      // UBER ARENA: replace unused denied medal; draw a tyrant sprite
#define EF_TEAMVOTED      0x00080000      // already cast a team vote
#define   EF_POISONED         0x00100000      // poisoned by toxic railgun
#define EF_TRANSMIT      0x00200000      // just for testing


Bitwise OR assign / enable in the Upgrade_Weapon function:

Code:
void Upgrade_Weapon(int counter, gentity_t *other, int steps) {

   other->client->ps.eFlags |= EF_TRANSMIT; // just for testing

...


And a Bitwise AND / check in CG_Missile function:
Code:
if (cent->currentState.eFlags & EF_TRANSMIT) {
      CG_Printf("can you read this");
   }


So the intended outcome of this test is:
1. Upgrade any weapon into an uberweapon (either with 3x pickup, tuning device, or the /uber cmd - all call the same function Upgrade_Weapon). EF_TRANSMIT is turned on.
2. Game should print "can you read this" continuously while a missile is in the air, if the person who fired it has an uberweapon, since EF_TRANSMIT should now be on.
(And I can easily revert this test code since I make regular commits to GitHub)

But, just like my last attempts, nothing happens - the game still refuses to send over the information from the server to the client. Would love to know if anyone has ran into similar struggles in the past, what their solutions were, and why the problem occurs in the first place. The ability for me to send information this way is necessary for me to implement things like homing rocket tracking sounds, or recoloring the ion plasma gun bolts (special effects dependent on the player having an uberweapon).



_________________
EmeraldProductions
http://emeraldproductions.weebly.com/index.html


Top
                 

The hell good boy
The hell good boy
Joined: 22 Jun 2011
Posts: 1922
PostPosted: 01-25-2019 12:02 AM           Profile   Send private message  E-mail  Edit post Reply with quote


Code:
#define EF_PLAYER_EVENT      0x00000010
#define   EF_BOUNCE         0x00000010      // for missiles

Hmm, do these flags reffer to different settings? Because otherwise this will cause some serious issues...



_________________
[ Websites | Facebook | Twitter | YouTube | Instagram ]
When you feel the worst, turn to the sun and all the shadows will fall behind you.” - John Lennon


Top
                 
Quake3World.com | Forum Index | Programming Discussion


Post new topic Reply to topic


cron
Quake3World.com
© ZeniMax. Zenimax, QUAKE III ARENA, Id Software and associated trademarks are trademarks of the ZeniMax group of companies. All rights reserved.
This is an unofficial fan website without any affiliation with or endorsement by ZeniMax.
All views and opinions expressed are those of the author.