Re: [ioquake3] Accessing gentity_t->health from the engine

2012-03-10 Thread Stephen LARROQUE
Hello Ben,

Thank you very much for your code, I wish I could write so much complicated
defines by myself ;)

Unfortunately your code does not work right away, first because as_gent
takes entityShared_t as argument instead of sharedEntity_t, and secondly
your function only returns the r member, which is in fact an
entityShared_t, but this is not what I'm looking for.

>From what I understand, your function takes a field of a sharedEntity_t and
returns it as a gentity_t, but here I need a field that is only to be found
in gentity_t: health, and so it seems your code does not fit very well, but
it's a good idea (I like the generic defines!) and I keep it safe for the
future, it may be useful :)

Anyway I could make my initial code work, in fact I was very near to the
goal, I only did a stupid mistake in the declarations in server.h :p

For informations if someone ever has similar needs as mine, it was pretty
simple in the end but pretty complicated to find how to do it.

The simple trick is to find a way to include both declarations of gentity_t
and sharedEntity_t, and then you can simply cast a sharedEntity_t into a
gentity_t.

The way I did this is pretty simple:

#include "../game/g_local.h" // get both the definitions of gentity_t (to
get gentity_t->health field) AND sharedEntity_t, so that we can convert a
sharedEntity_t into a gentity_t (see more details in
SV_GentityUpdateHealthField() notes)

Then, to declare my functions so that they are accessible from any
/server/*.c files, is to also include in my file:

#include "../qcommon/qcommon.h" // needed so that the public declarations
in server.h can access these functions (because server.h links to qcommon.h
-- in the end, no includes redundancy conflicts and every server files can
access these functions!)

And then declare my functions in server.h. This way, the compiler can find
my functions by crawling server.h -> qcommon.h -> myfile.c, and without any
includes redundancy!

So beware, you must NOT include server.h directly, else you can't include
g_local.h

And finally, you can simply make a function like this one:

void SV_GentitySetHealthField( sharedEntity_t * gent, int value ) {
gentity_t *ent;

ent = (gentity_t*)gent; // convert the sharedEntity_t to a gentity_t by
using a simple cast

ent->health = value;
}

And that's it!

Also another way to do it is to redeclare the whole gentity_t (and some
other structs such as movers_t if I remember well, because they are
necessary for the declaration of gentity_t), and then it also works, and
you can then include server.h and avoid including g_local.h, but then with
this solution you get a BIG redundancy because gentity_t gets declared
twice, and if one is updated the other won't...

So in the end, I'm pretty satisfied with my solution.

The final version should soon be released of my server-side demos patch
should soon be released (see the thread linked in my first message). I am
also thinking about another slimer and maybe cleaner way of managing
server-side demos, if I get some spare time I'll maybe give it a try.



Le 2 mars 2012 00:30, Ben Noordhuis  a écrit :

> On Fri, Mar 2, 2012 at 00:13, Stephen LARROQUE  wrote:
> > Hello,
> >
> > I am currently trying to make a server-side demos patch for OpenArena
> which
> > should be completely compatible with standard ioquake3.
> >
> > My goal is almost achieved, but I face one last problem: the health is
> not
> > updated in the HUD when spectating a democlient. Every other stat is (eg:
> > ammos, armor, etc.), except health.
> >
> > I could track down the problem, and it seems that even if there is a
> > playerState_t->stats[STAT_HEALTH] field, contrary to the others such as
> > STAT_ARMOR, this one is not directly used, and most of the time it's
> > gentity_t->health that is taken in account for damage processing and
> health
> > drawing.
> >
> > I know I can edit the gamecode, but I would like the patch to be fully
> > managed server-side to ensure a full compatibility with mods.
> >
> > My question is: do you guys know of a way to access, and set, the health
> > field from gentity_t from the engine?
> >
> > I tried to cast a sharedEntity_t into a gentity_t, but without much
> result,
> > the values are completely off.
> >
> > Thank you for reading me,
> > Stephen L.
>
> How and where do you cast it? It should (could!) work provided that
> you take the field offset into account. Your code should look
> something like this:
>
> #define offset_of(type, member) \
>  ((intptr_t) ((char *) &(((type *) 8)->member) - 8))
>
> #define container_of(ptr, type, member) \
>  ((type *) ((char *) (ptr) - offset_of(type, member)))
>
> gentity_t *as_gent(entityShared_t *shared_ent) {
>  return container_of(shared_ent, entityShared_t, r);
> }
> ___
> ioquake3 mailing list
> ioquake3@lists.ioquake.org
> http://lists.ioquake.org/listinfo.cgi/ioquake3-ioquake.org
> By sending this message I agree to love ioquake3 and

Re: [ioquake3] Accessing gentity_t->health from the engine

2012-03-10 Thread Ben Noordhuis
On Sat, Mar 10, 2012 at 19:07, Stephen LARROQUE  wrote:
> Hello Ben,
>
> Thank you very much for your code, I wish I could write so much complicated
> defines by myself ;)
>
> Unfortunately your code does not work right away, first because as_gent
> takes entityShared_t as argument instead of sharedEntity_t, and secondly
> your function only returns the r member, which is in fact an entityShared_t,
> but this is not what I'm looking for.

Yes, sorry. There's a typo in the example, it should have read:

  return container_of(shared_ent, gentity_t, r);

IOW, take the field offset of `r` and subtract it from the
`shared_ent` pointer to get the address of the enclosing `gentity_t`
struct.
___
ioquake3 mailing list
ioquake3@lists.ioquake.org
http://lists.ioquake.org/listinfo.cgi/ioquake3-ioquake.org
By sending this message I agree to love ioquake3 and libsdl.