From 693374c5c10e46d5064d32844e899aa84596a124 Mon Sep 17 00:00:00 2001 From: Alug Date: Wed, 17 Sep 2025 18:08:06 +0200 Subject: [PATCH] ensure deterministic order for P_Random stuff passed as arguments the evaluation order of arguments passed to functions is undefined in C/C++, so its up to the compiler in which order to evaluate these P_Random functions modify the randomseed each time theyre called, which can lead to different outcomes (thus desynchs) on different platforms, compilers, compiler versions etc. so match up with the most common which is last to first (seemingly the order gcc on nix and windows handle it) common case are mine/eggbomb explosions hitting the smk ice blocks causing desynchs when either server or client were clang compiled --- src/k_kart.c | 97 +++++++++++++++++++++++++++++++++------------------ src/p_enemy.c | 86 ++++++++++++++++++++++++++++++++++----------- src/p_mobj.c | 66 ++++++++++++++++++++++++++--------- 3 files changed, 179 insertions(+), 70 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index bce64a793..8b590887d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1236,10 +1236,15 @@ static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the m void K_SpawnNormalSpeedLines(player_t *player) { - mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), - MT_FASTLINE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale); + rand_y = player->mo->y + (P_RandomRange(-36,36) * player->mo->scale); + rand_x = player->mo->x + (P_RandomRange(-36,36) * player->mo->scale); + + mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE); P_SetTarget(&fast->target, player->mo); fast->angle = K_MomentumAngle(player->mo); @@ -1284,10 +1289,15 @@ void K_SpawnNormalSpeedLines(player_t *player) void K_SpawnDraftSpeedLines(player_t *player, fixed_t scale, skincolornum_t color, boolean translucent) { - mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), - MT_FASTLINE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale); + rand_y = player->mo->y + (P_RandomRange(-36,36) * player->mo->scale); + rand_x = player->mo->x + (P_RandomRange(-36,36) * player->mo->scale); + + mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE); P_SetTarget(&fast->target, player->mo); fast->angle = K_MomentumAngle(player->mo); @@ -1308,11 +1318,15 @@ void K_SpawnDraftSpeedLines(player_t *player, fixed_t scale, skincolornum_t colo void K_SpawnInvincibilitySpeedLines(mobj_t *mo) { - mobj_t *fast = P_SpawnMobjFromMobj(mo, - P_RandomRange(-48, 48) * FRACUNIT, - P_RandomRange(-48, 48) * FRACUNIT, - P_RandomRange(0, 64) * FRACUNIT, - MT_FASTLINE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = P_RandomRange(0, 64) * FRACUNIT; + rand_y = P_RandomRange(-48, 48) * FRACUNIT; + rand_x = P_RandomRange(-48, 48) * FRACUNIT; + + mobj_t *fast = P_SpawnMobjFromMobj(mo, rand_x, rand_y, rand_z, MT_FASTLINE); P_SetMobjState(fast, S_KARTINVLINES1); P_SetTarget(&fast->target, mo); @@ -2344,7 +2358,7 @@ static fixed_t K_GetInvincibilitySpeed(UINT16 time) { if (K_GetKartInvinType() == KARTINVIN_LEGACY) return INVINSPEEDBOOSTLGC; - + fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); return Easing_OutCubic(t, 0, INVINSPEEDBOOSTALT); } @@ -2353,7 +2367,7 @@ static fixed_t K_GetInvincibilityAccel(UINT16 time) { if (K_GetKartInvinType() == KARTINVIN_LEGACY) return INVINACCELBOOSTLGC; - + fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); return Easing_OutCubic(t, 0, INVINACCELBOOSTALT); } @@ -3539,6 +3553,9 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) mobj_t *dust; mobj_t *truc; INT32 speed, speed2; + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; K_MatchGenericExtraFlags(smoldering, source); smoldering->tics = TICRATE*3; @@ -3558,9 +3575,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust->scalespeed = source->scale/12; P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale)); - truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, - source->y + P_RandomRange(-radius, radius)*FRACUNIT, - source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE); + rand_z = source->z + P_RandomRange(0, height)*FRACUNIT; + rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT; + rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT; + + truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMEXPLODE); K_MatchGenericExtraFlags(truc, source); P_SetScale(truc, source->scale); truc->destscale = source->scale*6; @@ -3577,9 +3596,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) for (i = 0; i < 16; i++) { - dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, - source->y + P_RandomRange(-radius, radius)*FRACUNIT, - source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE); + rand_z = source->z + P_RandomRange(0, height)*FRACUNIT; + rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT; + rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT; + + dust = P_SpawnMobj(rand_x, rand_y, rand_z, MT_SMOKE); P_SetMobjState(dust, S_OPAQUESMOKE1); P_SetScale(dust, source->scale); dust->destscale = source->scale*10; @@ -3587,9 +3608,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust->tics = 30; dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT; - truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, - source->y + P_RandomRange(-radius, radius)*FRACUNIT, - source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE); + rand_z = source->z + P_RandomRange(0, height)*FRACUNIT; + rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT; + rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT; + + truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMPARTICLE); K_MatchGenericExtraFlags(truc, source); P_SetScale(truc, source->scale); truc->destscale = source->scale*5; @@ -4061,9 +4084,13 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) else aoff += ANGLE_45; - dust = P_SpawnMobj(mo->x + FixedMul(24*mo->scale, FINECOSINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS), - mo->y + FixedMul(24*mo->scale, FINESINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS), - mo->z, MT_WIPEOUTTRAIL); + fixed_t rand_x; + fixed_t rand_y; + + rand_y = mo->y + FixedMul(24*mo->scale, FINESINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS); + rand_x = mo->x + FixedMul(24*mo->scale, FINECOSINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS); + + dust = P_SpawnMobj(rand_x, rand_y, mo->z, MT_WIPEOUTTRAIL); P_SetTarget(&dust->target, mo); dust->angle = K_MomentumAngle(mo); @@ -4538,7 +4565,13 @@ static void K_FlameDashLeftoverSmoke(mobj_t *src) smoke->momy = 3*src->momy/4; smoke->momz = 3*P_GetMobjZMovement(src)/4; - P_Thrust(smoke, src->angle + FixedAngle(P_RandomRange(135, 225)<scale); + fixed_t rand_angle; + fixed_t rand_move; + + rand_move = P_RandomRange(0, 8) * src->scale; + rand_angle = src->angle + FixedAngle(P_RandomRange(135, 225)<momz += P_RandomRange(0, 4) * src->scale; } } @@ -5219,9 +5252,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 drop->destscale = (3*drop->destscale)/2; drop->angle = angle; - P_Thrust(drop, - FixedAngle(P_RandomFixed() * 180) + angle, - 16*mapobjectscale); + P_Thrust(drop, FixedAngle(P_RandomFixed() * 180) + angle, 16*mapobjectscale); drop->momz = flip * 3 * mapobjectscale; if (drop->eflags & MFE_UNDERWATER) @@ -9362,8 +9393,8 @@ static vector3_t *K_FindPlayerCluster(fixed_t eps, INT32 (*func)(player_t *, fix clusterplayer[i] = false; // Density check - if (N > bestdensity) - { + if (N > bestdensity) + { bestdensity = N; findme = closesttocluster; diff --git a/src/p_enemy.c b/src/p_enemy.c index 8242a3f2b..82566adf1 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3424,7 +3424,14 @@ void A_FishJump(mobj_t *actor) if (i < MAXPLAYERS) { fixed_t rad = actor->radius>>FRACBITS; - P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<target->player) return; - + // Set the sign to be an appropriate background color for this player's skincolor. actor->color = skincolors[actor->target->player->skincolor].invcolor; actor->frame += skincolors[actor->target->player->skincolor].invshade; @@ -7230,7 +7237,7 @@ void A_StateRangeByParameter(mobj_t *actor) if (locvar2 - locvar1 < 0) return; // invalid range - + if (udmf) { parameter = actor->args[0]; @@ -9673,7 +9680,7 @@ void A_FlickyCenter(mobj_t *actor) return; homeRadius = locvar2 ? FixedMul(abs(locvar2), actor->scale) : 384*actor->scale; - + if (!actor->tracer) { mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false, 0); @@ -10118,11 +10125,16 @@ void A_FlameParticle(mobj_t *actor) rad = actor->radius>>FRACBITS; hei = actor->height>>FRACBITS; - particle = P_SpawnMobjFromMobj(actor, - P_RandomRange(rad, -rad)<info->deathsound) //S_StartSound(remains, actor->info->deathsound); - + if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumper <= 0) && !itembreaker) { actor->target->player->itemroulette = KROULETTE_ACTIVE; @@ -10695,8 +10707,15 @@ void A_JawzExplode(mobj_t *actor) { INT32 speed, speed2; - truc = P_SpawnMobj(actor->x + P_RandomRange(-8, 8)*FRACUNIT, actor->y + P_RandomRange(-8, 8)*FRACUNIT, - actor->z + P_RandomRange(0, 8)*FRACUNIT, MT_BOOMPARTICLE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = actor->z + P_RandomRange(0, 8)*FRACUNIT; + rand_y = actor->y + P_RandomRange(-8, 8)*FRACUNIT; + rand_x = actor->x + P_RandomRange(-8, 8)*FRACUNIT; + + truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMPARTICLE); truc->scale = actor->scale*2; speed = FixedMul(7*FRACUNIT, actor->scale)>>FRACBITS; @@ -10885,10 +10904,15 @@ void A_SPBChase(mobj_t *actor) : (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target && xyspeed > K_GetKartSpeed(actor->tracer->player, false, false)/4) // Don't display speedup lines at pitifully low speeds { - mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale), - actor->y + (P_RandomRange(-24,24) * actor->scale), - actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale), - MT_FASTLINE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale); + rand_y = actor->y + (P_RandomRange(-24,24) * actor->scale); + rand_x = actor->x + (P_RandomRange(-24,24) * actor->scale); + + mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE); fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); //fast->momx = (3*actor->momx)/4; //fast->momy = (3*actor->momy)/4; @@ -11283,8 +11307,15 @@ void A_FZBoomSmoke(mobj_t *actor) for (i = 0; i < 8+(4*var1); i++) { - mobj_t *smoke = P_SpawnMobj(actor->x + (P_RandomRange(-rad, rad)*actor->scale), actor->y + (P_RandomRange(-rad, rad)*actor->scale), - actor->z + (P_RandomRange(0, 72)*actor->scale), MT_THOK); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = actor->z + (P_RandomRange(0, 72)*actor->scale); + rand_y = actor->y + (P_RandomRange(-rad, rad)*actor->scale); + rand_x = actor->x + (P_RandomRange(-rad, rad)*actor->scale); + + mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, rand_z, MT_THOK); P_SetMobjState(smoke, S_FZEROSMOKE1); smoke->tics += P_RandomRange(-3, 4); @@ -11445,13 +11476,20 @@ void A_MementosTPParticles(mobj_t *actor) mobj_t *mo2; int i = 0; thinker_t *th; + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; if (LUA_CallAction(A_MEMENTOSTPPARTICLES, (actor))) return; for (; i<4; i++) { - particle = P_SpawnMobj(actor->x + (P_RandomRange(-256, 256)<y + (P_RandomRange(-256, 256)<z + (P_RandomRange(48, 256)<z + (P_RandomRange(48, 256)<y + (P_RandomRange(-256, 256)<x + (P_RandomRange(-256, 256)<frame = 0; particle->color = ((i%2) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK)); particle->destscale = 1; @@ -11512,9 +11550,15 @@ void A_ReaperThinker(mobj_t *actor) if (actor->scale < 2<x + (P_RandomRange(-60, 60)<y + (P_RandomRange(-60, 60)<z, MT_THOK); + fixed_t rand_x; + fixed_t rand_y; + + rand_y = actor->y + (P_RandomRange(-60, 60)<x + (P_RandomRange(-60, 60)<z, MT_THOK); particle->momz = 20<color = ((i%2 !=0) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK)); particle->frame = 0; diff --git a/src/p_mobj.c b/src/p_mobj.c index 287f67cf7..82d276f84 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6847,7 +6847,7 @@ static void P_PlayerInvincibilityOverlay(mobj_t *thing) { I_Assert(thing->target != NULL); I_Assert(thing->target->player != NULL); - + if (!thing->target->player->invincibilitytimer) { P_SetTarget(&thing->target, NULL); @@ -7966,11 +7966,16 @@ static boolean P_MobjDeadThink(mobj_t *mobj) if (!(mobj->fuse % 8)) { fixed_t r = mobj->radius >> FRACBITS; - mobj_t *explosion = P_SpawnMobj( - mobj->x + (P_RandomRange(r, -r) << FRACBITS), - mobj->y + (P_RandomRange(r, -r) << FRACBITS), - mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), - MT_SONIC3KBOSSEXPLODE); + + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS); + rand_y = mobj->y + (P_RandomRange(r, -r) << FRACBITS); + rand_x = mobj->x + (P_RandomRange(r, -r) << FRACBITS); + + mobj_t *explosion = P_SpawnMobj(rand_x, rand_y, rand_z, MT_SONIC3KBOSSEXPLODE); S_StartSound(explosion, sfx_s3kb4); } P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); @@ -8930,7 +8935,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) smoke->momy = mobj->target->momy/2; smoke->momz = mobj->target->momz/2; - P_Thrust(smoke, mobj->angle+FixedAngle(P_RandomRange(135, 225)<target->scale); + fixed_t rand_angle; + fixed_t rand_move; + + rand_move = P_RandomRange(0, 8) * mobj->target->scale; + rand_angle = mobj->angle+FixedAngle(P_RandomRange(135, 225)<x + (P_RandomRange(-48,48)*mobj->scale), - mobj->y + (P_RandomRange(-48,48)*mobj->scale), - mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale), - MT_SIGNSPARKLE); + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale); + rand_y = mobj->y + (P_RandomRange(-48,48)*mobj->scale); + rand_x = mobj->x + (P_RandomRange(-48,48)*mobj->scale); + + P_SpawnMobj(rand_x, rand_y, rand_z, MT_SIGNSPARKLE); + mobj->flags &= ~MF_NOGRAVITY; + if (abs(mobj->z - mobj->movefactor) <= (512*mobj->scale) && !mobj->cvmem) { if (mobj->info->seesound) @@ -9466,7 +9484,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) else // fire + smoke pillar { UINT8 i; - mobj_t *fire = P_SpawnMobj(mobj->x + (P_RandomRange(-32, 32)*mobj->scale), mobj->y + (P_RandomRange(-32, 32)*mobj->scale), mobj->z, MT_THOK); + + fixed_t rand_x; + fixed_t rand_y; + + rand_y = mobj->y + (P_RandomRange(-32, 32)*mobj->scale); + rand_x = mobj->x + (P_RandomRange(-32, 32)*mobj->scale); + + mobj_t *fire = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_THOK); fire->sprite = SPR_FPRT; fire->frame = FF_FULLBRIGHT|FF_TRANS30; @@ -9478,7 +9503,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj) for (i = 0; i < 2; i++) { - mobj_t *smoke = P_SpawnMobj(mobj->x + (P_RandomRange(-16, 16)*mobj->scale), mobj->y + (P_RandomRange(-16, 16)*mobj->scale), mobj->z, MT_SMOKE); + rand_y = mobj->y + (P_RandomRange(-16, 16)*mobj->scale); + rand_x = mobj->x + (P_RandomRange(-16, 16)*mobj->scale); + + mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_SMOKE); P_SetMobjState(smoke, S_FZSLOWSMOKE1); smoke->scale = mobj->scale; @@ -9702,9 +9730,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if ((mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) && !(leveltime % 10)) { - mobj_t *dust = P_SpawnMobj(mobj->x + (P_RandomRange(-4, 4)<y + (P_RandomRange(-4, 4)<z + (P_RandomRange(0, 2)<z + (P_RandomRange(0, 2)<y + (P_RandomRange(-4, 4)<x + (P_RandomRange(-4, 4)<scale/2); P_InstaThrust(dust, FixedAngle(P_RandomRange(0,359)<tracer->momz)/2);