Forum

Game code in C

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Game code in C

Postby JasonX » Fri Mar 11, 2016 3:57 am

I'm working on my engine port and i've decided to drop QuakeC altogether and use pure C, or even an external DLL in the future, for the game code. Does anyone know where to start on this? I mean, just the basics like the ScratchQC project: loading a map and putting a camera there. What are the functions that QuakeC itself calls?
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby Baker » Fri Mar 11, 2016 2:47 pm

pr_cmds.c

Code: Select all
static builtin_t pr_builtin[] =
{
PF_Fixme,
PF_makevectors,   // void(entity e)   makevectors       = #1
PF_setorigin,   // void(entity e, vector o) setorigin   = #2
PF_setmodel,   // void(entity e, string m) setmodel   = #3
PF_setsize,   // void(entity e, vector min, vector max) setsize = #4
PF_Fixme,   // void(entity e, vector min, vector max) setabssize = #5
PF_break,   // void() break                  = #6
PF_random,   // float() random                  = #7
PF_sound,   // void(entity e, float chan, string samp) sound = #8
PF_normalize,   // vector(vector v) normalize         = #9
PF_error,   // void(string e) error            = #10
PF_objerror,   // void(string e) objerror            = #11
PF_vlen,   // float(vector v) vlen            = #12
PF_vectoyaw,   // float(vector v) vectoyaw      = #13
PF_Spawn,   // entity() spawn                  = #14
PF_Remove,   // void(entity e) remove            = #15
PF_traceline,   // float(vector v1, vector v2, float tryents) traceline = #16
PF_checkclient,   // entity() clientlist               = #17
PF_Find,   // entity(entity start, .string fld, string match) find = #18
PF_precache_sound,   // void(string s) precache_sound      = #19
PF_precache_model,   // void(string s) precache_model      = #20
PF_stuffcmd,   // void(entity client, string s)stuffcmd = #21
PF_findradius,   // entity(vector org, float rad) findradius = #22
PF_bprint,   // void(string s) bprint            = #23
PF_sprint,   // void(entity client, string s) sprint = #24
PF_dprint,   // void(string s) dprint            = #25
PF_ftos,   // void(string s) ftos            = #26
PF_vtos,   // void(string s) vtos            = #27
PF_coredump,
PF_traceon,
PF_traceoff,
PF_eprint,   // void(entity e) debug print an entire entity
PF_walkmove, // float(float yaw, float dist) walkmove
PF_Fixme, // float(float yaw, float dist) walkmove
PF_droptofloor,
PF_lightstyle,
PF_rint,
PF_floor,
PF_ceil,
PF_Fixme,
PF_checkbottom,
PF_pointcontents,
PF_Fixme,
PF_fabs,
PF_aim,
PF_cvar,
PF_localcmd,
PF_nextent,
PF_particle,
PF_changeyaw,
PF_Fixme,
PF_vectoangles,

PF_WriteByte,
PF_WriteChar,
PF_WriteShort,
PF_WriteLong,
PF_WriteCoord,
PF_WriteAngle,
PF_WriteString,
PF_WriteEntity,

PF_sin,
PF_cos,
PF_sqrt,
PF_changepitch,
PF_TraceToss, // 65?
PF_etos,
PF_Fixme, // PF_WaterMove,

SV_MoveToGoal,
PF_precache_file,
PF_makestatic,

PF_changelevel,
PF_Fixme,

PF_cvar_set,
PF_centerprint,

PF_ambientsound,

PF_precache_model,
PF_precache_sound,      // precache_sound2 is different only for qcc
PF_precache_file,

PF_setspawnparms
};
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Game code in C

Postby JasonX » Fri Mar 11, 2016 8:05 pm

Well, but i don't think that i can just call the PF_* functions directly. They seem to have globals and a stack to grab the args from. So, for example, i would have to start to re-implement most of them, right? Take precaching, for example:

Code: Select all
void PF_precache_model(void)
{
    char *s;
    int i;

    if (sv.state != ss_loading) {
        PR_RunError("PF_Precache_*: Precache can only be done in spawn functions");
    }

    s = G_STRING(OFS_PARM0);
    G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
    PR_CheckEmptyString(s);

    for (i = 0; i < MAX_MODELS; i++) {
        if (!sv.model_precache[i]) {
            sv.model_precache[i] = s;
            sv.models[i] = Mod_ForName(s, true);
            return;
        }

        if (!strcmp(sv.model_precache[i], s)) {
            return;
        }
    }

    PR_RunError("PF_precache_model: overflow");
}


Would become:

Code: Select all
void precache_model(char* s)
{
    int i;

    for (i = 0; i < MAX_MODELS; i++) {
        if (!sv.model_precache[i]) {
            sv.model_precache[i] = s;
            sv.models[i] = Mod_ForName(s, true);
            return;
        }

        if (!strcmp(sv.model_precache[i], s)) {
            return;
        }
    }
}


Right?

Also, instead of calling things like
Code: Select all
PR_ExecuteProgram(pr_global_struct->ClientConnect)
and
Code: Select all
PR_ExecuteProgram(pr_global_struct->PutClientInServer)
i would just call MyClientConnect() and etc?
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby Baker » Fri Mar 11, 2016 8:12 pm

That would be one way to do it.

As far as I know, QuakeC never has any functions that take a variable number of arguments nor different data types for an argument ... so you could hard code the parameters as fixed with a strong type (i.e. float or char *)

i would just call MyClientConnect() and etc?


Sounds that like that work since you are no longer loading globals from the progs.dat
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Game code in C

Postby JasonX » Fri Mar 11, 2016 9:12 pm

Another question: inside SV_TouchLinks, the following is called: PR_ExecuteProgram(touch->v.touch). What is this for? There are some other calls to PR_ExecuteProgram that don't seem to be functions...
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby Baker » Fri Mar 11, 2016 10:44 pm

Load map dm6

Type "edicts" in the console

Look at edict #8

You can just type "edict 8" in the console to see just edict #8. One of the fields you will see is "touch" ... and that specific entity has something in that field.

(I mean I could answer the question directly, but it is better if you use the edict command and directly view what is going on. Doing the above will give you about everything you need to know on handling that. You'll need to use that "edict" command a lot with what you are doing.)
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Game code in C

Postby JasonX » Sat Mar 12, 2016 7:41 pm

Thanks for the info. I'm still trying to get the game running, bumping into a few segfaults due to calls like this:

Code: Select all
SV_ModelIndex(pr_strings + ent->v.model))


Or anything that has pr_strings. I tried to use ent.v.modelindex directly, without luck, and also SV_ModelIndex(ent->v.model). But no luck as well. The whole pr_string mess is difficult to understand/remove. So far, i just want to load a level. The first part of ScratchQC.
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby Spike » Sat Mar 12, 2016 8:52 pm

pr_strings is just an offset into the qc string table. if you're serious about running C code, just treat it as ((char*)NULL) and remove it when practical.
you just need to look out for dereferences, which are safe in qc as they're effectively just empty strings.
Spike
 
Posts: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Game code in C

Postby r00k » Mon Mar 14, 2016 8:06 am

Something else you can do, for learning purpose, is to look at the KTX gamecode source in C. It's for QuakeWorld but then, that shouldn't matter.

https://github.com/deurk/ktx
r00k
 
Posts: 1108
Joined: Sat Nov 13, 2004 10:39 pm

Re: Game code in C

Postby JasonX » Mon Mar 14, 2016 5:50 pm

Thanks a lot for the info, guys. However, by removing the indexed calls and leaving just the char*, i still get protocol errors: Host_Error: CL_ParseServerMessage: Server is protocol 66820 instead of 15
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby Baker » Mon Mar 14, 2016 7:11 pm

JasonX wrote:Thanks a lot for the info, guys. However, by removing the indexed calls and leaving just the char*, i still get protocol errors: Host_Error: CL_ParseServerMessage: Server is protocol 66820 instead of 15


Revert your last change and examine what you did? You do have some sort of version control going on right (git, svn, etc)? Where if you make a mistake or something doesn't work you can undo.

(Or: You might consider switching to a Quake2 engine which already uses DLLs for game logic.)
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Game code in C

Postby frag.machine » Mon Mar 14, 2016 8:39 pm

I'd suggest you to have a small function or even a macro that receives the value corresponding to the string offset and returns a proper char * and use it every time a string is referred in the code. This should fix most (if not all) problems due invalid string references. Actually, forget what I said: IIRC such macros already exist in pr_builtins.c. Just use it (you may need to move it to quakedef.h tho)

Also, if you are really set with the idea of pure C for game logic maybe the Quake 2 engine would be a good reference.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2069
Joined: Sat Nov 25, 2006 1:49 pm

Re: Game code in C

Postby Spike » Mon Mar 14, 2016 11:26 pm

set cl_shownet 2
see where your server differs from the version you started with.
Spike
 
Posts: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Game code in C

Postby JasonX » Wed Mar 16, 2016 4:15 pm

I'm a little bit lost on how the pr_strings thing works. By default, when a server is started, anything read from *.bsp is parsed into the PR_* structures and then sent along as integers over the network? Should i just use chars instead?
JasonX
 
Posts: 407
Joined: Tue Apr 21, 2009 2:08 pm

Re: Game code in C

Postby frag.machine » Wed Mar 16, 2016 7:31 pm

pr_strings is a pool of immutable strings (ex: "You got the ", " left the game with ", "progs/player.mdl", etc), previously declared in QuakeC code and stored at the begin of the progs.dat file, concatenated with a '\0' char as separator between individual strings and "\0\0" as final marker. When the engine loads the progs.dat it reads this chunk of text into pr_strings. Every string reference in QuakeC is actually an integer offset to this pool, and every time you need the actual string (ex: when the QuakeC interpreter executes a bprint() call) the macros at pr_builtins.c I mentioned before returns a char pointer to this pool.

Note that this applies only to immutable strings. Strings built during runtime (ex: ftos()) are stored in pr_str_tmp (or something named like that, can't remember right now).

Regarding the error you are facing: most likely you are not sending correct string values. Specially in the case of the precache lists, which are read exactly from pr_strings. Maybe my explanation above will make things a bit easier to debug now.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2069
Joined: Sat Nov 25, 2006 1:49 pm

Next

Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest