Skip to content

Revert freeze grenade precache path (moved to separate addon) - #465

Closed
tectioon wants to merge 146 commits into
Source2ZE:mainfrom
tectioon:fix/freeze-grenade-separate-addon
Closed

tectioon wants to merge 146 commits into
Source2ZE:mainfrom
tectioon:fix/freeze-grenade-separate-addon

Conversation

@tectioon

Copy link
Copy Markdown

Summary

  • The freeze grenade model was moved out of frostg into its own standalone Workshop addon (frostbomb), where it stays at its original weapons/models/freeze_grenade/... path (that addon's gameinfo.gi VpkDirectories now includes weapons, so it packs correctly there).
  • Reverts the precache manifest resource string in zombiemod.cpp back to weapons/models/freeze_grenade/freeze_grenade.vmdl to match.

Test plan

  • Confirm frostbomb Workshop item is approved and actually contains the weapons/ folder in its published VPK
  • Server loads both frostg and frostbomb addons together (already configured via multiaddonmanager.cfg)
  • Buying Freeze Grenade in shop no longer crashes the server

🤖 Generated with Claude Code

JayCroghan and others added 30 commits November 5, 2025 15:17
Merging CS2Fixes dev with main
sv_subtick_movement_view_angles works yet again, though you should still disable it if disabling subtick movement
patocek and others added 27 commits September 8, 2026 18:25
Triggers the model's own "Break" input (spawns its 20 fracture
pieces) when a zombie thaws out, instead of silently removing the
entity. Actual removal is delayed slightly so the break has a chance
to spawn the debris first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EconomyShopPlugin's FreezeGrenade shows a cosmetic replacement model
that follows the real (hard-to-reskin) weapon_decoy/decoy_projectile
entity - this command hides the real one via a direct m_nRenderMode
field write (already an established pattern in this codebase, e.g.
mapmigrations.cpp/playermanager.cpp), not a native function call, so
carries much lower risk than the SetModel attempts that crashed the
server previously.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
metamod-source's master branch broke this project's build today
(2026-09-08) via "Provide an alternative to SourceHook" - it made
ISmmPlugin.h require khook.hpp, which nothing here provides, failing
every build with "fatal error C1083: Cannot open include file:
'khook.hpp'" (confirmed identically on Windows, SteamRT3, and
SteamRT4 CI runs, and in a local build). Pinned to the commit right
before that change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous pin (1c6191a3) was not actually the parent of the
breaking commit a12f3cd5 ("Provide an alternative to SourceHook") -
it still required khook.hpp and CI continued to fail identically.
Pinned to a12f3cd5's direct parent (7ec0f169) instead, which still
uses sourcehook.h. Verified locally: full Windows build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The decoy_projectile still shows overlapping with the ZMBIO freeze
grenade cosmetic model after deploying zm_hide_entity, despite the
render mode write using the same NetworkStateChanged-triggering
pattern already proven elsewhere (mapmigrations.cpp). Logging the
call, resolved classname, and render mode before/after to find out
whether the command is even being reached/finding the right entity,
rather than guessing further.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CS2Fixes already calls CBaseModelEntity::SetModel natively on live
player pawns without issue (zombiereborn.cpp's ApplyBaseClassVisuals,
leader.cpp), unlike calling it from C# which crashed the live server
twice. Exposes the same safe pattern as a command so EconomyShopPlugin
can reskin the thrown decoy_projectile into the ZMBIO freeze grenade
model without touching native entities directly from C#.

Also precaches the new model path referenced by the freeze grenade's
updated weapons.vdata (weapon_decoy's m_szWorldModel).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ZM_DecoyExploded/zm_detonate_freeze_grenade now share a
  ZM_TriggerFreezeExplosion helper and both play the ZMBIO
  explosion_freeze_core particle (whose compiled resource already
  references the distort/flakes/trails children) at the detonation
  point before removing the projectile.
- zm_detonate_freeze_grenade is a new command that immediately
  detonates a freeze grenade projectile in place, for
  EconomyShopPlugin to call on player touch instead of letting the
  grenade bounce off them until its native fuse timer runs out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…te-particles

Add freeze grenade explosion particle and manual detonate command
EconomyShopPlugin (CS#) needs to know when the first infection is
about to happen to play a 10-second countdown sound, but that timing
is only known internally in ZM_StartInitialCountdown. Publish it via
a read-only zm_infect_countdown_seconds cvar instead of duplicating
the random-timing logic in C#.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
zm_infect_countdown_seconds only got written by ZM_StartInitialCountdown
(triggered at freeze time end), so a stale value from a prior round or
a plugin reload could sit there through the freeze time window and get
misread by EconomyShopPlugin's countdown-sound polling as an
already-in-progress countdown, swallowing the real first announcement
once ZM_StartInitialCountdown actually began.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EconomyShopPlugin's new !zmenu class-select menu needs to set a
player's zombie class from a click, but the native c_zmclass command
has FCVAR_LINKED_CONCOMMAND and the engine refuses to run it via a
CS# player.ExecuteClientCommand-simulated client command ("[InputService]
Cannot execute concommand 'c_zmclass', missing required FCVAR flag").

Add a plain server-console command instead (same pattern as
zm_set_entity_model/zm_detonate_freeze_grenade), callable via
Server.ExecuteCommand, that does the same preference update
zmclass_callback does without going through the client-command path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Foundation for EconomyShopPlugin's zombie class abilities (e.g.
Spitter's acid spit) - lets C# deal a specific damage amount to a
player, attributed to another player, through the real
CTakeDamageInfo/TakeDamage path (kill feed, on-kill rewards) instead
of a plugin-side health edit. Same attacker-attribution pattern as the
existing zm_mine_kill command, just with a variable amount and
DMG_ACID instead of a lethal DMG_BURN.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
For EconomyShopPlugin's zombie class abilities (e.g. Spitter's acid
spit) that need a visible effect at a specific world position rather
than attached to a player. The existing !particle admin command
(commands.cpp) is chat-triggered - same FCVAR_LINKED_CONCOMMAND issue
that blocked c_zmclass from C# - and never cleans itself up, which is
fine for one-off admin debugging but not for something fired
repeatedly mid-round. This takes an explicit position and self-removes
after durationSeconds, same CHandle+CTimer cleanup pattern already
used for the freeze grenade's ice cube.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
For EconomyShopPlugin's Spitter zombie class ability - acid spit now
also stuns (briefly disables movement on) the human it hits. The
existing SetFrozen/ZM_FreezePlayer machinery does something similar
but is hardcoded to CS_TEAM_T for the freeze grenade; this is a
team-agnostic version (MOVETYPE_NONE for a duration, same
CHandle+CTimer restore pattern already used elsewhere in this file).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EconomyShopPlugin switched Spitter's acid spit to a travel-trail
effect using particles/kolka/part10_acid2.vpcf and
part10_acid2_burst.vpcf, but only the original spitter_acid.vpcf was
precached - an unprecached particle resource just doesn't render, no
error, which is why the new trail/burst was invisible.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The existing napalm system (IgnitePawn, gated by zm_napalm_enable)
only triggered for HE grenade hits (inflictor classname "hegrenade"),
even though molotov/incendiary ("inferno") already had its own
knockback handling right next to it. Extended the same condition to
cover both, so buying a molotov (upcoming EconomyShopPlugin human
shop item) sets zombies on fire the same lasting way an HE grenade
does - a real attached particle via SetParent, not a per-model skin
effect, so it works identically across all zombie class models
without extra setup.

Also precache the burn particle (customio.cpp's g_cvarBurnParticle) -
it wasn't precached anywhere, same silent-precache-miss category as
the earlier Spitter particle bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ZM_OnRoundStart iterated every slot via CCSPlayerController::FromSlot()
and only null-checked the result before dereferencing it further. During
a full match restart (all bots kicked and reconnecting at once, seen in
server logs right after this function's own "Classic spawn is enabled!"
print), a slot can briefly hold a stale/reused controller pointer that
isn't null but is no longer valid - crashing the server.

Add the same IsConnected() guard already used elsewhere in this file
(ZM_OnPlayerHurt, ZM_ClientCommand_JoinTeam) for exactly this situation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirrors zm_spawn_particle but for a visible model instead of a particle
effect, using the same CEntityKeyValues model-spawn approach already
proven for the freeze grenade's ice cube prop_dynamic. Lets
EconomyShopPlugin show an actual traveling rocket model for the Rocket
Launcher instead of relying on particles alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Needed by EconomyShopPlugin's Pulse Rifle orb, which has no real game
entity to call EmitSound on (it's a plugin-side simulated projectile) -
spawns a short-lived invisible info_target to anchor a positioned
EmitSound call, same CHandle+CTimer cleanup pattern as zm_spawn_particle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Relocated from weapons/models/freeze_grenade/ to models/weapons/freeze_grenade/
(matching weapons.vdata's updated m_szWorldModel and the addon's Rocket
Launcher/Pulse Rifle convention) - CS2's Workshop Tools publish scan only
picks up content under recognized top-level folders like models/, so the
old weapons/ root was silently excluded from the published VPK.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…player

EconomyShopPlugin's Rocket Launcher repurposes a real weapon_aug entity so
it behaves like a normal held/dropped/picked-up weapon, but needs its
native fire completely inert - only the skeleton/reload/holster animations
are wanted, actual rockets are simulated separately in the plugin.

Jamming schema fields like NextPrimaryAttackTick from C# every ~0.05s left
a race: the engine re-evaluates/resets that field on its own every game
tick (128/s), far more often than the plugin's timer corrects it, so a
real bullet could still slip through in the gap.

This strips the subtick attack markers in Detour_ProcessUsercmds - the
same technique cs2f_disable_subtick_shooting already uses server-wide,
just scoped to one marked player - which runs at the right point on every
single tick, before the engine ever processes the attack input.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Unlike ZEPlayer::GetPlayerSlot() elsewhere in this codebase, which
returns a CPlayerSlot wrapper needing .Get(), the base engine
CCSPlayerController::GetPlayerSlot() already returns a plain int.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EconomyShopPlugin's Rocket Launcher spawns a fresh cosmetic prop every
tick along the rocket's flight path via zm_spawn_prop. Without this, a
model with its own baked-in collision hull (like rpg_rocket.vmdl) would
be solid, and the rocket's own wall-trace sweep would immediately
collide with its own previous tick's prop a moment after firing -
detonating instantly instead of actually traveling, matching the exact
symptom reported (hit registers ~48 units out, right at the trace's own
start position, on every shot regardless of aim direction or location).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rate addon)

The freeze grenade model now lives in its own Workshop addon (frostbomb)
where weapons/ is packable, instead of being relocated inside frostg's
models/weapons/ tree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@tectioon

Copy link
Copy Markdown
Author

Opened against the wrong repo by mistake, closing. This is a fork-specific change, not meant for upstream.

@tectioon tectioon closed this Sep 11, 2026
@tectioon
tectioon deleted the fix/freeze-grenade-separate-addon branch September 11, 2026 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants