Skip to content

Conversation

@ELDment
Copy link
Contributor

@ELDment ELDment commented Sep 22, 2025

Prior to implementing TerminateSelf, plugins could only prevent initialization by throwing exceptions within their Load() override method. Once fully loaded, however, plugins lacked any elegant mechanism for self-termination

So, we implemented a state-aware TerminateSelf method:

  • PluginState.Loading: Abort initialization by throwing an exception (handled by outer try-catch)
  • PluginState.Loaded: Trigger the standard unload sequence for safe termination while preserving reload capability through css_plugins commands
image image

btw. Rather than injecting the complete PluginContext into BasePlugin (which would enable dangerous control inversion allowing plugins to manipulate framework internals or other plugin instances), we employed interface segregation by introducing ISelfPluginControl. This restricted interface exposes only self-termination capabilities to plugins, 100% adhering to the principle of least privilege and preventing unauthorized access to framework components or cross-plugin manipulation 🤗

@ELDment ELDment requested a review from roflmuffin as a code owner September 22, 2025 13:30
@ELDment
Copy link
Contributor Author

ELDment commented Sep 22, 2025

Nothing 😪

@ELDment
Copy link
Contributor Author

ELDment commented Sep 22, 2025

image

To be honest, I originally tried to recreate SourceMod's SetFailState functionality. However, since CSS has better practices for plugin management, I switched focus to implementing safe unloading instead (rather than putting plugins into a failed state)

Meh, I'm not entirely sure this follows best practices though, so I'd appreciate any thoughts or feedback you might have

@ELDment ELDment marked this pull request as draft September 22, 2025 14:33
@ELDment
Copy link
Contributor Author

ELDment commented Sep 22, 2025

[Need Help] Implementing Silent Execution Termination

I want TerminateSelf to behave like throwing an exception (clears call stack and terminates execution immediately) but without:

  • Printing stack traces to console
  • Requiring try-catch blocks everywhere

Current Situation:

We're using TerminateWithReason() in our plugins, but it doesn't provide the "immediate termination" behavior we need. The call stack unwinds back to OnTestTerminateCommand, and execution continues normally until the method exits 😅
image

Desired Behavior:

[ConsoleCommand("Terminate")]
public void OnTestTerminateCommand(CCSPlayerController? player, CommandInfo command)
{
    Console.WriteLine("BEFORE");
    TerminateSelf("TEST");      // Should terminate silently here
    Console.WriteLine("AFTER"); // This should never execute
}

To prevent control flow from unwinding back to the original caller, we experimented with throwing an exception after Unload(false);
image
While this successfully terminates execution due to the absence of exception handlers in the call stack, it results in unhandled exception stack traces being logged to the console, making this approach inelegant and unsuitable for production use

@ELDment
Copy link
Contributor Author

ELDment commented Sep 22, 2025

Nothing 😪

@ELDment
Copy link
Contributor Author

ELDment commented Sep 23, 2025

Well, we successfully solved the Silent Execution Termination problem in commit ba6a8b7

image

@ELDment
Copy link
Contributor Author

ELDment commented Sep 23, 2025

When TerminateSelf is called within the Load override, we only log the termination reason without stack traces

image image

However, when plugins throw unexpected errors during loading (Since this is not intentional on our part), we provide full stack trace details since these are unintentional failures
image
image

@ELDment
Copy link
Contributor Author

ELDment commented Sep 23, 2025

Now TerminateSelf still works flawlessly under concurrent programming conditions 🥳
image
image

@ELDment ELDment marked this pull request as ready for review September 23, 2025 04:04
@ELDment
Copy link
Contributor Author

ELDment commented Sep 23, 2025

@roflmuffin
I think we're good to go now, let's do a code review 🤠

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