winstxnhdw / lc-hax

A powerful, feature-rich and highly performant internal cheat for the co-op indie horror video game, Lethal Company.
78 stars 25 forks source link

[Bug]: Get Rid of .UnFake() as well #270

Closed xAstroBoy closed 5 months ago

xAstroBoy commented 5 months ago

What happened?

is the same thing as doing foo == null, which makes it even more complex, just get rid of this as there's no point , just confuses the code around and it seems the unfake checks break as well a few part of the code , EX : nightVision no longer working.

winstxnhdw commented 5 months ago

The issue wasn't because of Unfake but because I accidentally removed the NOT operator in this line.

In a perfect world, I wouldn't have to use Unfake to use the full .NET features such as pattern matching. Unfortunately, Unity did something stupid like overloading the == operator to only return null if the object is 'destroyed' (but GC hasn't collected the reference to the object). See here.

The implications of this is that newer .NET features like is or is not (pattern matching) can potentially return unexpected results. Okay, so why not just avoid is and is not and do ==? See the following example.

This is with pattern matching.

if (Helper.CurrentCamera is not Camera camera) {
    yield return waitForEndOfFrame;
    continue;
}

sunIndirect.transform.position = camera.transform.position;

Without pattern matching.

if (Helper.CurrentCamera == null) {
    yield return waitForEndOfFrame;
    continue;
}

sunIndirect.transform.position = Helper.CurrentCamera.transform.position;

Nothing wrong with this? Sure. Let's look at our implementation of CurrentCamera.

public static Camera? CurrentCamera =>
    Helper.LocalPlayer?.gameplayCamera.Unfake() is Camera gameplayCamera && gameplayCamera.enabled
        ? gameplayCamera
        : Helper.StartOfRound?.spectateCamera.Unfake();

CurrentCamera appears to be a property that returns the correct camera object after performing multiple conditional checks.

Pattern matching allows us to cache Helper.CurrentCamera in a local variable camera without needing to recompute these (potentially costly) values again.

Okay, so why not cache the variable before using it?

Camera camera = Helper.CurrentCamera;

if (camera == null) {
    yield return waitForEndOfFrame;
    continue;
}

sunIndirect.transform.position = camera.transform.position;

Well, that's one extra line for every null check in our code base. For mods like ClearVision with many null checks, it greatly clutters the code. We also have about 200 of them and will have a lot more in the future.