Skip to content

Avoid allocating arguments for absent collision callbacks - #286

Open
fderop wants to merge 3 commits into
cortex-command-community:developmentfrom
fderop:perf/reuse-contact-storage
Open

fderop wants to merge 3 commits into
cortex-command-community:developmentfrom
fderop:perf/reuse-contact-storage

Conversation

@fderop

@fderop fderop commented Oct 2, 2026 •

Copy link
Copy Markdown

Collision notifications constructed Lua argument vectors before the dispatcher discovered that no callback existed.
Both collision paths now check the callback table first and reuse a static callback name. The terrain path uses:

static const std::string functionName = "OnCollideWithTerrain";
auto function = m_FunctionsAndScripts.find(functionName);
if (function != m_FunctionsAndScripts.end() && !function->second.empty()) {
	RunScriptedFunctionInAppropriateScripts(functionName, false, false, {}, {std::to_string(m_TerrainMatHit)});
}

Collision-state assignments remain unconditional. Objects with callbacks still use the original dispatcher for initialization, enabled-script filtering, locking, and invocation order.
The guard matches its existing early-return condition.

Across three process pairs, dense collision routines take 7.0–14.2% less time and terrain collisions take 32.0% less time.
Physics outputs and Lua callback checks match, including disabled and re-enabled scripts.
Gameplay mean simulation time improves from 2.610 to 2.565 ms, but p95 worsens from 8.746 to 9.078 ms.
This does not establish a general FPS or latency gain.

Only MovableObject.cpp changes in production. Results and reproduction instructions.
The included PMR pool experiment showed no reliable gain and remains test-only.

@fderop
fderop marked this pull request as ready for review October 2, 2026 18:28
@Causeless

Copy link
Copy Markdown
Contributor

I must misunderstand something. The very first thing that RunScriptedFunctionInAppropriateScripts() does is this block of code, which is effectively the exact same thing as the check added by the LLM here at each caller:

auto itr = m_FunctionsAndScripts.find(functionName);
if (itr == m_FunctionsAndScripts.end() || itr->second.empty()) {
	return -1;
}

How can doing this twice possibly improve performance?

@Causeless

Copy link
Copy Markdown
Contributor

Is it just that we're not constructing the temporary vectors passed into the function?

@fderop

fderop commented Oct 3, 2026

Copy link
Copy Markdown
Author

Is it just that we're not constructing the temporary vectors passed into the function?

Yes, the vectors are built before the function gets a chance to return early. Checking at the caller avoids those allocations when there’s no callback

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.

2 participants