#Pathfinding Lag Fix | Pathfinding Lib | Smart Enemy Pathfinding
1 messages · Page 3 of 1
also no source code available for that mod so I guess I will have to decompile it to figure out why it is running that less than once every two AI intervals
What code is it running that's bad? I can take a look
Yeah Co author after original coder left
Never made github public because good question
Might be because of unity not gitignored or smthn like that
I mean the method that is either running infrequently or getting run for the first time repeatedly due to a ton of these guys spawning is the TargetClosestPlayer method
oh god
Actually it looks fine, iunno why we never made it public, but I'd have to check the files if we have any assembly csharp there
Lol that's kinda funny
It keeps running it until it finds a target player that's nearby
Then it switches state and never runs it again because it doesn't switch states back
Though it does run it every doaiinterval
In its first state
hmm, then I wonder if it was just because a lot of them were spawning
or because they were switching back to the state where they were searching for a target?
that wouldn't be abnormal even for vanilla enemies
I'm assuming these enemies like to spawn in groups?
Also what do you log to know that it's less than once every two AI intervals? Just mentioning because AI intervals can be different for every enemy
I just check if the time since the paths to players job was scheduled is greater than twice the interval time defined on that enemy, and if so, I check the paths on the main thread and print that I'm doing it there
I've always had this error, but the mod isnt even on my modpack
Ic, I think
Never used this fabled Lc optim
i think it is "FixCentipedeLag" you are looking for
^
bad mod
it will kill centipedes for you if they spawn at the beginning of the day or if everyone leaves the interior
don't use it
right

I would tend to say it'd be preferable to patch SetDestination and set_destination_Injected both directly to cancel them if the agent is off the navmesh, that is much less invasive
but it's probably fine, I don't think I have any need to look for that specific call to SetDestination
...unless I decide to add a fix for the stutter stepping that AI do when they can't find a complete path to their destination
which might be nice...
I forgot I was thinking about that yesterday
@green gust this is the check I was referring to before: https://github.com/Zaggy1024/LC_PathfindingLagFix/blob/master/PathfindingLagFix/Patches/PatchEnemyAI.cs#L319
I realized I was silly and forgor to push but now it is up on GitHub
okay and GitHub doesn't know how to find the method it calls to get the timestamp, so here that is: https://github.com/Zaggy1024/LC_PathfindingLagFix/blob/master/PathfindingLagFix/Utilities/AsyncPlayerPathfinding.cs#L82-L107
Ah icic
Well how do you even begin to do that? It's more so an issue with the enemy's logic if it's choosing to go somewhere unpathable
not really
well, or not exactly I guess I should say
if an enemy tries to path to somewhere unpathable, it can instead go to the closest point
however, calling SetDestination repeatedly as vanilla does causes the agent to instead reset its path and recalculate it asynchronously, so it stays stationary until that path is ready to be used
if it
- used async pathfinding to create a path, then placed that into the agent's path object when it was ready, or
- checked if the destination had changed
that would be either reduced or eliminated
(in cases where they are setting unreachable destinations)
also xu, why doesn't the HorseAI check the closest player more often? is it supposed to run away from the first player it sees on its navmesh?
The funny part is that this is just a bug no ones noticed/devs noticed but never bothered fixing cuz it didn't take away from the gameplay
It never reset states back to wandering
Probably after the target player is like 15+ distance away
oh wait I should have hooked TargetClosestPlayer, looks like it is calling it rn
lemme check if it does if I get closer
huh yeah okay it was other ones repeatedly calling it, I don't get any calls even when going inside with only one spawned that I went within range of
Yep
so I guess the logs were spamming just from a lot of them spawning most likely
in any other scenario it shouldn't print that log consistently
Yuh, there's meant to be prob like 5+ that spawn at once
yee
that's fair
I think it's a non-issue kinda, although I could move it to debug level in order to hide it from console in the stable release
it's only there rn to ensure that it's not marking these paths stale incorrectly
huh, why does the mantis shrimp call TargetClosestPlayer with both requireLineOfSight = false and = true?
seems a bit excessive, but I guess with PathfindingLagFix's patch it doesn't matter much anyway
definitely would have been a bit of a problem with lots of those spawning in a lobby with lots of people
oh and now it stopped calling it entirely

glad to see the worth of this patch proven though, the fps goes from 208 to 224 when I enable async player targeting
(tbf it's with 14 of these spawned, but any other enemies also calling TargetClosestPlayer should cause at least some reduction in performance similarly to this)
14 sounds a normal-ish number
Mantis shrimps spawn in groups so it's normal to see like 8 of em in a spot
gotcha, yeah
it was spawning 2 at a time just with the debug button, but I wasn't sure how many groups to expect
I never did code anything for mantis shrimps but they have weird logic regarding looking at a player that's looking at them, moving back, etc, but I cant say that it's that for sure
I would've expected it to use vector.dot for that though
yeah, a dot and a linecast would make sense
while i do know that the mod is currently not fit for player consumption rn, there's multiple repeating logs spamming the console that (i believe) is causing the game to lag
if that's intended because of debugging purposes then yeah just ignore this
just wanted to double check
it was indeed, and those will be gone in the next version
although they definitely shouldn't spam at any high frequency
honestly the fact that you seem to be seeing it from the same enemy multiple times makes me wish I had put more information into those logs
maybe I should bring them back for the next version and print out the instance ID lol
if it is printing that, that means you're losing out on the benefit of the async player targeting
it's normal for it to print at least once per enemy, but for enemies that check for targetable players every interval, it should never print again
@slender wadi I'm keeping the logs in with extra information in v2.0.10 Beta, while also avoiding printing it in scenarios where I know for sure it should be using the sync method, would be interested to hear if you see these logs printing still and how often
also, what exactly was the performance impact you were noticing that you associated with the logs?
I have no evidence to support my claim, but dogs have been acting really weirdly after the most recent updates of Pathfinding Lib/Fix
0194b682-2af4-8599-28f0-ec9a285a6c0c
What the fuck is this
There is straight up a baboon hawk walking in place
networkObjectID will be better since instance IDs aren't same across clients
opp srry i had to go to bed
but yeah i’ll be interested
it was spamming quite a lot and was def tanking framerate because of it
though it wasn’t like a consistent frame decrease, more like constant stuttering
these are the logs after the new update
and it only spams worse the more enemies it does it to
Here's both the log and dependency string in full
i gtg to school now so i won't be able to test anything for like a good couple of hours
I don't need to have it consistent across clients, I just need to distinguish individual enemies
not sure what would cause that, I don't patch that method
weirdly how?
okay that's really curious, it looks like the path time is straight up not updating, I wonder if I'm not always updating it when I should be
do you think you could grab Player.log from that session instead? I want to make sure that there aren't any exceptions occurring off the main thread
I still have around 2 hours of school, but i don’t think i’ve ever heard of a Player.log before
Where would i find that?
it should be in your save folder if you know where that is
%appdata%/../LocalLow/ZeekerssRBLX, if I remember correctly
Yesterday, before the update, it was me and my friend
Today, after the update, it was only me
okay that's strange then
it worked fine for me solo testing
will have another look though
more specifically it's in the Lethal Company folder under that directory
also 1a3 taught me a handy shortcut %appdata%\..\LocalLow\ -> %localappdata%Low
you'd have a Player.log file and a Player-prev.log file, from the most recent time you opened the game as well as a backup of the log from the previous time you booted the game
if you've relaunched twice or more since the session where you got the issue, you'd need to replicate it again, though
ahh, I think I found the issue, it happens after you become targetable and then untargetable
just had a little goof where I'm checking invalid indices of an array that I only grow
here you goo
and the player-prev log stan was talking abt just in case
thanks! doesn't look like it had any errors, so I think it's fair to assume the spam came from what I'm about to push out a fix for
just pushed Beta 2.0.11 with a fix for that
alr, tried it it with the new update
and the log spam is def decreased
now it's only in short bursts, which to be fair does cause stutters in-game
huh, that's at least more in line with what I would have expected, but your frame rate would have to be incredibly low for that to happen normally
was it stuttering?
i'm testing this on oldred
when i first landed, i got some lag spikes where my game froze for a bit, then returned to normal, which was when the logs were only in short bursts
then everything was perfect for a while, was able to go in, grab some stuff
saw goku and prayed he wouldn't get me
then while i was searching a room the game just turned into a powerpoint, which is when it started SPAMMING spamming the logs
okay well that is definitely curious
the logs would print when you get lag spikes, so it may very well be an issue with another mod
unless logs in general just absolutely murder your frames
I would be curious to see
a. this is reproducible on that map/seed
b. if it stops happening when PathfindingLagFix Beta is disabled
I could try to test it on that map and seed later if you toss me a profile code, or if you wanna repro yourself that would also work
i'll try to see if i can reproduce it, but if you want i can also send a code
0194b9f6-3f0b-afde-5823-c0ae9425cd44
the modpack's pretty hefty (112 mods), so i wouldn't be suprised if it's another mod causing it
also if you get like a gigantic wall of constant error logspam on the main menu after playing a round or two and exiting to it, just don't mind it
it's 100% not pathfindinglagfix (though idk what mod's causing it), it's hard to pinpoint it since the only info it gives is that it's an occludeaudio error, and it doesn't impact the performance somehow
i'm constantly tweaking with stuff on the pack so i'll figure it all out eventually
okay yeah it looks like the majority of these logs are just coming from the hydrogere
oh what makes you sure that PathfindingLagFix isn't having a bug here though?
I mean I think it's unlikely as well, but it's nice to rule it out completely
the logs do depend on whether a frame or two run long, but it seems pretty surprising that it's happening so often
That error’s been happening before the mod was ever installed
wait, this occlude audio thing you mentioned? does that only show in the log files? I'm not seeing it in the excerpts you screenshotted
oh sorry I kinda missed the context skimming your messages, I thought you were referring to something that was contributing to the frame drops
I didn't get a chance to look too closely at this today, but if the low fps happens consistently on oldred I can have a look at it in profiler tomorrow
I did play a bit of almost vanilla with PathfindingLagFix beta and encountered some unusual and long stutters though, not sure if that was my machine behaving weird or if I may have regressed something
Honestly i should probably try to use the unity profiler for some stuff, could help a lot in identifying what mod’s causing lag so i don’t just blame it on smth else on accident
That’d probably require me having to make an entire new unity project to do so, but i think the assistance it provides would be worth it
If I install the beta version, do I need to keep the normal version at the same time?
They’re 2 different versions
You don’t download the beta along with the current
So these two versions are not compatible with each other. It's best to keep only one of them, right? I see.Are there no serious problems with the beta version at present?
yes, only use one
for the most part i would suggest using the beta, it's pretty stable now and doesn't present any major issues, but it might have minor gameplay differences compared to vanilla (or the original mod, which is almost perfectly faithful)
If I add a lot of extra monsters, can the pathfinding patch still optimize performance?
I think I have added more than a dozen new enemies, including many enemies in coderebirth.
pathfindinglagfix has the highest amount of support for vanilla enemies
because it's designed with them in mind and has some specialized patches for them
but it does patch some general pathfinding methods that most modded enemies will use
and IIRC code rebirth actually takes advantage of some of that specialized design so they should be extra optimized in the future
Thank you very much, at least for now, the performance of the game can still maintain a relatively high level with a large number of additional enemies. Adding this mod in the game at night has improved the performance by more than 40%.
i belive Beta and stable use the same id, so if you have both BepInEx will skip stable and only load beta as it has a higher version number.
it is still better if you only have one of them enabled
you can use an empty project of any kind to profile actually
only slightly annoying part is that you have to use separate executables for the game, so I just have two copies of the entire game and swap between them in Gale
Oh really?
Thats actually much better
glad i don’t have to patch an entire other project for that
I already have like 3 my harddrive is pleading to me
okay so quickkk question unrelated to the mod
but how do i actually profile the modpack using unity like that
oh ew, just booted up that last profile you sent and immediately I see a heartbeat in the menu
time to profile
oh it's just LethalThings
tossing this bit of the deep profile here since I have no clue what a "commando" nutcracker is
but whatever it is, it takes up way too much time setting itself up through LethalEmotesAPI it seems like
also something called "nutcracker3"
Isn't that just one of the reskins for it?
🤔
I don't play heavily modded much
Commando sounds like it's from ExtraEnemyVariety
mod that basically adds skins to existing enemies through the API it uses
coulda sworn i already removed that from the modpack
why does it need to use an emotes api though?
wouldn't this just be a model replacement?
it's spending a disgusting amount of time on Start() for it being purely cosmetic though
I checked and that isn't in there
I thought the same
@slender wadi looks like StarlancerEnemyEscape is causing some massive stutters on that map, you may want to disable it and see if the problem goes away
if it doesn't, lemme know and I can profile again
I wanna say though that if there aren't any other pressing issues, I'll demote that log to debug and push v2 to stable
it's taken long enough
besides the log spam from the hydrogeres (which considering you profiled it, probably means it wasn't an issue that impacted performance), i don't believe i experienced anything else
I did see the masked causing an AI interval stutter due to trying to find the elevator
masked is just really really bad in vanilla on any interior other than Mineshaft
I might add a patch to PathfindingLagFix if nobody else has patched it already
but if anyone has, I will break their patches by doing so and some mods may not handle that too happily
nobody has patched masked yet
if it's not too much to ask
it might be a good idea to do a diff between v56 and v69 to see what exactly changed with their AI
if any issues are noticeable
well I know what the issue is
because a bunch of people have reported issues with their pathfinding ever since the mineshaft update
Commando the internal name for emotesAPI skeleton initialization. Every enemy has a skeleton that can be animated so they are compatible with emotes made for the player skeleton if so desired. This is only called on start and has no tangible impact on gameplay performance that we have been able to measure through extensive testing. If you wish to see a mod utilizing this feature of emotesAPI you can test it with EnemyInteractions.
it calls FindObjectOfType every interval
in mineshaft interiors they tend to get stuck going up and down forever
the elevator
i don't think i've seen them hide in the player's ship ever since v60
it had a significant effect on performance at spawn time, that shouldn't be ignored if at all possible
they seem to just walk around outside for a brief second then immediately walk back inside the building
but only sometimes
half a millisecond is significant?
yes
but I think it may have been more than that, perhaps that's because it was the first spawn? not sure
on a start call that get's called like, at most like 2-3 times a run?
Do you have gameplay scenes where this shows a tangible deficit to frametimes or gameplay framerate?
let me fire it up again 
maybe I'm being a stickler, but I don't really think it's acceptable for an API to cause a significant deviation like that, even if it is only at Start(), if there is any possibility of amortizing or offloading that cost
although arguably maybe this is an issue with the assets being loaded? I don't know anything about the API
(speaking specifically about during normal gameplay)
sorry i feel like im kinda getting in the middle of another conversation
i wasn't just referring to the spikes
although yeah, obv Object.FindObjectOfType is unnecessarily expensive
oh you mean the inconsistent/strange behavior?
Part of the API allows you to use any emotes to work with enemies, in doing so and to make one animation compatible with all rigs in the game, a secondary control armature is prepared during that time that can be activated whenever an emote mod choses to do so to allow any enemy to use said emote. As far as I'm aware only EnemyInteractions utilizes this feature as of current but in our past testing, all frametimes fell within margin of error of vanilla having no impact unless there were literally hundreds of enemies at once.
could check if RoundManager.Instance.currentDungeonType == 4 before searching for a mineshaft elevator, if you believe that is an acceptable fix
but anyways yeah
it feels like their wandering behavior doesn't work like it used to at all
and despite zeekerss putting "fixed masked getting stuck on the elevator" in 2(?) update changelogs it is still definitely a problem
i did a diff between v56 and v69 on my own end and it looks like he just completely rewrote the masked behavior in state index 0
so it's a bit hard to tell what exactly changed
maybe i will look into it on my end and just make masked fixes
Lol
there's a field for the mineshaft elevator lol, it doesn't need to find it at all
using the selection in the screenshot above, it's safe to say that the coroutine there was using well over a millisecond of time, though I'm not sure if all of that was within your API
I'll try to get another profiler recording of that frame on the same seed to give you a better view
and I'd like to make it clear, I don't know if there's a better way to do what you're doing, I just see something spending a lot of extra time and I'm immediately suspicious that there may be
be it object pooling, threading, async/coroutine, etc
another problem would be that it calls RoundManager.FindMainEntrancePosition which does FindObjectsOfType<EntranceTeleport>()
no caching whatsoever
huh, I'll have to look out for that then
this is what I was seeing
does that account for waiting time in coroutines?
also, I don't see EnemyInteractions in here
waiting time as in WaitForSeconds? no, that would wait until the next frame to run
Its a separate mod you must install https://thunderstore.io/c/lethal-company/p/Gemumoddo/EnemyInteractions/
indeed, I'm aware it's a separate mod
that's my point, this doesn't have that, so presumably the functionality is unused?
No, enemy interactions calls the secondary armature instantiated on enemies that spawn, it does not mess with the spawning of the armature
calls?
what do you mean by calls?
it requests to use it?
if the skeleton is unused, why is it being instantiated?
Every entity, player and enemy, are capable of emoting with emotesAPI, thats kinda the point of emotesAPI, its up to emote packs or plugins to utilize the feature.
you can't do so lazily?
what
why is this asset not cached?
Great repository names are short and memorable. Need inspiration? How about scaling-octo-happiness ? - Wet-Boys/LethalEmotesAPI
only instantiate what you need, instead of doing it ahead of time
if someone asks for the skeleton, can you not create it then instead of doing it in Start()?
assuming that is not already the case, but from what you said I'm getting the impression it isn't
I mean you are technically correct yes, but that was deemed not necessary
it certainly appears to have a non-negligible effect on frame pacing to me
debug builds aren't significantly slower than release, when not using deep profiling, so this should be pretty indicative of the actual cost
the fact that it's calling LoadAsset every Start() seems very strange to me
doing that ahead of time at game startup would cut the runtime of the first iteration of this coroutine from 1.75ms to 0.22 ms
and not only that, but you can do it async so that it doesn't block the main thread (if Unity does things correctly)
A: didn't think about it
B: from quick google search (so correct me if you have more experience with it), if I call loadasset on the same item while still having references to it, people are saying unity keeps a cached version of it
I mean, I don't use the mod personally, so I have no stake in it, but it would be good to run the profiler on these things to determine if they are worth doing or not
caching it ahead of time means that you don't get a stall for each new enemy spawned, regardless, so I don't think it makes sense to tell me that it was "deemed not necessary" if you didn't know this was happening
I didn't mean any of this to sound like an attack on your mod, but it definitely pays to do your due diligence with regard to performance
oh I couldn't agree more
with v2 of PathfindingLagFix, I'm aiming for a deviation due to the work the mod is doing of less than .1ms, and it doesn't seem like that should be too hard to achieve in most cases
frame times become drastically better by cutting out synchronous pathfinding, so anything like this becomes painfully obvious on a frame time graph
anything that is a non-optional dependency should not be allowing this unless it's absolutely necessary in my opinion
alr on second thought it's almost 1:30 in the morning for me, so i'll try to get you that profiler log in the morning
i disabled StarlancerEnemyEscape and added the LethalThings dart mod, and i'm currently not experiencing any big lag spikes, if i'm experiencing any at all
obviously it's much much worse if it happens in an Update() call, but enemy Start() isn't exactly a rare occurrence, and I find that there are way too many mods doing way too much in hooks on those methods, to the point where a heavily modded pack gets a deviation of something like 10-20ms from an enemy spawn (not even just due to logging)
that's good to hear, and yeah, get your sleep 
if it happens again we can have another look
Well, here goes nothing:
Version 2.0.0
Note that this has the same mod ID as PathfindingLagFix Beta, but a lower version, so that will need to be disabled in order to run the stable version.
- Rewrote the mod to run all pathfinding patches off the main thread using PathfindingLib, reducing the performance impact of many forms of vanilla enemy pathfinding to near zero. This provides a general framerate improvement when many enemies are spawned, especially for hosts.
- All patches have been completely rewritten.
- Patched behaviors now include:
- All roaming AI (i.e. thumpers, lootbugs, coilheads, and many more)
- All omniscient player targeting (i.e. blobs, jesters, brackens, and more)
- Bracken hunting, evasion, and hiding spot pathfinding
- Snare flea hiding spot pathfinding
- Spore lizard evasion pathfinding
- Tulip snake dismounting pathfinding, and calls to
FindObjectsByType<FlowerSnakeEnemy>() - Manticoil evasion pathfinding
For anyone currently running the beta, nothing has really changed since beta version 2.0.11, but hopefully things will remain stable for the inevitable massive influx of downloads on this mainline release 😅
(apologies for not matching the stable version to the beta version, but I don't want to just leave a big gap in versions for the stable branch, blame Thunderstore for not supporting version revision numbers)
Pathfinding Lag Fix v2
Hi, I would like to know if this mod has or could have incompatibilities with Diversity that does AI revamps, LostEnemyFix, StarlancerIAFIX, SpiderPositionFix, FairAI.
Sorry for the inconvenience and thanks in advance. ^^
I haven't been informed of any issues with those mods, and I would expect any conflicts to occur during startup
it's definitely not intended to conflict with or compete with any of those, so any such issues should be reported and fixed
Ok perfect, thanks
True btw, I don't remember a single time in my recent playthrough it doing that, probably Zeekerss removed that feature with the kidnapper fox update cuz people didn't like enemies camping the ship?
That's just a guess, but idk if this mod can do something about the masked
I tend to stay away from bug fixes in this mod because it's mainly intended to be faithful to vanilla, only exception is the bracken stopping in front of the player when within a certain range since that bug is directly affected by one of the async patches for the bracken
at some point maybe I would end up making another mod that introduces actual bug fixes, but if Butter beats me to it on the masked I wouldn't complain
Technically, it would be faithful to vanilla because masked worked like that before the mineshaft update 
that's arguable, yeah, but there are people that depend on certain behaviors for high quota, and I don't want to interfere with that in a mod that is otherwise intended to be purely for performance
I personally have no aversion to making new projects to keep things separated, I've never been bothered by big mod lists if everything has its defined purpose and does it well :^)
Ok that's fair
If you're to make another project dedicated to the masked, I would also like to request a feature related to him spawning with a random suit from the rack 
oh if I did make such a mod it would be strictly for bug fixing, there's already enough mods that screw with making them more "player-like"
I don't want to get into that rabbit hole where I'll have a million compatibility bugs, unless I have a good motivation to do so
Well, at least I tried 😔 anyway it would be a cool mod
that feels more fitting for mirage tbh. but i belive it already does
yeah, my first thoughts were of Mirage, Lethal Intelligence, MaskedAIRevamp, and GeneralImprovements
all of them mess with the masked in fairly overlapping ways, so it's kinda shocking to me that people don't have more issues with compatibility when it comes to mods affecting masked
But all of them make the masked copy the player suit/cosmetics
I wanted the masked to be able to spawn with a random suit from the rack, not exactly mimicking the player
(And be client-side ofc)
I don't believe all previous employees had the same orange suit 😭
I love the "and be client side ofc"
to be fair that can be done quite easily
Postfix to Start and call setSuit with a random suit id
if there is a Awake postfix that instead
i'd like to fix it but tbh i just dont have a super great understanding of the masked AI
or the generic AI functions
i would've never discovered the cause of that bracken bug you mentioned in v60 because it's a mess of reused variables across multiple generic AI functions, for example
I was just wondering if you had any idea what specifically seems to be going wrong with the masked and if it's possibly related to something similar
i do care a lot about the possibility of fixing this bug though, it's a noticeable downgrade in behavior
so i'll probably try to figure out when im not busy working on other stuff
Is the bug a downgrade in mineshaft, in general, or non mineshaft?
it feels like they don't act like they used to at all, regardless of the interior type
but they act especially incorrect in mineshaft because they seem to just get stuck taking the elevator up and down forever
Interesting, I'm not good with transpilers at all but I could try giving the code a read since I've had to implement the same elevator behaviour beforehand
in v45 they would exit the map and wander around outside
and they'd even hide aboard the ship if they made it there and didnt encounter any players along the way
all of the code for functionality like that still exists and he never made any mentions of removing it, but it doesn't seem to happen anymore
most of the time they just leave the main entrance, walk around for a few seconds, and then walk right back into the main entrance
and get stuck in a loop doing that for forever
Hmm that's gonna help narrow it down if they're just in a kind of loop, hopefully it's not in too much of a mess though I know that's kind of hard with how the elevator is built
also, loosely related to this, the main reason i havent done something like this is because i patched setsuit in buttery fixes
in vanilla (this seems to be the case in mods like mirage and generalimprovements as well) masked never change suit more than once
and i fixed the bunny suit and bee suit not displaying their costume pieces on masked
but i never implemented any functionality to remove those costume pieces if they switch suit to something else
that is a problem i would need to address on my end to support this behavior, because otherwise, it would create visual issues if they randomly select the bee/bunny suit on spawn, and then get reassigned to another suit (such as if the mimic spawn coroutine recognizes they should be mimicking a player's appearance some frames later)
if im bundling all of my masked fixes into a separate mod then i guess that'd be a good opportunity to implement that
i took a brief look at it yesterday but it's a bit hard to tell what exactly is going on
he completely replaced the code in behaviourStateIndex == 0 from v56 -> v69
Yeah im looking now too, I know decompiled numbers aren't too accurate but 2600 lines is quite a bit to go through
and im at least 99% confident that's where the issues lie
but he turned it from a 38-liner to a 107-liner
bool flag = false;
PlayerControllerB closestPlayer = base.GetClosestPlayer(false, false, false);
if (!this.isOutside && closestPlayer != null && RoundManager.Instance.currentDungeonType == 4 && Vector3.Distance(closestPlayer.transform.position, this.mainEntrancePosition) < 30f)
{
flag = true;
}
if (closestPlayer == null || flag != this.isInElevatorStartRoom)
{
bool flag2 = false;
bool flag3 = false;
bool flag4 = true;
and it's always a joy to work with unnamed locals like this
Is elevatorTransform the ship transform?
Stored in startofround so I'm assuming it is
I'm also guessing mineshaft is dungeontype 4
yes
at least as of v64
there was a bug before v64 where march didn't have any interior types assigned and wouldnt reset currentDungeonType from whatever value it previously stored
Amazing
i forget if he fixed the core issue or just assigned a dungeon to march's interior list
so i would be subtly aware of the possibility that custom content might not properly handle that value
Oh the flags are starting to blend in my head now lol
maybe i will move this to #dev-enemies since it's not strictly relevant to pathfindinglagfix anymore
They still can. It’s just not common since when they leave the building they roam around like they usually would instead of just going to the ship. Only if they go near the ship will they attempt to hide.
And also masked going up and down the elevators was fixed by Zeekerss a while back
In v69
I feel like masked allegedly not working the same as they used to is placebo effect, obviously because they had been buggy the last few months until v69 so most people didn’t see them as frequently or just assumed they’re still buggy.
they are definitely still buggy
it's not exclusively placebo effect
it's true there is most likely some factor of placebo
but i have played actual games and watched them take the elevator up and down forever
even in v69
and i've never seen them properly wander outside in actual games since v60, only in very specific conditions on my debug profile
doesn't necessarily mean it's not happening, since you have limited info on most enemies in actual conditions
but the few masked i've actually observed in game seem to just go back and forth inside/outside like i was mentioning before
might be related, but i believe the main entrance point in some mineshaft generation actually doesnt spawn next to the entrance so stuff like masked wouldnt be able to go through the entrance (i think)
i'd had to check it more often but mineshaft's different door location could be a thing to check
okay was testing out again today, and i can confirm i didn't get any lag from pathfinding
i have however found this though from JLL and wesley's moons
which is probably why i've been lagging?
i saved the .data file but it's like
300mb
so i might need to get out mediafire for that
i also don't think i spotted that masked thing from yesterday after i disabled StarlancerEnemyEscape
though i have to check to make sure
oh, that seems curious, did they maybe just not spawn?
damn, that is a crazy amount of time spent, any idea what that lone trap thing is?
makes sense that you were having the log spam if it was having constant spikes to 40-60 ms
what is your frame rate like on vanilla moons? assume based on that profile that your machine must not be super powerful?
definitely is very interesting to see a profile from a machine that struggles to run the game, it would be awesome to get a look at a profile even just from late night March with a fairly vanilla profile (preferably with PathfindingLagFix), too
(as well as this modded one that you grabbed)
I was on Oldred, and the interior was the art gallery
the only traps that would be like that are the mines on Oldred that hang inside the vacility , or the lassoman ropes/paintings from the art gallery that kill you if you touch them
i have a pretty
okay? gaming laptop
it's suited me well for the six years i've had it now
my guess would be that it's the mines, but I can try to have a look later
yeah, if you have UnityExplorer you could simply open the inspector in its free cam and mouse inspect the mines to see what they're called
I am still curious what kind of fps you expect to get generally
I’m curious what the actual fps data displayed here is
I’d think Current FPS, Average FPS, 1% Lows, 0.1% Lows
But that doesn’t work since the third one is larger than the second in the after image
Also is that vanilla vs 2.0 or 1.4 vs 2.0?
alright, brought the unity explorer on board, left image is without Oldred's mine's and the art gallery's lassoman features (mysterious paintings, hanging ropes, etc.), middle image is with with only the lassoman features on, and right image is with only the oldred mines on
righttt discord formats images like that
left image is with nothing
top right image is with only lassoman features
bottom right image is with only oldred mines
I believe it was those, but for some reason the way RTSS records them doesn't seem to work too well, not exactly sure why
left number and the frame time graph are the main things to pay attention to
gotcha, so it looks like that big time spend in fixed update is from the mines
er wait no
lassoman is the issue?
not that I know what that is lol
It's a hazard/enemy on Wesley's interior
@heavy carbon does the lasso stuff in art gallery have any custom code or is it just a combination of interact triggers and JLL scripts with animations?
It does not have any custom code
huh, then maybe it was a fluke, it not showing up in the last profile there
what's WesleyMoonScripts.dll and its LoneTrap component?
looks like it's doing way more work than is reasonable, but not sure how yet
I've never once seen OverlapSphere take a whole millisecond
I've never had any lag from the Lassoman stuff so it might be shenenaigans happening when running a debug build to profile
very doubtful, I've never seen physics queries take that long
it's easy enough to confirm though
finally got around to looking at the script though, and I see two issues:
- It's using the allocating version of OverlapSphere
- It's not passing a layer mask to the OverlapSphere to avoid calculating intersections with and allocating space for colliders that are not involved in this component's interaction
not only that, but I would tend to think that a distance calculation on each player in allPlayerScripts would be faster, though that definitely should be profiled
if the radius of the OverlapSphere is large enough, it definitely seems like that could explain the long runtime of that call
what script is this from specifically?

I mean really what we probably need is a seed to reproduce this extreme slowdown, just so that he can confirm that a new method of doing this actually fully solves the slowdown, but I think that the iterative approach should be something like 30 microseconds max, and therefore could run every frame instead of fixed update if desired
(FixedUpdate is generally not advised for running anything except rigidbody stuff)
im also gonna need to set this up at some point so i can profile my mod, its been a hot minute since i've done that lol
animating transform rotation in there especially seems ugly, that would result in a stuttery movement that cannot be solved by turning on interpolation as it isn't actually going through a kinematic rigidbody
also worth noting that any extra work you put into FixedUpdate() will mean that you'll have frametime variance due to running things on a 50Hz update instead of every frame
better to schedule your things to run on some interval that you can space out between all components if it's at all heavy
or zeekerss's solution for AI of randomizing an interval within a very small range kinda helps with that somewhat
but physics updates themselves cause the frame times to fluctuate constantly anyway, we don't need to make that any worse
I wish we could do cheaper/partial physics updates more often instead of running on a fixed interval
sorry to keep coming back to the masked thing
are you sure the lag affects interiors other than mineshaft?
i agree the findobjectsoftype isn't necessary since he could just use the one cached in roundmanager.instance
but "flag" is only true if currentDungeonType == 4 (meaning a mineshaft generated)
and isInElevatorStartRoom defaults to false
so on any other interior wouldn't flag != isInElevatorStartRoom always be false != false and then the branch would be skipped
beyond defaulting to false, its value is only updated inside the dungeon type 4 branch
isn't the branch on an or?
oh duh
you're right
can't believe i walked through all that logic and completely missed that LOL
rip
that happens
logic from what i read seems to be:
if we're in mineshaft, there is a player inside and the masked just came back from outside
then the masked tries to use the elevator to get back in the facility.
or
if there is no player inside
then try to use the elevator to reach the main entrance
the logic for using the elevator seems to be only one so that's probably why the masked tend to get stuck in a loop in the elevator
A matty of sorts?
Version 2.1.0
- Fixed a bug that would cause the bracken not to path out of line of sight in some situations.
- Added presets and options to configure the bug fixes that slightly change behavior from vanilla.
also yeah what Matty said
I think that logic is:
if the masked has no targetable player (no players in the masked's current area, be it inside or outside)
or if the masked's closest targetable player is in the entrance room and the masked is not, or vice versa
use the elevator
yeah
it definitely doesn't work exactly that way in game
you can stand in the entrance room and watch masked go up and down the elevators constantly, as long as they don't see you (or maybe even if they see you?)
yeah was it you that mentioned the radius is too small? feels like it maybe should be a bounds check
but i think you are right that that is the intent
more like it's too large
huh, really?
if ramps generate at the bottom of the elevator you can trick the masked into thinking you're in the top room while you are at the bottom of the elevator
oh I see
that wouldn't explain this behavior but does seem like a bug
that ought to be fixed
i definitely agree with a rectangular bounds check being the approach
yeah feels like that definitely should be a small bounds check instead of a big ol sphere
at this point im working on a plugin to fix the masked (since i have a bunch of fixes from butteryfixes i could migrate, plus i want to tackle this eventually)
although.. be careful of that one moon that tilts the interior
so i will try to deep dive and figure out what is exactly happening
Nothing bad ever happens when missing with interiors that much
I assume you shouldn't need to overwrite my patch to make it not call FindObjectOfType?
oh did you patch that in pathfinding lag fix?
haha yeah totally didn't have to blacklist it in CullFactory
not yet
soon tm
i was gonna do it myself
oh I see
but the way i was gonna write it
well we can both do it :^)
yee
because my transpiler style is kinda goofy
oh? lol
yeah i just iterate through the code instructions with a for loop and do a bunch of operand checks around surrounding indices
i still have never figured out codematchers
anywho mine are also written similarly, they should all soft fail
lol
oh god
please do that
initially that was what I tried to do, but if you try to do anything remotely complex it becomes unmaintainable
... yeah...
CodeMatcher isn't too bad to use but I honestly like having a home grown one
CodeMatcher really shouldn't be too hard to figure out, lemme know if you want some help with that
or if you wanna use my class 
yeah i want to get better at writing transpilers but most of the time i try to avoid them completely if i can
and whenever i do write them it's so easy to just fall back on being lazy and doing it the old way
but there are definitely some shortcomings that have caused me trouble before
I think that style makes it way too easy to make it dependent on code being laid out in a certain way without being able to verify it conveniently
sometimes (i forget exactly what circumstance but it's been an issue before) i can't use accesstools to get the right methodinfo
so i've had to just read the method in the operand as a string and do contains
and that's pretty ugly and terrible
but "functional"
oh you'll have to use something like AccessTools or the C# reflection classes even with CodeMatcher
might have been generics
or maybe it was like... methods with a lot of overloads
because sometimes i couldnt just match the parameter types
i forget why that was a problem
hmm definitely should be able to
not sure if you plan to address this yourself
but im also probably just going to prefix and replace the RoundManager.FindMainEntranceScript and RoundManager.FindMainEntrancePosition functions
since they each call FindObjectsOfType and Masked call them like 3 times each time they use the entrance doors
it might actually provide some small boosts for other enemies like bracken, maneater, etc. that also reference this function in their AI
you could just cache EntranceTeleports as they spawn (and worst case, do a FindObjectsByType if the list is empty) and it would probably be identical to 99.9999999999% of vanilla and modded use cases
so that is what i am going to do
youd just need to return the one with the first instance ID as the default case, if you dont use instance ID sorting in the find call
@keen ruin @green gust i think i figured something out
it looks like masked can't wander around outside if the only players outside are inside the ship and the ship is closed
i'm using imperium to free cam above the map and i'm noticing they just constantly go in and out of the building if the ship doors are closed
but if the ship door is open, or i am standing off of the ship, they wander around outside freely
i think it's probably pretty safe to call this unintentional behavior
since it calls GetClosestPlayer with cannotBeInShip and cannotBeNearShip both false
but without going back to check v49 i can't say for sure if this is consistent with how masked have always functioned
it seems like the problem is just that the logic of EnemyAI.PlayerIsTargetable is wrong
because it does this check
(!this.isOutside || !StartOfRound.Instance.hangarDoorsClosed || playerScript.isInHangarShipRoom == this.isInsidePlayerShip)
regardless of if cannotBeInShip is false
i am not sure how to go about fixing this
changing this function will have the trickle down effect of affecting all vanilla enemies and modded enemies using this function but it's arguably "more correct" (?)
alternatively a special patch could be written specifically for the masked
this probably ought to be done anyway, to fix masked spamming the elevator even if a player is standing at the top of the mineshaft
i did notice that as long as im encouraging them to use the proper behavior (by leaving the ship door open and standing outside the ship somewhere)
they will enter the ship and hide just like they used to
so i am maybe going to lean towards this being the case
holy shit yeah
i optimized all of the functions using FindObjectsOfType<EntranceTeleport>() and assigned the cached elevator in MaskedPlayerEnemy.DoAIInterval()
and did a quick test spawning 50 masked inside the building then warping to the surface
it runs silky smooth with all of this
but if i disable all the patches it causes horrendous performance
i drop to like, <10 FPS until the masked manage to use the doors (so closestPlayer will stop being null)
that elevator search is bad
hmm, I see, and it doesn't cache those?
I could probably make a fully accurate caching patch for that by transpiling FindExitPoint
i just did it in a prefix
but yes
there's no caching
static bool EntranceTeleport_Pre_FindExitPoint(EntranceTeleport __instance, ref bool __result)
{
if (__instance.exitPoint == null || __instance.exitPointAudio == null)
{
for (int i = 0; i < entranceTeleports.Count; i++)
{
if (entranceTeleports[i] == null)
continue;
if (entranceTeleports[i].entranceId == __instance.entranceId && entranceTeleports[i].isEntranceToBuilding != __instance.isEntranceToBuilding)
{
__instance.exitPointAudio = entranceTeleports[i].entrancePointAudio;
__instance.exitPoint = entranceTeleports[i].entrancePoint;
}
}
}
__result = (__instance.exitPoint != null);
return false;
}
entranceTeleports is a static list i manage (they add themselves in Awake and remove themselves OnDestroy)
i believe this is identical to the original function
https://www.speedrun.com/Lethal_Company/guides/8gfz6
you could use this if you want to check their behavior in previous versions
View Lethal Company speedruns, leaderboards, forums and more on Speedrun.com
i did the same for the other two functions i mentioned
oh i know how to downgrade
it's just a bit of a pain
i can probably just do a code diff and know for sure
since i'm aware of the function causing the issue now
oh ew a prefix cancel
ah I see
prefix cancel is totally incompatible with me making an alternative patch with a transpiler
yeah im only prefixing it on the assumption nobody else cares to touch this
but if you intend to handle it yourself i suppose i will need to actually do the work
i did want to reach out in case you had plans
you would have to detect whether my patch ran and allow the original to run or else we get a situation where my code is unaware that it can't be run and replaces the returned value with null
i normally just check the chainloader on startup and cache a bool
I would like to, if that is indeed a costly operation in practice, I'll have to check though
if i need to return true before my custom code
hmm
in fairness i can probably just replace the findobjectsoftype call with a reference to my static array using a transpiler
you could just postfix it and check if exit point is non null and it has the teleport id you want
i forget if i optimized anything else
postfixing isn't an option because the very first line of code is the FindObjectsOfType call
there is no branching that happens beforehand
that is the case for all 3 functions i mentioned
it would require prefix cancel or transpiler
in FindExitPoint? it's only called if the exit is not already found
public bool FindExitPoint()
{
EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>();
check where it's called
public void TeleportPlayer()
{
bool flag = false;
if (!this.FindExitPoint())
{
flag = true;
}
every time the local player uses the teleport it gets called with no check
oh huh
it is kind of confusing
he has like 3 similarly named functions that all do similar things
i think these two functions sometimes have cached values that get checked first but it's not a hard and fast rule
that's certainly not ideal but doesn't mean my solution doesn't work
feels like fixing that is a job for a different mod
it's not that huge a deal
i don't exactly disagree
postfixing the method and checking it still works fine
it probably belongs somewhere in like, lethal performance, if it weren't going to be put here (which it sounds like it might be)
wdym
nah I wouldn't patch that here
the custom logic would have to replace the original function call (either prefix or transpiler) or it will still do FindObjectsOfType immediately when it is called
at that point custom logic doesn't matter, since you're trying to avoid the search
right?
I mean you can set your cached main entrance from a postfix of FindExitPoint and not have to cancel the method and potentially break transpilers
wha
im caching a list of main entrances and im substituting the search in all the functions that do a search
with an iteration through that cached list
that.. uh
I mean
that's a fine solution but it feels like it's excessive for a masked fix mod
that affects a whole lot more than the masked
if you put that in your main fixes mod that would make more sense to me
but also I still disagree with making it a prefix
well
i am sort of making the assumption that nobody else is touching these functions
which i think is a fair assumption but it is probably not the best etiquette
it's true
you shouldn't have told me about the issue then lol
i will double check and see if im doing any other optimizations
and if im not i will just transpile and replace the search with a reference to the array
i suppose
then again I can probably do it with a postfix and not be broken by your changes I guess
i see
i suppose that is fair enough
how are you making the array?
oh sorry it's a list not an array
i create a list with 8 slots (march has 4 entrances, so that covers all vanilla levels without resizing)
[HarmonyPatch(typeof(EntranceTeleport), nameof(EntranceTeleport.Awake))]
[HarmonyPostfix]
static void EntranceTeleport_Post_Awake(EntranceTeleport __instance)
{
if (!entranceTeleports.Contains(__instance))
entranceTeleports.Add(__instance);
}
[HarmonyPatch(typeof(NetworkBehaviour), nameof(NetworkBehaviour.OnDestroy))]
[HarmonyPostfix]
static void NetworkBehaviour_Post_OnDestroy(NetworkBehaviour __instance)
{
if (__instance is EntranceTeleport entranceTeleport)
entranceTeleports.Remove(entranceTeleport);
}
and it is managed by this
yee that's good enough, although enable/disable would be preferable if those exist
this is what I do for tulip snakes to avoid allocating each access
that is a fair point
(you don't have to add the branches, I'm just doing that so that I can test before/after to ensure nothing changes)
i assume there's no convenient way to like
pseudo-patch EntranceTeleport.OnEnable for example
i've always just patched the base class's method and had a type check but that feels kind of dirty
idk if there's a better way
if it doesn't have those methods then I wouldn't bother
you can just test the enabled property
and destroy?
that was this
static void NetworkBehaviour_Post_OnDestroy(NetworkBehaviour __instance)
{
if (__instance is EntranceTeleport entranceTeleport)
oh
the other option is clearing the list after a scene unloads which is fine for 100% of vanilla cases
but i dont know if that assumption holds true for all custom content
someone will break that assumption for sure
yeah i was concerned about that
networkbehaviour apparently doesnt even override onenable or ondisable
so i'd have to go a step up and patch monobehaviour
and i feel like the further up you go, the more processing time you waste on interactions that are executed globally
and that nullifies a lot of the benefit
yeah
im already a bit worried about this but im not sure what the better way to avoid this problem is
i think it is sacrificing parity with vanilla's return values (potentially breaking modded content) or overstepping into patching base methods
without much happy middleground
yeah, I'll brainstorm a bit when I'm at my PC in a minute
really, I think it's fine for it to call it always and just transpile TeleportPlayer to not call it if the exit point is already found
but this all is something that I think is worth suggesting to DiFFoZ, since he has a patcher that can add methods if desired
(I believe)
well the only reason i've been doing it myself is because i think he's been on hiatus recently
i was also doing vehiclecontroller caching over in butteryfixes because that is "no ETA" on lethalperformance's side
although it's still eventually planned i believe
bit if you wanted to transpile that to not be called within ButteryFixes or something that would maybe be fine
well
I see
i will probably rewrite them to be transpilers
at least
doing the prefixes was nice because it made it really quick and easy to test
and the performance is definitely a boon, for me
but i think you are right and i should probably do it the proper way instead of doing it the lazy way
and hoping it will last "long enough" beore someone breaks it
Lol
you find it noticeable when you teleport?
no i don't really care much about the findexitpoint thing
that was just easy to fix cuz i was fixing everything else the same way at the same time
but these 2 functions get called multiple times (3 times combined) every time a masked uses the entrance doors
and each one is an unskipped FindObjectsOfType call with 0 caching
the biggest performance boost was definitely from the elevator caching
though
right
definitely is something I would like to include here since it can be a pure performance patch
yes
with no behavior change
i was patching them because atm nobody else is patching them
but i think that FindMainEntrancePosition, at least, belongs here, ultimately
it's used in pathfinding for multiple enemies
yeah
FindMainEntranceScript is only used by the masked
and it's just so he can play the sound of the doors opening when they teleport
so that one doesnt matter as much
it's funny that there are two methods that do almost identical things, just one gets the position on top of that logic to find the entrance
i think i actually transpiled out its call in EnemySoundFixes because it warranted replacement with a custom function
huh I see
lol yes ideally you could just feed FindMainEntranceScript into FindMainEntrancePosition and save yourself the effort of writing the same function twice
was it playing the sound on one side regardless of which direction it was going?
but each have different "default" behaviors
find position returns Vector3.zero if it doesn't get a valid result
ah right
and find script returns whatever is at the front of the array (so whichever has the lowest instance ID)
or returns null if the array is empty
you could easily hook null & Vector3.zero into each other
but the return array[0] thing kind of throws a wrench into chaining them with correct behaviours
at least, for my money
if I just use a cached field it's fine
yes and also there was a problem with the walkie talkies
but I have to figure out how to get the "first" one if it fails
i forget which way it was, but it was either players make the door open sound on walkie talkies or the masked do
and the other didn't
not that I think it really matters, but best not to change behavior at all
i just replaced the call in both functions to a shared function that plays audio on both sides of the door, as well as on walkie talkies
oh, do players make the sound on both sides too? I haven't really paid attention to that
yeah, players make audio on both sides of the door, masked only make audio on what side they end up
and then one or the other plays the audio on nearby radios in addition to that
anyways
this probably makes the most sense
im tempted to just leave the findmainentrancescript prefix in since it's only used by masked, but i can practically guarantee some custom mod is using it, and maybe another mod is patching it
so i think that is laziness speaking over reason
i will probably just rewrite all of them to be safe
or well
actually i guess i can just not bother because ideally my userbase is using enemysoundfixes which obsoletes this function anyway
so maybe i will just leave that in someone else's hands if it proves to be an issue with custom content
i guess all im actually trying to say is, when you get a chance, look into patching RoundManager.FindMainEntrancePosition
i think it is of most interest to you
well you shouldn't need to worry about FindMainEntranceScript since I'm planning on patching it
and I think it will be easy to replicate it with caching and still have vanilla paritous behaviour
I could probably bust out a transpiler in like an hour once I decide on the best solution
I gotta figure out the best way to ensure that it perfectly matches the vanilla output
public static Vector3 FindMainEntrancePosition(bool getTeleportPosition = false, bool getOutsideEntrance = false)
{
EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>(false);
for (int i = 0; i < array.Length; i++)
{
if (array[i].entranceId == 0)
{
if (!getOutsideEntrance)
{
if (!array[i].isEntranceToBuilding)
{
if (getTeleportPosition)
{
return array[i].entrancePoint.position;
}
return array[i].transform.position;
}
}
else if (array[i].isEntranceToBuilding)
{
if (getTeleportPosition)
{
return array[i].entrancePoint.position;
}
return array[i].transform.position;
}
}
}
Debug.LogError("Main entrance position could not be found. Returning origin.");
return Vector3.zero;
}
you could simplify it down to this
for (EntranceTeleport teleport in cachedTeleports)
{
if (teleport.entranceID == 0 && getOutsideEntrance == teleport.isEntranceBuilding)
return getTeleportPosition ? teleport.entrancePoint.position : teleport.transform.position;
}
return Vector3.zero;
the fact it compresses so much is one of the reasons it's so tempting to just prefix cancel the original
but under the hood it might not actually offer much advantage
im not too sure
it just looks way cleaner
the only caveat here is you need to make sure your cached teleports are sorted by instance ID
or you could potentially get minute differences if custom content has multiple entrances tagged with an ID of 0
but im pretty certain there would be bigger problems if that was the case, because entrances depend on the ID to match with each other and function as teleports
so i doubt that is a tremendously common problem
caching just main entrance should also work, if I just only assign it if it's null
that would provide the first instance
prefix cancel feels like the play for those methods though
you'd have to be careful how you do this
you'd either need to cache both of the entrance teleports with ID 0
or you'd need to check for both entrance point and exit point (exit point is only selected when the player uses the teleport, so you'd need to find it yourself in this case to be safe)
imo it'd probably just be better to cache the entrance and exit but i suppose both would work
anyways i have some stuff i need to go do
i'd like to release all of this stuff tonight because i am also waiting to release something else
but thank you for the chat
i will continue to look into the masked behavior since i didn't solve all the mysteries i wanted to
the GetClosestPlayer and PlayerIsTargetable thing will be a tricky nut to crack
and IMO it probably approaches changes too subjective to be encompassed by pathfinding lag fix
but maybe it will be possible to fix their elevator usage without straying too far from vanilla's behavior
and the caching will defo help
oh I don't plan on doing any changes to their pathing in PathfindingLagFix
that's all you
ah yeah, I was just suggesting that it was probably a minimal change
I think the intention of the code is there, usually bugs like this are small oopsies
i gotcha
very often related to optional parameters lol
optional parameters are evil
(sometimes)
i think i just misread it as "i could probably fix this with minimal changes" but i see what you mean now
yeah
yee mb
im not sure if you read (i've posted a lot) but part of the problem is that masked don't fetch the "closest" player if they are in the ship with the doors closed
also it's looking more like I'm just gonna do the list trick lol caching is more of a pain than I thought since I forgot it had both sides
the logic to get the right transform is kinda ugly
because even though GetClosestPlayer says it doesn't care if players are in the ship, it calls PlayerIsTargetable which considers a player untargetable if they are in the ship, the doors are closed, and the enemy doing the search is on the other side of the doors (either inside while the player is outside or vice versa)
so if you lock yourself in your ship, the masked won't find any enemies inside and will go outside to search
then see no players outside and go back inside to search
endlessly, every 3 seconds, which explains the weird behavior people have been reporting regarding that
if you make yourself untargetable with imperium you can observe that behavior in plain sight, so i think that's probably clouding a little bit of the debugging process as well
yee I saw you said that
anyways i feel like zeekerss probably just intended that function to call to check "are players on the surface or inside the building" and so i will probably just make it a config option to simplify it to that
it deviates from vanilla behavior but i think it's probably closer to intent
how are people seeing this behavior outside free cam though?
and i think it just feels better
you would be able to see the masked acting weird on the radar
ah I suppose that's true
if you have a corpse or a radar booster next to the entrance doors, and have your door closed
and imo it's not that tall of an order to have a corpse at the doors and your ship closed up on the moons that are spawning masked
so that kinda makes sense to me
replacing it with custom code to get the closest player including within the ship is probably fine
yeah
anyways not to just dump work into your hands but if you're already planning to patch the main entrance doors
i feel like it's pretty likely i will either be doubling up on the work for no tangible benefit (our patches would have the same result) or just causing you problems i'd need to patch out of my mod later
so i might just leave it at the elevator caching and wait to see how things go over here before i get into anything else
the small lag spikes when they teleport is the lesser of two evils, anyway
yeah, up to you as long as your patches can soft fail and don't cause problems for mine 😅 I'll be putting this on the beta branch so you can always test it ahead of time
pushed my patch for the main entrance stuff here: https://github.com/Zaggy1024/LC_PathfindingLagFix/commit/b58170941cdec653bb67e1e7e3cf03a48a2b349e
ended up doing a list and prefix cancel unfortunately, but it should be fine in theory
anyone else transpiling those methods would be pretty strange unless they're trying to fix this issue, and since I use postfixes for everything it shouldn't be able to break
lol, i see
well that is unfortunate but i definitely cant blame you
anyone else transpiling those methods would be pretty strange unless they're trying to fix this issue
this is basically where i am as well
but i suppose you never know, in the end
hey zags question, i assume the lag fix applies to any script using SetDestinationToPosition?
nono the async pathfinding is to reduce main-thread calls to CalculatePath (on NavMesh or NavMeshAgent)
also I just discovered this
I am in pain
zeekerss please
two calls to CalculatePath where one and a variable would suffice
it would be less strange if someone transpiled FindExitPoint though I think
also buttery, I'm seeing a masked go in and out with ship doors open on 42313928, might be worth lookin into
I'll check and make sure it still does that without my patches tho in a sec
what map?
well
moon

i wonder if the offmeshlinks break their ability to pathfind to the player
but i thought titan's other staircase (the one by the fire exit) connects cleanly to navmesh
so idk about that
NavMeshAgent.CalculatePath should be totally consistent with SetDestination in that regard and all others
so I doubt it
unless it's calling NavMesh.CalculatePath and not communicating all agent config
yea this dude is just going in and out, no PathfindingLagFix
wait
did you say doors need to be closed?
the problem is PlayerIsTargetable
if that returns false for any reason, they are considered invalid for GetClosestPlayer
what i was encountering was that if the ship doors are closed, and you are on the opposite side of the doors from the masked in question, it would not consider you as a target, and would go back inside the building
so if your ship doors are open, it could be anything else on that function canceling out your "targetability"
for example, if a masked grabs you, all other masked will start ignoring you (so if you were the only one outside, they will go back in the entrance)
it probably does a check for that one "inKillAnimationWithEnemy" value or whatever it was called
There's a couple that make you untargetable, but yeah prob
yeah it does
looks like it's not a problem with that, GetClosestPlayer() is returning me when he is outside
oh
im stupid
i didnt register the part where you said mineshaft
this probably has to do with broken mineshaft logic yeah
oh I guess I forget what you said about that
ah
if (flag4 && RoundManager.Instance.currentDungeonType == 4 && !this.isOutside)
{
if (!this.isInElevatorStartRoom)
{
flag2 = this.UseElevator(true);
}
else
{
bool flag5 = false;
for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
{
if (!StartOfRound.Instance.allPlayerScripts[i].isPlayerDead && StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled && StartOfRound.Instance.allPlayerScripts[i].isInsideFactory)
{
flag5 = true;
break;
}
}
if (!flag5)
{
flag3 = true;
flag2 = this.GoTowardsEntrance();
}
else if (!flag)
{
flag2 = this.UseElevator(false);
}
}
}
else
{
flag3 = true;
flag2 = this.GoTowardsEntrance();
}
there is this giant block of code
Flag hell
it must be that else block sending it back
and GoTowardsEntrance() forces them to path to the entrance doors
so yeah I'm thinking it might be this
although it's weird
the only thing that should be coming up false here is flag4
and flag4 is the "is elevatorScript not null" boolean
Then doesn't thay just mean that in mineshaft, its just an if else for whether it's inside or outside
it's the masked going back inside, so isOutside == true
so !isOutside == false
the condition we care about is either further up or completely missing
Speaking of Masked when a handful of them path into each other they really like to cause lag lol
whut
this entire thing is happening inside a branch that only applies if:
- the masked is inside and no targetable players are inside, or the masked is outside and no targetable players are outside
or - the masked is inside the building, there is a player inside the building, it's a mineshaft, and that player is within 30 units of the entrance doors
I'd assume there'd be prior code to this that should be handling masked not just instantly going back inside
this might be the elevator caching thing, if it's happening outside of mineshaft
it is the biggest difference for me with masked
Wait it still does this in the second scenario?
i get full frames with 50 masked spawned if i remove the elevator search
Yeah, I know Jade had to reduce the amount that can spawn outside on Rampart due to too many walking into each other sometimes and making the game lag
It may very much be this then
probably
i am publishing my masked plugin tonight
hopefully in a couple minutes or an hour or so
and it will cache the elevator script
although zaggy will probably implement that into pathfindinglagfix beta soon too
lemme just deobfuscate this crap
Lol
Are you also gonna be pushing the update with VehicleController stuff cached soon?
I also saw FindExitPoints was mentioned, was thay a bad function too?
i am releasing 3 things at the same time
Yay
butteryfixes is having masked stuff pulled out of it into the new plugin
and that update will include vehiclecontroller caching
then the mask plugin

and then another new plugin that i was gonna release yesterday and delayed because of all of this junk
Should do a ButteryOptimizations mod
i have not tested these as much as i would've liked so i am really hopeful there aren't major issues i have missed
but i have smoke tested everything and it works pretty well on my profile, at least, so i am optimistic
Excited
I can finally bring the fox back and not have it drag my game down to 15 fps everytime it grabs a player
XD
You messed with a bunch of the entrance and fire exit logic functions in roundmanager right?
that's the hope, anyway
no, zaggy wound up patching them, and both of us were doing prefix cancels
i was only doing them because nobody else had done them yet
Ahh ic
How bad is that one? I use it a decent amount
i added a skip if it exitPoint and exitPointAudio are already cached since there is no reason the vanilla function should be called in that circumstance
you should avoid it as much as possible

it opens immediately with a FindObjectsOfType call
if all you want is the exit point
you can do
if (teleport.exitPoint == null)
teleport.FindExitPoint()
I use it because I need to populate the fireexits ingame ;>
you just shouldn't be calling it actively under almost any circumstance
Iirc it's that function anyway
Hmm yeah I should do it like that
calling it once in some start-of-day script should be fine
but if you are regularly using it over the course of a day it will lag spike
looks like the issue is that flag is not equivalent to isInElevatorStartRoom
i so badly want to just throw out the state 0 logic
no offense to zeekerss but it sucks
Zeekerss needs to separate his shit into readable functions lol
use what? just check if exitPoint == null and then call FindExitPoint if that's what you are talking about
i feel like it'd make way more sense to split it into a "path to main entrance function" and then that handles all the logic of using the elevator only if it's necessary (for mineshaft interiors)
No state machine should just be... like that bleh
that's something I plan on doing in PathfindingLib, actually
generalizing elevator code and making it so that enemies that want to path through them can find a path through any elevators in the level
that's cool
also through teleports
and maybe one of these days i can implement it into a customized masked wander state
that works less bad than this
lol
theoretically the masked could just use a custom roaming algorithm that calls through to that API and then it can wander and check all nodes on the map
i would definitely need to make it a config setting because i dont see a great way to make "replacing an entire behavior state on a vanilla enemy" super transpiler-able
it'd probably just be a prefix cancel with a config at the top to return true instead
yeah it's tricky
but thing is
I think I have to do it in PathfindingLib itself, because the point is to allow people to use PathfindingLib in their own elevator implementations, so the masked have to know how to make use of that too
it's tricky tho
well actually I shouldn't say I would put it in PathfindingLib itself, but a dependency of it that people should make a hard dep if they want to use that API for their moon/interior
How do you even prefix cancel state 0 stuff specifically? Since its in doaiinterval with the rest of the state machines
as long as the state doesn't change before the switch, you can just prefix cancel if state is 0
probably something like
prefix
{
if (configDisablePrefix)
return true;
if (isEnemyDead || currentBehaviourStateIndex != 0)
return true;
// custom state 0
return false;
}
is how i'd do it
Oh yeah that makes sense lol
the more i look at this elevator behavior the more i just dont want to use it at all
i have them working ok on factory and manor except i need to make their targeting less picky
so they dont get stuck entering/exiting the building forever
but all of the mineshaft logic just seems rotten
yeah it does seem more messed up than I thought
trying to figure out the smallest patch to fix this rn
good luck