1
0
Fork 0
forked from fte/fteqw

Add the fork+sleep builtins to the menuqc and csqc VMs too.

This commit is contained in:
Shpoike 2024-12-12 13:06:21 +00:00
parent 39e921624f
commit 0650610667
9 changed files with 160 additions and 143 deletions

View file

@ -6834,9 +6834,9 @@ static struct {
{"registertempent", PF_NoCSQC, 208},//{"RegisterTempEnt", PF_RegisterTEnt, 0, 0, 0, 208},
{"customtempent", PF_NoCSQC, 209},//{"CustomTempEnt", PF_CustomTEnt, 0, 0, 0, 209},
//210
{"fork", PF_Fixme, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
{"fork", PF_Fork, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
{"abort", PF_Abort, 211}, //#211 void() abort (FTE_MULTITHREADED)
{"sleep", PF_Fixme, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
{"sleep", PF_Sleep, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
{"forceinfokey", PF_NoCSQC, 213},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"forceinfokeyblob", PF_NoCSQC, 0},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"chat", PF_NoCSQC, 214},//{"chat", PF_chat, 0, 0, 0, 214},// #214 void(string filename, float starttag, entity edict) SV_Chat (FTE_NPCCHAT)
@ -8792,6 +8792,7 @@ qboolean CSQC_DrawView(void)
if (csqc_isdarkplaces && *csqc_world.g.physics_mode == 1)
{
csqc_world.physicstime = cl.servertime;
PR_RunThreads(&csqc_world);
}
else
{
@ -8822,6 +8823,7 @@ qboolean CSQC_DrawView(void)
}
#endif
PR_RunThreads(&csqc_world);
World_Physics_Frame(&csqc_world);
csqc_world.physicstime += host_frametime;
}

View file

@ -2551,7 +2551,9 @@ static struct {
//gap
{"getmodelindex", PF_m_getmodelindex, 200},
//gap
{"fork", PF_Fork, 210},
{"abort", PF_Abort, 211},
{"sleep", PF_Sleep, 212},
//gap
{"strstrofs", PF_strstrofs, 221},
{"str2chr", PF_str2chr, 222},
@ -3555,6 +3557,8 @@ void MP_Draw(void)
*menu_world.g.frametime = host_frametime;
inmenuprogs++;
PR_RunThreads(&menu_world);
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
if (scr_drawloading||scr_disabled_for_loading)

View file

@ -2113,15 +2113,15 @@ void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
int srcoffset = (prinst->callargc>3)?G_INT(OFS_PARM3):0;
int dstoffset = (prinst->callargc>4)?G_INT(OFS_PARM4):0;
if (size < 0)
PR_BIError(prinst, "PF_memcpy: invalid size\n");
PR_BIError(prinst, "PF_memcpy: invalid size %#x\n", size);
else if (size)
{
void *dst = PR_PointerToNative_Resize(prinst, qcdst, dstoffset, size);
void *src = PR_PointerToNative_MoInvalidate(prinst, qcsrc, srcoffset, size);
if (!dst)
PR_BIError(prinst, "PF_memcpy: invalid dest\n");
PR_BIError(prinst, "PF_memcpy: invalid dest (%#x - %#x)\n", qcdst, qcdst+size);
else if (!src)
PR_BIError(prinst, "PF_memcpy: invalid source\n");
PR_BIError(prinst, "PF_memcpy: invalid source (%#x - %#x)\n", qcsrc, qcsrc+size);
else
memmove(dst, src, size);
}
@ -5056,7 +5056,6 @@ void QCBUILTIN PF_strftime (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{
const char *in = PF_VarString(prinst, 1, pr_globals);
char result[8192];
char uresult[8192];
time_t ctime;
struct tm *tm;
@ -5075,9 +5074,8 @@ void QCBUILTIN PF_strftime (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
in = "%Y-%m-%d";
strftime(result, sizeof(result), in, tm);
unicode_strtoupper(result, uresult, sizeof(uresult), VMUTF8MARKUP);
RETURN_TSTRING(uresult);
RETURN_TSTRING(result);
}
//String functions
@ -6870,10 +6868,133 @@ void QCBUILTIN PF_rotatevectorsbymatrix (pubprogfuncs_t *prinst, struct globalva
////////////////////////////////////////////////////
//Progs internals
qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait)
{
world_t *world = prinst->parms->user;
qcstate_t *state;
edict_t *ed;
state = prinst->parms->memalloc(sizeof(qcstate_t));
state->next = world->qcthreads;
world->qcthreads = state;
state->resumetime = resumetime;
if (prinst->edicttable_length)
{
ed = PROG_TO_EDICT(prinst, world->g.self?*world->g.self:0);
state->self = NUM_FOR_EDICT(prinst, ed);
state->selfid = (prinst==svprogfuncs&&ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
ed = PROG_TO_EDICT(prinst, world->g.self?*world->g.self:0);
state->other = NUM_FOR_EDICT(prinst, ed);
state->otherid = (prinst==svprogfuncs&&ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
}
else //allows us to call this during init().
state->self = state->other = state->selfid = state->otherid = 0;
state->thread = prinst->Fork(prinst);
state->waiting = wait;
state->returnval = retval;
return state;
}
void PR_RunThreads(world_t *world)
{
struct globalvars_s *pr_globals;
edict_t *ed;
qcstate_t *state = world->qcthreads, *next;
world->qcthreads = NULL;
while(state)
{
pubprogfuncs_t *prinst = world->progs;
next = state->next;
if (state->resumetime > (world->g.time?*world->g.time:0) || state->waiting)
{ //not time yet, reform original list.
state->next = world->qcthreads;
world->qcthreads = state;
}
else
{ //call it and forget it ever happened. The Sleep biltin will recreate if needed.
pr_globals = PR_globals(prinst, PR_CURRENT);
if (world->g.self)
{
//restore the thread's self variable, if applicable.
ed = PROG_TO_EDICT(prinst, state->self);
if ((prinst==svprogfuncs?ed->xv->uniquespawnid:0) != state->selfid)
ed = prinst->edicttable[0];
*world->g.self = EDICT_TO_PROG(prinst, ed);
}
if (world->g.other)
{
//restore the thread's other variable, if applicable
ed = PROG_TO_EDICT(prinst, state->other);
if ((prinst==svprogfuncs?ed->xv->uniquespawnid:0) != state->otherid)
ed = prinst->edicttable[0];
*world->g.other = EDICT_TO_PROG(prinst, ed);
}
G_FLOAT(OFS_RETURN) = state->returnval; //return value of fork or sleep
prinst->RunThread(prinst, state->thread);
prinst->parms->memfree(state->thread);
prinst->parms->memfree(state);
}
state = next;
}
}
void PR_ClearThreads(pubprogfuncs_t *prinst)
{
world_t *world;
qcstate_t *state, *next;
if (!prinst)
return; //shoo!
world = prinst->parms->user;
state = world->qcthreads;
world->qcthreads = NULL;
while(state)
{
next = state->next;
//free the memory.
prinst->parms->memfree(state->thread);
prinst->parms->memfree(state);
state = next;
}
}
void QCBUILTIN PF_Abort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
prinst->AbortStack(prinst);
}
void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *world = prinst->parms->user;
float sleeptime;
sleeptime = G_FLOAT(OFS_PARM0);
PR_CreateThread(prinst, 1, (world->g.time?*world->g.time:0) + sleeptime, false);
prinst->AbortStack(prinst);
}
void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *world = prinst->parms->user;
float sleeptime;
if (svprogfuncs->callargc >= 1)
sleeptime = G_FLOAT(OFS_PARM0);
else
sleeptime = 0;
PR_CreateThread(prinst, 1, (world->g.time?*world->g.time:0) + sleeptime, false);
// PRSV_RunThreads();
G_FLOAT(OFS_RETURN) = 0;
}
//this func calls a function in another progs
//it works in the same way as the above func, except that it calls by reference to a function, as opposed to by it's name
@ -7739,6 +7860,7 @@ void QCBUILTIN PF_pushmove (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored)
{
PR_ClearThreads(progs);
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_reset(progs->parms->user);
#endif

View file

@ -391,7 +391,12 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_bitshift(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
struct qcstate_s *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait);
void PR_ClearThreads(pubprogfuncs_t *prinst);
void PR_RunThreads(world_t *world);
void QCBUILTIN PF_Abort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_externrefcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -1273,6 +1278,19 @@ typedef struct csqcedict_s
int skinobject;
} csqcedict_t;
typedef struct qcstate_s
{
float resumetime;
qboolean waiting;
struct qcthread_s *thread;
int self;
int selfid;
int other;
int otherid;
float returnval;
struct qcstate_s *next;
} qcstate_t;
#ifdef __cplusplus
};

View file

@ -263,6 +263,7 @@ struct world_s
pvec_t *drawfont;
pvec_t *drawfontscale;
} g;
struct qcstate_s *qcthreads;
#ifdef USERBE
qboolean rbe_hasphysicsents;

View file

@ -2069,8 +2069,8 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
// thread->lstackused -= f->locals; //the current function is the odd one out.
//add on the locals stack
memcpy(prinst.localstack+prinst.localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
prinst.localstack_used += thread->lstackused;
// memcpy(prinst.localstack+prinst.localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
// prinst.localstack_used += thread->lstackused;
//bung the locals of the current function on the stack.
// for (i=0 ; i < f->locals ; i++)

View file

@ -116,7 +116,6 @@ int pr_teamfield;
static unsigned int h2infoplaque[2]; /*hexen2 stat*/
#endif
static void PRSV_ClearThreads(void);
void PR_fclose_progs(pubprogfuncs_t*);
void PF_InitTempStrings(pubprogfuncs_t *prinst);
static int PDECL PR_SSQC_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname);
@ -124,21 +123,6 @@ static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void PR_DumpPlatform_f(void);
typedef struct qcstate_s
{
float resumetime;
qboolean waiting;
struct qcthread_s *thread;
int self;
int selfid;
int other;
int otherid;
float returnval;
struct qcstate_s *next;
} qcstate_t;
static qcstate_t *qcthreads;
typedef struct {
//for func finding and swapping.
char *name;
@ -246,33 +230,6 @@ static struct
void PR_RegisterFields(void);
void PR_ResetBuiltins(progstype_t type);
static qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait)
{
qcstate_t *state;
edict_t *ed;
state = prinst->parms->memalloc(sizeof(qcstate_t));
state->next = qcthreads;
qcthreads = state;
state->resumetime = resumetime;
if (prinst->edicttable_length)
{
ed = PROG_TO_EDICT(prinst, pr_global_struct->self);
state->self = NUM_FOR_EDICT(prinst, ed);
state->selfid = (ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
ed = PROG_TO_EDICT(prinst, pr_global_struct->other);
state->other = NUM_FOR_EDICT(prinst, ed);
state->otherid = (ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
}
else //allows us to call this during init().
state->self = state->other = state->selfid = state->otherid = 0;
state->thread = prinst->Fork(prinst);
state->waiting = wait;
state->returnval = retval;
return state;
}
void PDECL ED_Spawned (struct edict_s *ent, int loading)
{
#ifdef VM_Q1
@ -803,7 +760,7 @@ void Q_SetProgsParms(qboolean forcompiler)
sv.world.Event_ContentsTransition = SVPR_Event_ContentsTransition;
sv.world.Get_CModel = SVPR_GetCModel;
sv.world.Get_FrameState = SVPR_Get_FrameState;
PRSV_ClearThreads();
PR_ClearThreads(svprogfuncs);
PR_fclose_progs(svprogfuncs);
// svs.numprogs = 0;
@ -814,7 +771,7 @@ void PR_Deinit(void)
{
int i;
PRSV_ClearThreads();
PR_ClearThreads(svprogfuncs);
#ifdef VM_Q1
Q1QVM_Shutdown(true);
#endif
@ -9238,91 +9195,6 @@ void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct globalvars_s
#endif
}
void PRSV_RunThreads(void)
{
struct globalvars_s *pr_globals;
edict_t *ed;
qcstate_t *state = qcthreads, *next;
qcthreads = NULL;
while(state)
{
next = state->next;
if (state->resumetime > sv.time || state->waiting)
{ //not time yet, reform original list.
state->next = qcthreads;
qcthreads = state;
}
else
{ //call it and forget it ever happened. The Sleep biltin will recreate if needed.
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
//restore the thread's self variable, if applicable.
ed = PROG_TO_EDICT(svprogfuncs, state->self);
if (ed->xv->uniquespawnid != state->selfid)
ed = svprogfuncs->edicttable[0];
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ed);
//restore the thread's other variable, if applicable
ed = PROG_TO_EDICT(svprogfuncs, state->other);
if (ed->xv->uniquespawnid != state->otherid)
ed = svprogfuncs->edicttable[0];
pr_global_struct->other = EDICT_TO_PROG(svprogfuncs, ed);
G_FLOAT(OFS_RETURN) = state->returnval; //return value of fork or sleep
svprogfuncs->RunThread(svprogfuncs, state->thread);
svprogfuncs->parms->memfree(state->thread);
svprogfuncs->parms->memfree(state);
}
state = next;
}
}
static void PRSV_ClearThreads(void)
{
qcstate_t *state = qcthreads, *next;
qcthreads = NULL;
while(state)
{
next = state->next;
svprogfuncs->parms->memfree(state->thread);
svprogfuncs->parms->memfree(state);
state = next;
}
}
static void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float sleeptime;
sleeptime = G_FLOAT(OFS_PARM0);
PR_CreateThread(prinst, 1, sv.time + sleeptime, false);
prinst->AbortStack(prinst);
}
static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float sleeptime;
if (svprogfuncs->callargc >= 1)
sleeptime = G_FLOAT(OFS_PARM0);
else
sleeptime = 0;
PR_CreateThread(prinst, 1, sv.time + sleeptime, false);
// PRSV_RunThreads();
G_FLOAT(OFS_RETURN) = 0;
}
//DP_TE_STANDARDEFFECTBUILTINS
//void(vector org) te_gunshot = #418;
static void QCBUILTIN PF_te_gunshot(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)

View file

@ -48,8 +48,6 @@ qboolean PR_ParseClusterEvent(const char *dest, const char *source, const char *
qboolean PR_UserCmd(const char *cmd);
qboolean PR_ConsoleCmd(const char *cmd);
void PRSV_RunThreads(void);
#define PR_MAINPROGS 0 //this is a constant that should really be phased out. But seeing as QCLIB requires some sort of master progs due to extern funcs...
//maybe go through looking for extern funcs, and remember which were not allocated. It would then be a first come gets priority. Not too bad I supppose.

View file

@ -2726,7 +2726,7 @@ qboolean SV_Physics (void)
SV_ProgStartFrame ();
PRSV_RunThreads();
PR_RunThreads(&sv.world);
#ifdef USERBE
if (sv.world.rbe)