#Starlancer AIFix v3.13.2 | EnemyEscape v3.0.0
1 messages · Page 9 of 1
Wdym "fix"
not a fix
but a workaround i guess
to make it serversided
idk if this mod alr does that
why its stupid
Because a mod that changes a core gameplay element should never only be opt in by one user
All users should need to opt in
lethalescape got fully serversided
Lethal escape was very buggy too
But ignoring the buginess, I don't think most people enjoyed randomly figuring out that it was installed by host
the lethalescape owner randomly abandoned the mod 😭
like most og mods sadly.
@gleaming robin
i "reworked" the way Slarlance AIFix works, by making their ai smarter, a more efficient mod, just better
do u want it
ayo👀
what i mean by smarter ai, they are just gonna make smarter decisions on what to do
and its really optimized
Do you have a GitHub repo with the source code? I'd need to look at it before I make any decisions there
Depending on how it works, you could also just use AIFix as a dependency and release your mod as an AI "improvement" instead, since if it changes their behavior that kinda goes beyond AIFix's scope.
If you have optimizations for AIFix's code though, feel free to submit a pull request
sure
ok, this is interesting
how would it work?
uses navmesh instead and some other things
Wouldn't that generate desync problems like LethalEscape?
maybe, i did not get in any issues yet
that's a good notice, have you tested it with friends?
do u want to me upload it in thunderstore
as another Starlancer AIFIX variant
oh wait, it's AIFIx, I throught it was EnemyEscape lol
yeah
its AIFix
XD
but hey, I hope everything works perfectly
do you not have a github?
i have
can ya post it so we can take a look?
sure
AIFix seems pretty perfect to me rn, so im just curious what u could've improved
That's not really a source code repository, that's just a download link
yeah
the source is inside it
without navmesh
can you instead post the github with code inside it rather than a zip?
why tho
i dont really wanna download an unknown zip
a zip cant really do nothing

it's also easier to view the code through github
im feeling lazy 
better be sure than risk something
you're free to release an adaptation of my code as long as you adhere to the CC BY-NC-SA license, but I'm not going to download your code and look through it. Please just move the files from the zip into the repo itself and I'll happily look at it
sure
Thank you. I'm gonna be away for a bit for dinner and a movie, but I'll take a look once I get back
Technically zips can, zip bombs are a thing
done
its LCSpawnOnPlayerFix because i used it as a template
wait one sec
i must fix a thing
done
good lordy you really managed to confuse the diff
any chance you could check out his github and apply your changes on top of that instead? because it kinda looks like you might have a bunch of whitespace changes or something going on here
oh yeah lol
you converted everything from spaces to tabs
also, what are all these comments like
// Token: 0x06000007 RID: 7 RVA: 0x000023E5 File Offset: 0x000005E5
? did you decompile it?
its like that because i lost the main source
yeah
used dnspy
oh boy

you'd probably be better off re-applying your patches from memory/referencing that than doing this
this is not PR-able at all
maybe there will have something that you will able to use anyway
well I'm not the author but I'm guessing that AudioKnight isn't going to want to try to determine what you changed from a diff between source and a decomp anyway
it's very difficult to read
you could describe your improvements if you'd like him to look at them
i made it module-like and made it more simple
that's not really specific enough
im testing smthn rq, do you know what would cause this error?
using the code from starlancer's github but im probably building the dll wrong lol
not sure
I mean, other than game version mismatches
are you on the beta? it looks like EnemyAI.Awake() doesn't exist there
ah... that'd do it, does starlancerAIFix not work on the beta rn?
I guess not judging by your error there lol
hmm nah it looks just fine loading it with the original DLL
@faint copper I am not surprised by any of what Woah did to StarlancerAIFix, he has caused problems in other threads in the past and I don't trust him at all lol
So to find out his "Improvement" was butchering the mod
Unsurprising
we dont know that
we don't know what it does lol
but the name did sound familiar
I'm not bothered by it either way
Fair lol, but you did say there was a lot of stuff that was wrong
nothing wrong, just odd way of doing things, and some stuff that made it hard to compare
it's just decompiled so the diff is useless
Ah got it
and if one can't explain the changes that they made to some code, then that code is just not going to be merged
So I just misunderstood lol
so 
Yeahhhhh
having manually looked at it, it seems he added more stuff to jester AI but i couldnt really tell what else, some stuff was slightly changed but that was the main thing i found
Why would Zeekers remove an awake function of all things??
I think because that function wasn't as Optimized as the other one Xu found
So Zeekerss just yeeted it
Lol
Awake is a native method within Unity/C#, it essentially means "as soon as the GameObject exists"
Ahhh strange
Did you find what it needs to be replaced with? There were some changes to EnemyAI
I think the error was unrelated actually, check the other discord 🤭
I'd imagine zeekers just removed it in favor of some other event like Start
I was looking at 1A3's diff of it and I don't see any changes to Awake
idk what the dev environment Xu uses is, but maybe it allowed building without having the necessary packages? Bc unless I'm mistaken I was told the current upload of AIFix works just fine in v55
I'm not sure how this patch ever worked, you're right that Awake() wasn't removed in v55 because it didn't exist in v54 either
I am confoos
oh I'm dumb
Awake is just a native method right? Like Start() and Update()
So it still exists and runs without any explicit calls
That's not at all what I said
You mentioned optimization recently I was going off of that lol
can you run over outside inside enemeis with the cruiser?
If the cruiser does damage in the same way the shovel does, or uses a kill trigger than it should work
Enemies can die via spikes inside, yeah?
I believe Unity uses reflection to find any Awake functions (not sure why they don't use a virtual method but we don't question it), so no, it shouldn't just magically exist as far as I know
the method has to be declared to exist, unless the unity runtime is telling mono to generate the method, which would be pretty pointless
Unsure then, but the awake patch has always worked for me iirc
yeah, that is very strange
Let hoarding bug drive the cruiser.
Thats all.
masked should be
im assuming so it doesnt get called on monobehaviours that don't implement it?
maybe?
I would've thought they would just do an empty default method body for that then
or an interface even, although that's kinda uglee
hmm, that's true
you could be right about that, it probably registers them into a list somewhere
the new v55 inside enemy seems to not get ai fixed
Starlancer will be updating his mods after V55 hits the main branch but this is to be expected, the Fox also probably doesn't get ai fixed

Even if the fox gets AI fixed its AI revolves around the Vain Shrouds, unless those also spawn inside it will probably not work
Tweaks will need to be made to its AI when inside, similar to other creatures in the past
I already played and saw these but please keep it spoiler free if possible 
its kinda hard to in these development channels
like, realistically you shouldnt expect a few of these channels to be spoiler free

there was still an announcement to keep stuff in spoiler tags or on their own channel
announcement doesnt apply to these mod channels where related + #dev-general lol
it doesn't really say that anywhere in the message, but I guess you'd know
same expectations as in when v50 released
obviously in dev general I'd imagine the spoiler rule not applying but I wouldnt imagine these also don't apply to that, it's a bit silly
its not silly at all, you're reporting a bug
well everyone spoiled everything everywhere when v50 released so
not really
bro I got everything spoiled both outside and inside mod threads for v50 😭
oh i thoguth u meant
they spoiled as in
use the spoiler feature
yeah you're right lol
like, peeper thread spoiled me, clips channels didn't have spoiler tags and some stuff in the artwork channel wasn't tagged either

like I'd hop on modding general to ask a question and they'd be blurting out enemy names left and right
like they do now
its unfortunate but spoilers are like that in every community, every game, every show
it took me all my power to not be spoiled about a minecraft video lol
it bothers me a little bit cuz it's really not hard to just ||do this|| but I can't expect everyone to comply obv
like ||I have not seen anything for the clay dude in-game but both Samantha, sagey, some people in fixed bodies, etc spoiled the shit out of me so now I know what it looks like, what its name is, the special player corpse it leaves, and it's just soooo annoying like BRO it's not even been a fucking week...||
it's just frustrating is all
you just gotta close discord and experiecne it before coming back tbh, its what i did
I did for a whole weekend, I can't just do nothing but grind a game when I've got other shit to do but I get what you mean
well, i hope u remember to how not to get spoiled when v60 comes 
any idea why config files might not be generating for me for this mod?
for aifix or enemyescape?
for aifix
aifix doesn't have a config
hey
you can easily make it host only with ```
if (RoundManager.Instance.NetworkManager.IsHost && __instance.OwnerClientId != GameNetworkManager.Instance.localPlayerController.actualClientId)
{
__instance.ChangeOwnershipOfEnemy(GameNetworkManager.Instance.localPlayerController.actualClientId);
}
gets the ownership of the enemy
i'm not the dev, why ping me? also this probably won't work
1A3 that said that
it did for lethal escape
lethal escape had tons of desyncs everywhere
why do you even want it to be host only?
Can confirm
SEE works fine as it is. Please do not bring up the idea of making it "host-only" any more.
no
k then
for me it had no desync, but alright then.
Works on My Machine ™️
I wanna commit drive into hoarding bug
I'll see if I can fix that in the next few days
If you're referring to AIFix, it interacts by removing a patch from LEsc's Jester code
If you mean Starlancer EnemyEscape, I don't recommend using them together. It's possible nothing would break if they were used together, but I made SEE as a modern successor to LEsc
Ah
Someone else was using them both together
EternalX
Starlancer EnemyEscape and LethalEscape
Yea it's redundant to have both lol
b-but what if i want two times the escape so that my enemies can double escape?
Switch to the Chaos preset in SEE
:3c
Hello Mr Starlancer
I have returned
And I must ask of a question of importance
What might this setting inquire? Seconds or Minutes?
thats how many seconds until it picks if it wants to escape or not
Thank you kindly
kirboi is correct
i think barbers in one location will break those in others? saw barbers sliding around inside after a barber spawned outside, probably relating to the master system somehow
You need BarberFixes
By ButteryStancakes
are old birds capable of attacking aifixed enemies yet? and can brackens go outside via enemyescape yet?
Not yet, I'll see if I can address that today
I'll put in a check that should prevent this
What even was the problem here
No idea, but I should prevent the modified code from running on things that don't have an escape component anyways
I was curious why it was running, I looked at the code and thought I saw it being prevented too so was even more confused
Though it might be worth reaching out to the author and seeing if they can fixing compatibility with it @spice kindle
Wait Bellcrab had problems with enemy escape?
If I did have something to prevent it already, it's not working 🤭
Seems so, but idk what exactly without looking at it's code
Huh
Nothing in its enemyai code is the problem
glad I don't set modded enemies to escape
The problem is likely how it's spawned
in or out
I'm guessing it spawns in too early, it spawns in the same time as ingame hazards, because its not registered as an enemy but as a hazard
The error was referencing a FindNextWanderPoint. It's running into an issue with my SetDestination prefix
I was about to say something but I think I know the problem
It's definitely not on your end
Their wander point functions picks a random point in the navmesh
But what if the navmesh isn't baked in at this point?
Ahhh that could be, especially if it stopped erroring after a moment
I think it did yeah, u can notice it errors a few times because its all separate bellcrabs spawning
I'll have to ask batby when navmesh gets baked into the interior
I did indeed already have a check there lol
I'm still gonna look into the old birds, but I think Bracken can follow you out, they just won't escape if they're all alone in the facility (which is intentional atm bc there's a lot I'd have to do to Bracken code that I truly don't feel like doing for now)
them going outside with nobody inside is what i meant
🥹
Yeaaa sorry 😓
I'd have to either
A) Transpile its DoAIInterval() [Clean, very difficult for me bc transpiler]
or
B) Replace its DoAIInterval() using a Prefix [Dirty, but doable. Very dirty. Filthy. Gross]
can you add a guy that politely asks it to go outside to circumvent that
does this mean yes
it means I have no idea how I would do that lol
what exactly are the problems with it going outside?
It's essentially glued to its favorite spot while no one is in the same area as it, so much so that forcefully patching it anywhere results in a tug of war between the destination and it's home spot
would trying to force it to target an outside player work?
I think I tried that before, but I'll experiment at some point
I love watching you cook
Always makes me happy to see you return
c;
do baboon hawks go inside to collect loot? like do they randomly wander inside as normal or do they actively navigate inside to get scrap? would maybe be fun racing baboon hawks to do your job
they've done that a few times yeah
one.time a grou of baboons walked in on my friend getting mauled by a thumper
and since my friend dropped his scrap as he was running away the hawks tried grabbing it which resulted in them ganging up on the thumper and killing it
It ends up being a case of "It Just Works™ "
They don't go inside with the intention of looting, but as soon as they're inside they'll take any loot they come across
randomly wandering inside as normal 😔
PINGAS
enemyescape thinks barber is a mod enemy
Do you have barber fixes on? Maybe that changed things a bit?
I havent looked into how EE detects what is vanilla and what isn't yet
it also thinks the foxes are a modded enemy so
Yeah Starlancer probably would need to update the mod, it's registering them though so i think the issue is minor
U right
Completely forgot that lol
Can someone test those enemies at 100 and make sure they don't error out or anything
Yo Kidnapper, you good bro?
Probably general log code that Zeekers used, like the nutcracker and blob
a
yeah i have unity open
i've been messing around with editor scripts for a couple hours lol
Can you show me an EnemyAI prefab?
yea lemme load one up
EnemyType is a shared ScriptableObject between all monsters of the same species
you can't dynamically alter it on an enemy-by-enemy basis
ye
and for further stuff cuz u asked, the right is the enemytype all my enemies share for snailcat
left is the prefab*
EnemyType also contains the values for the enemy's current spawn count and max spawn count
script references enemytype
so if you have two dogs with separate enemy types, they would each have their own spawn counts which is probably not intended
enemytype also references a prefab
etc.
just lemme see the full component lol
No prob, it's just a lot more convenient for me to see the component like this instead of a decomp
ty
@wind spire Does the basegame correctly add the power levels depending on what list the enemy is in? Meaning, all I need to alter is the removal of the power level?
no
oh
wait
nvm
i misread sorry
yes
power level is added by the function that spawns the enemy
if the enemy is in the inside enemy list, when it is added to a vent, it adds power level
kk
same for if they're in outdoor list
I might be thinking about how ToString() works incorrectly, but would this work?
[HarmonyPatch(typeof(EnemyAI), "KillEnemy")]
[HarmonyPostfix]
private static void KillEnemyPatch(EnemyAI __instance)
{
if (RoundManager.Instance.currentLevel.Enemies.ToString().Contains(__instance.enemyType.name))
{
RoundManager.Instance.currentEnemyPower -= __instance.enemyType.PowerLevel;
}
else if (RoundManager.Instance.currentLevel.OutsideEnemies.ToString().Contains(__instance.enemyType.name))
{
RoundManager.Instance.currentOutsideEnemyPower -= __instance.enemyType.PowerLevel;
}
else if (RoundManager.Instance.currentLevel.DaytimeEnemies.ToString().Contains(__instance.enemyType.name))
{
RoundManager.Instance.currentDaytimeEnemyPower -= __instance.enemyType.PowerLevel;
}
}```
wouldn't getting rid of .ToString() and .enemyType.name get what ya want?
Unfortunately no, because currentLevel.Enemies is a List<SpawnableEnemyWithRarity>
hmm
If this would work, then it's still an early concept, bc it doesn't account for the situation where someone might put the same enemy in multiple lists
yeah true, but u can do that by doing return true, sure there's a very definitive priority done but i cant imagine u being able to do much more
but i think you should loop over that list because it contains the enemy ai that u can compare with (i think)
while it might look like a lot of looping, .Contains probably does something similar in the background
you can do
return true would be unnecessary with else if statements, wouldn't it?
ye
return true means u continue the function, so no real difference
[HarmonyPatch(typeof(EnemyAI), "KillEnemy")]
[HarmonyPostfix]
private static void KillEnemyPatch(EnemyAI __instance)
{
if (RoundManager.Instance.currentLevel.Enemies.Any(enemy => enemy.enemyType == __instance.enemyType))
{
RoundManager.Instance.currentEnemyPower -= __instance.enemyType.PowerLevel;
}
else if (RoundManager.Instance.currentLevel.OutsideEnemies.Any(enemy => enemy.enemyType == __instance.enemyType))
{
RoundManager.Instance.currentOutsideEnemyPower -= __instance.enemyType.PowerLevel;
}
else if (RoundManager.Instance.currentLevel.DaytimeEnemies.Any(enemy => enemy.enemyType == __instance.enemyType))
{
RoundManager.Instance.currentDaytimeEnemyPower -= __instance.enemyType.PowerLevel;
}
}
ah yeah .Any instead of just loopin with a foreach lol
also you need to do
RoundManager.Instance.currentEnemyPower = Mathf.Max(RoundManager.Instance.currentEnemyPower - __instance.enemyType.PowerLevel, 0);
etc. to prevent power from going into negatives like vanilla
and you need to set
RoundManager.Instance.cannotSpawnMoreInsideEnemies = false;
when subtracting from currentEnemyPower specifically
Ahh okay, awesome, yea that's much nicer than ToString()'ing it lol
there is one specific situation where this wouldnt work
the kidnapper fox adds/subtracts outside power
but it isn't a member of currentLevel.OutsideEnemies
it's actually just part of RoundManager's WeedEnemies list
so you might want a || RoundManager.Instance.WeedEnemies.Any(enemy => enemy.enemyType == __instance.enemyType) on that
Just to be clear, that OR should be a part of the outside enemy list check?
i think so ye
cuz otherwise the fox will trigger it too even if its inside and doesnt belong inside
Oh and I added __instance.removedPowerLevel = true; to my EnemyAI.Start() patch as was suggested
just as a note
i'd probably change this to patch over SubtractFromPowerLevel
since that gets called both by KillEnemy and OnDestroy
but im not sure how much that matters
in vanilla enemies don't ever get destroyed except when the day is already over
or when KillEnemy is called with destroy = true
but it might have better mod compat
Fair point
and since your prefix to SFPL is just setting removedPowerLevel my postfix shouldn't cause any problems there, yeah?
yeah
i just do this
[HarmonyPatch(typeof(EnemyAI), "SubtractFromPowerLevel")]
[HarmonyPrefix]
static void PreSubtractFromPowerLevel(EnemyAI __instance, ref bool ___removedPowerLevel)
{
MaskedPlayerEnemy maskedPlayerEnemy = __instance as MaskedPlayerEnemy;
if (maskedPlayerEnemy != null)
{
if (!___removedPowerLevel && maskedPlayerEnemy.mimickingPlayer != null)
{
___removedPowerLevel = true;
}
}
else if (__instance is ButlerEnemyAI)
{
if (Configuration.maskHornetsPower.Value)
{
___removedPowerLevel = true;
}
}
}
and set MaskedPlayerEnemy's isOutsideEnemy to false
so our two mods should work just fine together
Trial run has been a success. I'll probably give it another look tomorrow and see if I notice anything, then upload it
I'm planning a session where I add nearly every custom enemy made
Thinking adding enemy escape on top of it would be hilarious
Spoiler: ||It would||
hehehe
Just know there's a lot of custom enemies that have issues or don't work properly
Expect things to break 😛
Yeee I've been tryna label which are confirmed to work or not work
I think i have around 16 that confirm work
another 16 I get to sort through
Hell yeah'
that jumpscared me so bad, what happened here?
my eyes would never see this without you
I was using the internship mod which basically adds NPCs, but yeah idk what happened, maybe lag issue?
also is the jester not going back in its box a bug in this mod?
I honestly don't know. I've looked at the decompiled code and the diffs to see what's changed since v50, but nothing should've changed to make the jesters buggy
I think Ima disable jesters escaping for now, because it kinda locked me out of the facility
I NEARLY FORGOT TO ADD THIS
Starlancer AIFix v3.7.0 | EnemyEscape v2.4.2
- Starlancer AIFix v3.7.0
- Enemy power level should now subtract from the correct spawnlist upon death.
- Previously, a Thumper spawned that spawned outside would still subtract its power level from the interior spawn sytem after dying.
- Using a pre-defined list, certain vanilla interior enemies now receive a generic threat component. In the future, this may be expanded to be more dynamic and affect modded enemies as well.
- This should allow exterior enemies (such as Old Birds) to attack the ones that normally exist only inside the facility.
- Enemy power level should now subtract from the correct spawnlist upon death.
YESSS
Ah crap, undocumented change:
- Jesters will now forcibly stop targeting a player if the Jester is inside and the player is outside, and vice versa
We'll see if that properly stops the perma-aggro'd Jesters, and maybe I'll finesse it a bit more down the line
niiice
may can you publish it at the github
did you update ReasonableDefaults with the new enemies?
cuz I can't find em in the list here
Will do later, it needs some comment cleanup lol
Nope, haven't updated SEE yet
ah makes sense
k
still not released to the github
huh
Thank you Debby ✨
It's unfortunate, but I'm not a servant and will not be subjected to demands from someone who has repeatedly criticized and diminished my work
no stress, cooking takes time
I've been getting tired of that guy anyways, he already got banned from Matty's thread a few months back by @sterile echo for doing similar behavior
Dude likes to just stir up trouble
He was also warned not to do the same stuff again
I won't say I'm cooking anything up atm, mostly just in maintenance mode. But I love the connections I've formed and the impact that my lil mods have had on the LC Modding community, and people like that aren't the ones I want in my sphere
maintainence is the seasoning
Starlancer is currently cooking the biggest update to his life, I'm talking 20 monsters, 10 interiors, minimum 30 moons
And more
he's working on lethal company 2
I still wanna know why Forest Giants no longer spawn on Auralis
Something is broken with Auralis
😦
You forgot the new game I'm putting in LC that you start by completing S0 with negative scrap in your ship
I ate em
I love negative scrap
If you test it by itself and there's no giants, I'll take a look at it tonight
Baboon hawk wings with a side of forestgiant salad
I mean Giants spawn fine on every other moon it's just Auralis
😦
Maybe we can get that update with your assetbundles optimized too, since it seems like V60 keeps getting delayed 😦
Does it happen even in a test environ? I can't think of why that would be
Yes
Ughhhh alright, I'll look at it later tonight then 😋
Its been handled :3
In fact in a testing profile it was more Empty on my main pack there's usually dogs and baboons that spawn :3
There was nothing on the testing one
🤭
is the testing pack just starlancer moons?
Yeah StarlancerMoons and LGU to probe it Eclipsed
Eclipsed should have like 4 giants spawn in while the ship is landing if not already be spawned in when landing
I'm thinking the spawn nodes that giants use on Auralis are broken somehow
I'll let everyone know if I figure it out 🤭
💜
Will you? 
no
Damb 
Issue was apparently due to me "correcting" the weird unity error regarding the EnemyType scriptable objects names. I've re-copied the SOs and simply stripped them of their prefab and other embedded assets, and it seems to have fixed the issue. Giants are spawning again, and Imperium isn't showing duplicates
Investigating one other thing and then I'll update

There's an issue I just noticed that's most notable on the company building (when using NavMeshInCompany) but basically if you look at the vanilla methods to check LOS:
EnemyAI.CheckLineOfSighthttps://i.1a3.uk/1723511408.pngEnemyAI.CheckLineOfSightForPositionhttps://i.1a3.uk/1723511359.png
You can see both of them have checks for a specific range of coordinates which of course doesn't necessarily match the same value that you are passing into EnemyAI.SetEnemyOutside() therefore EnemyAI.isOutside is incorrect which results in enemies such as the barber not being able to target on the company building
^ @gleaming robin
Slightly related but I also have the code to fix enemies being unable to attack on the company building that you might also find useful to add to AIFix:
[HarmonyPatch(typeof(EnemyAI), "PlayerIsTargetable")]
[HarmonyPrefix]
private static void PlayerIsTargetablePatch(ref bool overrideInsideFactoryCheck)
{
if (StartOfRound.Instance.currentLevelID == 3) // If at the company building ignore the inside factory check
{
overrideInsideFactoryCheck = true;
}
}```
Interesting. I've had a long day, but I'll look into it, unless you already have an idea for a solution.
And thanks, I'll add it soon and credit you :3
Oh, I could just use Zeekers' hardcoded division I guess
But only for the company building
yeah it's probably not ever noticeable anywhere else tbf
Unless I'm being stupid the company would always be outside
the water is around -30 and the roof of the company building is 170
which ofc is never below -100 so would always work if forced to outside
Damn, u right
Easy fix, thanks a bunch for bringing it to my attention and for allowing me to add it to AIFix!
np 🙂
Is this related to why Wesley suddenly dropped dead at The Company building earlier?
LOL
Lmao possibly
🤭
He was so confused
He was like "I didn't even press the killbind button I just died out of nowhere"
XD
@golden basin seems in our case from today it was an AiFix bug lol so Surfaced and Locker are fine. I thought it was related to the same issue as what we had at StarlancerZero cus AiFix was still 3.6.0 there
this wouldnt cause random deaths 🤔
it just results in enemies thinking that they don't have line of sight to a position/object even when they actually do (only on the company building)
Hmmmmm well the issue only ever seems to happen to Wesley too somehow
LOL
I have no idea what it is tbh
Maybe @spice latch is just trolling everyone 🤭
Lmao
Starlancer AIFix v3.8.0 | EnemyEscape v2.4.2
- StarlancerAIFix v3.8.0
- Implemented fixes for spawning interior enemies on the Company moon.
- Thanks @old root!
- The sandworm can now attack in interiors other than the vanilla Factory. Only tested in the vanilla Mansion, but the fix should be universal.
- Implemented fixes for spawning interior enemies on the Company moon.
@spice latch you're welcome
I've updated the source code on GitHub with the latest changes plus some comments. Look at your own risk, for I am not a professional coder.
Legend
You know this means we're going to Polarus later right Wesley?
🤭
Gotta hope rng is on our side and we get an inside worm
what ended up being the cause for the worm issue?
I think the issue is that it was comparing tags for a surface it was allowed to pass through
So I just told it to ignore that bit of code if it's inside
No worm on Bunker 😦
You heard it but it wasn't attacking?
mhm
it was below me on minimap too
Bunker is pretty broken and outdated tbh, so I'm not surprised it doesn't work there but it's still a bit sad since Bunker is my Infernis go to. I'll be trying it on other interiors later tho.
Please do and report back :3
nvm, I think I had an issue with the update. It said it updated your AI, but it stayed on 3.7.0
After testing though it does have a minor, but negligable, issue when emerging.
It sort of repositions itself before attcking and 9/10 times it'll emerge, but sometimes it won't. Still, since it happens behind the scenes and nobody can tell without a minimap, and it'll reposition itself very shortly after I don't think it's a huge issue.
Works on all interiors, yeah. Even on Armory its main body doesn't float in the main area, even when its hitbox is on the highest catwalks. 👍
Yaaaay
I think it's mesh renderer is actually invisible to the player until it attacks, even though you can see it on the minimap
Finally, after all this time, the sandworm WORKS
it's not, just pretty far down
^^ Yeah, you can see it via poltergeist or other death spectator mods. Atlas Abyss happens to be deep enough to show the Leviathan while it's active too. That's why I wanted to try it out on armory.
It's possible a deep enough castle could also make it appear, but since it's a pretty cramped interior and not as open or spacious as Armory it's a pretty easy overlook for me.
Well it won't be perfect, but it works :P
My worms can finally devastate Infernis ^.^ yaaaaaaay
So bit of a weird issue, I was testing the Ghost Girl on Acidir and she appears to not be AIFixed and just not work if spawned outside, which is weird because I thought in vanilla she just worked fine outside, but apparently not?
It was spawned with Imperium if that means anything, just a bit of an oddity I noticed
AIFix is pretty dynamic at this point, so it should have zero problems assigning AI functions. Hopefully just some quirkiness with Imperium
So weird issue we've been experiencing but AiFix did update since. We've been running into a problem where when someone leaves and rejoins the lobby that player can't be heard, and even worse a lot of sounds become global. AiFix was one of the mods that updated before this issue started so is it possible 3.8.0 somehow borked something?
It's such a strange bug and idk what could be causing it
I don't see how AIFix could possibly cause that
Yeah it's very strange lol
Maybe there is some incompatibility or an update with another mod, because this has not happened to me in my games with friends.
and I have all my 230 mods updated
Yeah possible. Just wanted to mention it cuz spawning her outside, she doesn't function at all, she does the thing where she gets stuck next to the ship
If you happen to find the root of this issue, I'd love to know as well 🙏 Ran into the same issue the other night.
Very strange. She's a subcomponent of EnemyAI, so there's no real reason she shouldn't get AIFixed
Yeah I'll see if I can find a way to test her without Imperium to see if it's an Imperium quirk
hey starlancer
so
SEE is having trouble with huggy wuggy
this is on v61 btw
even tho I don't have it set to escape
Yea I had imperium spaz on me a bit too
StarlancerAIFix allows indoor enemies to spawn outside right?
Indeed
Fucking christ
I need Imperium
UUUUUUUGGGGHHHH
Is there a way to disable it? I can't find the config file for this mod
Oh wait
Hold on wait
no no
I read that wrong
No StarlancerAIFix lets Enemies from Indoors and Outdoors have AI anywhere
Indoor or outdoor
meaning like Brackens are now able to have AI outside and Dogs are now able to have AI Inside
if you wanna spawn them in opposite areas
like actually spawn them
use LethalQuantities
yea is there a way to disable that tho? Cause I don't wanna deal with brackens outside lmfao
and if you want them to Escape from inside or go inside
use StarlancerEnemyEscape
I'd say use LethalQuantities
No problem
does this work with modded entities as long as the entity is just a reskin of an existing one? I wanna make it so the Sandman on Tranquility can exit the facility, but regular brackens cannot
i believe this supports most modded enemies
Anything that uses the EnemyAI component will be helped along by AIFix
okay cool, and the config targets by entity names, not specific a.i. functions, right? Cuz' I'm pretty sure the Tranquility author literally just took a regular bracken, gave it a unique name, and made it appear differently but it uses all the exact same a.i. functions as a regular bracken across the board
Oh sorry, I keep forgetting this thread is SEE as well, not just AIFix. But yes, it should register them based on their name.
excellent
I can give the sandman the unique ability of exiting the facility that no other mob will have in my modpack, in this case
Would it be possible to have the Old Bird's statue be placed outside the vent when spawning indoors?
Unless this is supposed to happen and I broke it somehow
No one ever really mentions interior old birds, what broke?
nothing
I got old birds on grand armory on oldred just fine, it sure is panic inducing having a giant robot stomp around inside tho 😂
Yeah that’s the exact interior I was testing it on, but instead of them waking up from a dormant statue, they would appear suddenly from the vents which is terrifying
Nothing wrong behavior wise, just thought I would suggest that
Gotcha. Unfortunately I don't think it'd work very well bc the stationary form is a nest prefab
I’ll just stick to staying away from open vents then, since you can actually see them open upon landing if a old bird is set to come out
I might be stupid, but enemy escape only allows enemies to escape when they've spotted a plaer right? So they can't just wander outside by themselves?
They can randomly choose to path outside by themselves
I put a nutcracker with escape chance on 100 infront of the main entrance and it stayed inside idk?
(using imperium)
Odd. What moon and interior?
erm facility, interior range was 20
it kept walking past it, I spawned it in the main entrance room usign imperium
I've had nutcrackers work in the past, and I don't use any special logic for them, so I'm not sure why they'd be having issues
Stack trace:
EnemyEscape.StarlancerEscapeComponent.Update () (at <8aad92ecb03b4635a4d617df98be2985>:IL_0372)
[06:27:32.8018759] [Error : Unity Log] NullReferenceException: Object reference not set to an instance of an object
Stack trace:
EnemyEscape.StarlancerEscapeComponent.Update () (at <8aad92ecb03b4635a4d617df98be2985>:IL_0372)
[06:27:32.8155481] [Error :UnityDebuggerAssistant]
--- Exception Handler ---
Exception Caught: System.NullReferenceException
Assembly: StarlancerEnemyEscape
Plugin Info
GUID: AudioKnight.StarlancerEnemyEscape
NAME/VER: Starlancer EnemyEscape@2.4.1
LOCATION: \plugins\AudioKnight-StarlancerEnemyEscape\StarlancerEnemyEscape.dll
Message: Object reference not set to an instance of an object
Source: StarlancerEnemyEscape
--- Begin Frames ---
--FRAME 1:
In Assembly: StarlancerEnemyEscape
Target Method: StarlancerEscapeComponent.Update
--- End Frames ---
--- End Exception Handler ---```
having this spammed in the console a lot
--- Exception Handler ---
Exception Caught: System.NullReferenceException
Assembly: StarlancerEnemyEscape
Plugin Info
GUID: AudioKnight.StarlancerEnemyEscape
NAME/VER: Starlancer EnemyEscape@2.4.1
LOCATION: \plugins\AudioKnight-StarlancerEnemyEscape\StarlancerEnemyEscape.dll
Message: Object reference not set to an instance of an object
Source: StarlancerEnemyEscape
--- Begin Frames ---
--FRAME 1:
In Assembly: StarlancerEnemyEscape
Target Method: StarlancerEscapeComponent.SetDestinationToPositionPrefix
--FRAME 2:
In Assembly: Assembly-CSharp
Target Method: BaboonBirdAI.DoAIInterval
--FRAME 3:
In Assembly: Assembly-CSharp
Target Method: BaboonBirdAI.Update
--- End Frames ---
--- End Exception Handler ---```
this as well
@night creek That error is usually if an interior fails to generate an entrance
Check for blocked entrances and see what interior you got.
btw @gleaming robin was looking into the report above and saw this in your update,
if (enemy.GetType() == typeof(FlowermanAI)) //The Bracken doesn't want to path to an entrance when it's alone in the facility. Until or unless I transpile its DoAIInterval(), I'd rather the random pathing not eat up CPU.
{
return;
}
else if (enemy.GetType() == typeof(HoarderBugAI)) //Prevents random pathing when a lootbug is holding an item so it doesn't get confused.
{
if (enemy.GetComponent<HoarderBugAI>().heldItem != null)
{
enemy.SetDestinationToPosition(enemy.GetComponent<HoarderBugAI>().nestPosition);
heads up that c# has some pretty cool ways to do type checking and casting where you can instead do stuff like
if (enemy is FlowermanAI)
if (enemy is HoarderBugAI)
HoarderBugAI hoarderBug = enemy as HoarderBugAI
i think you can actually do this too
if (enemy is HoarderBugAI hoarderBugAI)
which is kinda like a tryget
really handy for that little enemy specific switch statement you have too
also the getcomponent check in your setdestination patch is unideal
reducing this amount of getcomponent calls that are running so often in update for each active enemy might actually have a pretty notable performance gain (if it was ever a bottleneck)
eg. before and after
if (enemy.GetType() == typeof(BaboonBirdAI))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<BaboonBirdAI>().scoutingSearchRoutine);
enemy.GetComponent<BaboonBirdAI>().scoutingSearchRoutine.unsearchedNodes = enemy.allAINodes.ToList();
}
else if (enemy.GetType() == typeof(HoarderBugAI))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<HoarderBugAI>().searchForItems);
enemy.GetComponent<HoarderBugAI>().searchForItems.unsearchedNodes = enemy.allAINodes.ToList();
}
else if (enemy.GetType() == typeof(CrawlerAI))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<CrawlerAI>().searchForPlayers);
}
else if (enemy.GetType() == typeof(SpringManAI))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<SpringManAI>().searchForPlayers);
}
else if (enemy.GetType() == typeof(BlobAI))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<BlobAI>().searchForPlayers);
}
/*else if (enemy.GetType() == typeof(RedLocustBees))
{
enemy.StartSearch(enemy.transform.position, enemy.GetComponent<RedLocustBees>().searchForHive);
}*/
else { enemy.StartSearch(enemy.transform.position); }
if (enemy is BaboonBirdAI baboonAI)
{
enemy.StartSearch(enemy.transform.position, baboonAI.scoutingSearchRoutine);
baboonAI.scoutingSearchRoutine.unsearchedNodes = enemy.allAINodes.ToList();
}
else if (enemy is HoarderBugAI hoarderBugAI)
{
enemy.StartSearch(enemy.transform.position, hoarderBugAI.searchForItems);
hoarderBugAI.searchForItems.unsearchedNodes = enemy.allAINodes.ToList();
}
else if (enemy is CrawlerAI crawlerAI)
enemy.StartSearch(enemy.transform.position, crawlerAI.searchForPlayers);
else if (enemy is SpringManAI springManAI)
enemy.StartSearch(enemy.transform.position, springManAI.searchForPlayers);
else if (enemy is BlobAI blobAI)
enemy.StartSearch(enemy.transform.position, blobAI.searchForPlayers);
else
enemy.StartSearch(enemy.transform.position);
(a switch could also work)
Cool, I'm going out of town for a couple of days, but I'll check it out fully once I get back
Thanks :3
@gleaming robin are modded enemies automatically blacklisted by enemy escape?
They're registered and default to 0
im gonna guess starlancer enemy escape and this mod go hand in hand
i cant find enemyescape config files
You'll have to launch to main menu before a config is generated iirc
i opened and closed the game a couple times and it's there now. thank you!
@gleaming robin hey, kinda specific question but I am working on a minigame mod that features a second indoor dungeon.
I baked the navmesh and entities can walk around freely in the second dungeon, but they seem to be unable to target me, I am using starlancer ai fix since I also need indoor entities to work outside but this is probably just a general problem and I hoped you maybe know what I am missing
Hm. Are you testing with Imperium or anything?
yeah, I can see that they correctly target the nodes and roam without any errors but they just seem to ignore me
targeting works outside though and in the main dungeon as well
Is it one of zeekerss y coordinate checks
I also assume there's no like colliders and whatnot blocking where they need to be looking
it seems like they aren't even trying to look at me, like I wasn't targetable at all
oh
o wait
did u look at "istargetable"
i think i might be le stupid
yeah sometimes talking out loud really helps
also you were kinda right
since the dungeon was at Y -100 and not Y -200, the game didn't mark me as isInsideFactory which obviously leads entities to ignore me exactly like that
they thought I was still outside

well thats one problem less
Wha? I didn't think that was a thing.
The reason I mentioned Imperium is (aside from forgetting you made it) is that I definitely have accidentally left on invisibility before lol
LMAO i was sure to double check that to not embarass myself with my own mod 
I definitely thought EntranceTeleports controlled "isInFactory", do they not?
yep they do, but I am using PlayerControllerB.TeleportPlayer which is used by the teleporter + inverse teleporter I believe
and they determine isInsideFactory by Y level for some reason
or wait, actually it doesn't, but somehow its still working at Y -200 ??
another question, do you know what snare flea does outside? are there any surfaces it can attach to?
what would be the default behaviour, do you know?
I've definitely had it attach to the catwalk on Triskelion, so I think it's just a height check. I'm also looking at the code rn and I'm wondering if something's changed, bc it looks like this is saying if the player has it on them outside it'll automatically die. Could you (or anyone) possibly test that for me?
I think this has actually happened to me before but can't say 100%, I can test it later
Do you have a recommendation for how to apply the prefix to just my affected entities without that GetComponent check?
Even though it may be unideal, it isn't running every frame however (at least I don't think it is)
Can you ss ur code with the get component
I'll just link to the line in the source
https://github.com/AudioKnight/Starlancer/blob/11b4e4637b7a079498ffc7d6f0ba452ffb88658a/StarlancerEnemyEscape/EscapePatch.cs#L489
Unrelated and I could be wrong but I think that getcomponent might always be true
You might need to do != null
I'm not sure how it'd always be true
I guess the way I'd do it is that everytime I give an enemy a component and I only need to check if they have that component I'd add them to a list
It just kinda auto converts
There's some scenarios where that happens, not often in C# but you gotta be careful sometimes
I know me doing:
If (collider.TryGetComponent<PlayerControllerB>(PlayerControllerB player)); is always true
But yeah this is how I'd cache it
If I add the component to an enemy
I add em to a static list
And then check if they're inside that list
I agree that's a good idea, but I'm still confused about the GetComponent thing 🤭
I'll see if I can find a source, but basically what do you think is the result of the getcomponent?
It returns true if the game object has the component attached to it
But I'm prefixing the entirety of SetDestinationToPosition, so that wouldn't always be true
Nah not the full if statement, just what does GetComponent itself return
Does it not return a bool?
If I were to do:
PlayerControllerB player = thing.GetComponent<PlayerControllerB>();
Would that help?
Ahhhh okay
Yeah I also just peeped Unity's manual
I'll try caching it and doing a null check
well
nvm the null check, I forgot the cache would be a list
:P
What's wrong with that lol
Idk static coding is a bad practice for many reasons but in modding it's somewhat required to do static coding to some extent
But you can still use objects and their instance variables instead of static in many cases
So would something like this work?
internal static string[] enemiesThatCanEscape;
...
enemiesThatCanEscape = []; //Do this at the start of each round to reset the list
...
enemiesThatCanEscape.AddItem($"{enemy.NetworkObjectId}"); //To keep each instance unique
...
if (enemiesThatCanEscape.Contains($"{__instance.NetworkObjectId}")) //The SetDestination part
It wouldn't be a string list, it's just be an enemyai list
Would there be a functional difference?
Looks prettier
How? xD
You'd be storing the instance of the enemy, not the stringified ID of it lol
In the container it'd just be .Contains(__instance)
Ah okay
So like this then
internal static EnemyAI[] enemiesThatCanEscape;
...
enemiesThatCanEscape = []; //Do this at the start of each round to reset the list
...
enemiesThatCanEscape.AddItem(enemy);
...
if (enemiesThatCanEscape.Contains(__instance)) //The SetDestination part
Pretty much, I'd change a couple things just because arrays aren't nice to use
I'd change it from an array to list
Like
internal static List<EnemyAI> enemiesblah = new();
And then when u wanna add you'd just do .Add
And when u wanna reset you'd do .Clear
Oh neat
Yeah there aren't really many reasons why you'd ever use an array over a list
So I don't use arrays
Been a while since I coded, and lists were still a bit foreign to me last I did
But yeah that's a lot cleaner
Is new() necessary? Visual Studio isn't throwing a fit about not having it, maybe because it's static?
When you're declaring it yes, because then the list is null and you'd need to initialise it by doing new()
New() just makes a list of size 0 of that type
kk
The actual syntax is like new List<EnemyAI>() but we can shorten it
Apparently it can also just be []
Yep, it can get pretty short lol
Seems like [] is a relatively new addition to the syntax, at least for List
Now to wait for my beta tester
wdym, if you never have to change the contents of a list, arrays are better and less memory intensive
Me when most of the time u have to change the contents of the list:
I mean maybe in your use cases, but there are plenty of cases where a fixed array is sufficent
more in lower level though, I'd imagine
Yeah its just a lot of micro optimisation though
I mean not really, an linked list always has an access time of O(n) whereas an array always has access O(1)
Ofc, its not world ending or anything, it's just good practice to use the most adequate tool for the job
I'd always recommend to use arrays for when you don't need to change the size, a set for when you don't need order and a list for when you need order and need to resize it
Starlancer AIFix v3.8.1 | EnemyEscape v2.4.2
- StarlancerAIFix v3.8.1
- Removed code related to WeedEnemies since Zeekers removed it in the latest beta.
i wonder if he will ever bring back the fox
or if he just completely changes the idea, because its not a bad idea it was just a bad implementation
dunno, but it is nice not to have to consider a 4th enemy type with AIFix/SEE
yeah, its just a shame that I wasted so much time on the spawn prediction of this entity which had multiple bugs I had to consider
just for him to throw it all out the window
I think he's gonna do away with the weed system but eventually bring the fox back
I liked the weed system, it was unique, although it could have used some adjustments
I never experienced it
what howge
I think if removing the weeds actually gave some kind of reward, this whole thing could have been really fun, like what if removing weeds gives you something to sell like bee hives, and the fox tries to stop you from doing so
that'd be way better imo compared to the fox just being another obstacle
yeah, I feel that, i have over 500 hours and I think I actually played for like 100 in november
rest is just starting and closing the game over and over and over and over
180, probably played like 70 or 80 with friends
mhm?
Irrelevant now 🤭
Hey @gleaming robin! Hope all is well. Can we have it to where it's compatible with monsters at the company building like the eyeless dog and a few others? It pairs well with NavMesh
https://thunderstore.io/c/lethal-company/p/Kittenji/NavMeshInCompany/
The eyeless dog stands in place, unfortunately
Pretty sure this isn't something for AiFix to fix
Dog standing in place means the navmesh isn't working proplerly, if it can aggro but not move then it's because NavMeshInCompany is fairly outdated
Yeah AiFix already has fixes for the Company from a PR from 1A3
Which is why I'm saying this isn't an AiFix problem
Ahhh, I misunderstood
Yeah the dog is most likely unable to move or pathfind because the Navmesh isn't setup properly, that mod hasn't been updated in 6 months
Yea, it's possible that v60 (or the new beta) may have broken it somehow. Perhaps someone will fork it or something
how do jesters work with enemyescape? do they chase you outside?
I think they can
But it's been forever since I've tested
Actually
I may have aifixed it to immediately lose aggro if everyone makes it away, but it can still choose to wander in/out
does this mean if the code is completely gone, mods like sober ship and yesfox just completely break? (I mean vanilla code)
I'm unfamiliar with how those are implemented, so you'd have to consult with them
yesfox updated to re-add the missing spawn code
sobership will allow weeds to spawn but not the fox since it doesnt do anything about the missing code
currently enemy escape is broken for me whenever a mineshaft spawns, this is known, correct?
First I'm hearing of it 🤔
I got a bunch of errors, was on triskellion with a mienshaft. Perhaps a mod conflict?
I thought it may be because the main entrance is unreachable for the enemies
In that case it should just not consider the main entrance for pathing
Trisk is weird but so cool
ALSO I'M SO HAPPY I FOUND PLANET SZ ON MY OWN AHHHH
No spoilers though
Ty for the update
Congrats!
enemies can reach main if you take em there with the elevator, but it is very hard to do so without dying
I can imagine 🤭
related clip:
Watch going up and millions of other Lethal Company videos on Medal, the largest Game Clip Platform.
he's got places to be
“OH GOD I LEFT MY OVEN ON”
PFFT
I've seen some things about the updated LethalEscape recommending not to use AIFix. If anyone experiences issues with modded moons having certain enemies not function, please do not bother reporting it. Without AIFix, which is designed to be extremely dynamic and accounts for most situations (and is still being maintained/updated), expect enemies to not behave appropriately.
If someone really wants to use LEsc, they should stick with vanilla moons or configure LLL to have only vanilla enemies spawn on modded moons.
Spider escape success
Blob escape success
@long minnow thank you for your information a while back regarding warping Spiders and Blobs :3
np, glad i was able to help :)
Not so much modded moons, but I was able to get an error spam in the console regarding an external Jester. if you sit on top of the cabinet in the ship, you should be able to recreate it, I wasn't recording at the time.
was something about no target player
Thanks! Pushing an SEE update soon, but I'll look into Jester behavior later.
Starlancer AIFix v3.8.1 | EnemyEscape v2.5.0
- StarlancerEnemyEscape v2.5.0
- Optimized the SetDestinationToPositionPrefix, thanks to @golden basin!
- Optimized the method in which the AI is given fresh behavior upon transition into/out of the interior, thanks to @tulip vault!
- Added the Maneater to the vanilla enemy list with a default escape chance of 1%.
- The reason for the low default chance is that its attack is an instant kill.
- Sandworm now has a default escape chance of 1%, since I was able to fix their interior behavior in AIFix.
- I feel that the Sandworm being able to go into/out of interiors makes logical sense, since it tunnels through the earth itself and there's no reason it should be able to get underneath interiors.
- The reason for the low default chance is that its attack is an instant kill.
- Previously they wouldn't attack in any interior besides the Factory.
- Blob physics have been fixed, so it has been given a default escape chance of 2%.
- This is to balance the fact that entering/exiting right on top of it can be... hazardous :3c
- Previously, the body of the slime would often lag when transitioning into/out of the interior, creating visual and gameplay issues.
- Bunker Spiders now function properly.
- Previously, their mesh refused to follow their NavMeshAgent outside, leading to odd behavior.
I love that this pic also shows a web, indicating that SEE doesn't impede web functionality
Hopefully this also fixes the fake errors with the component getting removed
We'll see, I guess 🤭
Mhm
Well at least Woah is a good motivator
Woah
just wanted to ask, the maneater doesn't escape in it's baby form, right?
No clue. I actually haven't seen the Maneater's behavior myself, I just looked at the wiki. But if it can move, it can escape.
I wonder if it still counts the outside as scary and transforms, or if it needs to be picked up to be scared
or just detected to actually change its state
Looks like, in the BabyUpdate() method, it starts crying if it detects that its outside alone
Or rather if it's outside + not held + not in the ship
babyCrying means held? Thats an odd description
Well you can make it stop crying by doing something while holding it, yeah?
I truly know very little about it 🤭
Yeah...
@gleaming robin Did you miss something?
dunno. i update starlancer and bomb get error
maybe need delete my cfg? sad need setting agins
yap i need deleted my old config
bruh
Oh weird, I didn't expect that to happen
My bad, idk how to prevent that with future updates
@gleaming robin do you mind if i shoot you some more little nitpicks?
you don't mind? sick
StarlancerEscapeComponent.Update
if (isEnemyDead)
{
Object.Destroy(this.enemy.GetComponent<StarlancerEscapeComponent>());
}
if (isEnemyDead)
{
Object.Destroy(this);
}
this one is also in awake ^
also in awake
if (enemy.GetType() == typeof(RedLocustBees)) { ignoreStateCheck = true; }
if (enemy is RedLocustBees) { ignoreStateCheck = true; }
- Gotcha
- I knew I'd miss something
SEE update inc it looks like 🤭
@gleaming robin This one really isn't like necessarily an improvement but a cool way to use newer c# pattern matching to reduce line count
AISearchRoutine newRoutine = enemy switch
{
BaboonBirdAI baboonBirdAI => baboonBirdAI.scoutingSearchRoutine,
HoarderBugAI hoarderBugAI => hoarderBugAI.searchForItems,
CrawlerAI crawlerBugAI => crawlerBugAI.searchForPlayers,
SpringManAI springManAI => springManAI.searchForPlayers,
BlobAI blobAI => blobAI.searchForPlayers,
SandSpiderAI sandSpiderAI => sandSpiderAI.patrolHomeBase,
_ => new AISearchRoutine()
};
if (enemy is BaboonBirdAI baboon)
baboon.scoutingSearchRoutine.unsearchedNodes = baboon.allAINodes.ToList();
else if (enemy is HoarderBugAI hoarder)
hoarder.searchForItems.unsearchedNodes = hoarder.allAINodes.ToList();
else if (enemy is SandSpiderAI sandSpiderAI)
sandSpiderAI.homeNode = enemy.favoriteSpot;
enemy.StartSearch(enemy.transform.position, newRoutine);
in EscapePatch.EntranceTeleportsAndAINodes
FindObjectsOfType can be replaced with FindObjectsByType(FindObjectsSortMode.None) which is faster because it doesn't care about the order it's returning with
Also, while it shouldn't happen, in the event that only returns 1 or 0 entrance your array creations that use entranceTeleports.Length / 2 will blow up. It's fine to use a list here (just use Clear() instead of remaking the list every time)
Does this look right?
private static void EntranceTeleportsAndAINodes()
{
enemiesThatCanEscape.Clear();
entranceTeleports.Clear();
outsideTeleports.Clear();
insideTeleports.Clear();
entranceTeleports = FindObjectsByType<EntranceTeleport>(FindObjectsSortMode.None).ToList();
for (int i = 0; i < entranceTeleports.Count; i++)
{
if (entranceTeleports[i].isEntranceToBuilding)
{
outsideTeleports.Add(entranceTeleports[i]);
logger.LogInfo("Finding exterior EntranceTeleports.");
}
else
{
insideTeleports.Add(entranceTeleports[i]);
logger.LogInfo("Finding interior EntranceTeleports.");
}
}```
Always
Right now where you compare a enemies position to all the entrances and find the best one every time it tries to escape
In theory you could actually “bake” a lot of this data at the start of the day by doing doing this on all the inside nodes and creating a dictionary of nodes and their closest viable entrance
Due to infinite circumstances it might not always work but could check if the path to the dict one is viable if not do your current behaviour instead
Interesting. Wouldn't that cause a fairly noticeable stutter while it's calculating all that?
I'll give it a try this weekend, it sounds like a fun experiment if nothing else
can someone please explain these errors? they were on the clients end
here is my code
0191ca15-6af4-07a3-a375-5f9d6d1583cc
and heres the log
The errors after the new update are cus config needs regenerated
ohhhhh
Yeah
thank you!
Yw
wasnt expecting it to be that simple lol
oh wait, config for which mod? I only have starlancer ai fix
hm not sure if there's a reason to call ToList() on an array there
if the FindObjectsByType call could use a ref List to avoid allocation maybe, but it doesn't look like there's an overload for that
This looks like an old error that we encountered a while back. What moon was this on?
Since FOBT returns an array, is there another way to fill the list?
oh does it need to be in a list for something else?
The current live release uses Arrays, but I'm broadening my horizons with Batby's advice regarding swapping from Arrays to Lists, unless you have an argument against them
oh, I think that was specifically for the collections of interior and exterior teleports
although I'm not sure exactly why Batby mentions length / 2 being 0, since you can have empty arrays
but it does make sense to use lists here to fill those out since you don't 100% know how many will have isEntranceToBuilding set
what I was mainly pointing out is that ToList() isn't free, and since you only read from entranceTeleports after you create it, that one might as well be an array
Welp, I definitely didn't know Clear() would be called on an array
oh no, that wouldn't work on an array
what I'm suggesting is
internal static EntranceTeleport[] entranceTeleports;
internal static List<EntranceTeleport> outsideTeleports;
internal static List<EntranceTeleport> insideTeleports;
internal static List<EnemyAI> enemiesThatCanEscape = [];
{
entranceTeleports = FindObjectsByType<EntranceTeleport>(FindObjectsSortMode.None);
outsideTeleports.Clear();
insideTeleports.Clear();
foreach (var teleport in entranceTeleports) {
...
}
}
FindObjectsByType<EntranceTeleport>(FindObjectsSortMode.None)
allocates once (in managed land), while
FindObjectsByType<EntranceTeleport>(FindObjectsSortMode.None).ToList()
allocates twice
Ohhh, I think I understand
Build two lists out of one array, and clear those each time with .Clear(), while the entranceTeleports array is fully overwritten on SetLevelObjectVariables() with FOBT
I think so? sorry, that sounds backwards, but I think you get the idea
It's all micro-optimizations really, but fun to play around with
yeah, definitely not a big deal for something you'd run once at the start of a level
I actually tend to favor arrays since they're cheaper to access for read-only data than lists, but it's probably negligible
Understandable, but I have seen fun things done with lists, especially to shorten # of lines 🤭
sounds like use cases where lists make sense, unless the fun things are Linq
if you gotta append stuff during the normal game loop then lists are definitely what you want
if you're pre-baking it, you can do a little ToArray() and that'll free up whatever extra memory the List allocated to anticipate future appends
(you can also free that memory with another List method, but if it's not gonna need to append later then there's not much reason to imo)
How does that free anything up, wouldn't that also allocate twice like Array.ToList()?
if you're appending to a list, it likes to allocate extra memory when it runs out of capacity, so that it doesn't have to allocate for each individual append
it never frees up that extra memory unless you tell it to, either by doing ToArray() to allocate an array to exactly match its size, or by calling TrimExcess()
ToArray() and TrimExcess() will both allocate a new chunk of memory to match the size exactly, but once that is done, they consume less memory in the application because the older, larger chunk is now gone
(ToList() will initially match the capacity to the size, if I had to guess, so that's not going to consume extra memory but it will waste an allocation)
I seeeee, good to know.
To see if I actually understand though, a use case for this would be adding something to a list, then caching the newly modified list as an array to essentially tell the system "hey, this list is done changing for now"?
essentially, yeah
if you think you may mutate it in the future, though, I wouldn't bother converting it
👍
Starlancer AIFix v3.8.1 | EnemyEscape v2.5.1
- StarlancerEnemyEscape v2.5.1
- If you experience errors after updating, delete the config and allow a new one to generate.
- Completely missed implementing the new Spider/Blob fixes in both directions. Oops.
- Code cleanup and optimization.
If I remember right, this was on Espira
Is that a new moon? If so, the errors might be stemming from AudioReverbTriggers not being set up correctly
Ah ok I’ll try taking the logs rhere
a while ago someone told me this mod (ai fix) makes old birds work indoors if you inject them
such as them not attempting to fly into the sky when inside
is this true?
I think I've seen them fly, but they've stayed within the bounds of the dungeon
(They still clipped through the roof, but they always land back in the dungeon)
i guess that's fine
Gonna be putting out an update later that removes my LethalEscape related compatibility code. I will only be supporting StarlancerEnemyEscape going forward
Nothing against the original author, I'm actually grateful for their work. The "Updated" version however has become incompatible and I will not be maintaining further compatibility with it when SEE exists and is, in my heavily biased opinion, a superior alternative
(Probably would be a good idea to update what the Reasonable Defaults are in the config description)
U right. I updated it in the readme and completely forgot to do it in the config 🤭
Starlancer AIFix v3.8.2 | EnemyEscape v2.5.2
-
StarlancerAIFix v3.8.2
- Removed code related to compatibility with LethalEscape. I will only be supporting the use of StarlancerEnemyEscape going forward.
-
StarlancerEnemyEscape v2.5.2
- Fixed the description of "Reasonable Defaults"
Can you explain the patch notes for the AI fix? "Removed code related to compatibility with LethalEscape. I will only be supporting the use of StarlancerEnemyEscape going forward" This just means you won't be supporting compatibility issues with the lethal escape mod but yours only correct?
I read it as you won't be supporting your AI Fix mod going forward but only your escape mod lol
You are correct, I was referring to SEE and LEsc being alternatives to one another, and as such I will only be supporting my version and will not address any compatibility issues that arise with the use of LEsc.
AIFix will continue to be supported/maintained/updated as needed for the foreseeable future.
AIFix and SEE will never directly incorporate each others code, as I always want people to choose whether they want enemies to escape or not.
ok awesome!!! I was worried the AIFix was gonna be dropped lol. Thank you
Nah, I need the ego boost that comes with it 🤭
The escape aspect seems to somewhat work for me, the enemies sometimes come out a different exit. if at all, and then when chasing me they can detect an exit and start going between chasing me and going back to the exit causing a loop. and if there are multiple of the same creature they will practically do the exact same thing, (same exit, same path) making it seem like they are the same?
anything here thats fixable?
I got a crawler following me through the emergency exit in Experimentation
and I like how some monsters are triggered by Leaf-Boys from @gilded talon's Biodiversity mod inside the facility
Yeah I had this too. Maneater followed me through a fire exit, but it appeared out of another one and was already at the ship when I came back
That's strange. I'll look into it later, but the code is written such that they should ignore random pathing to exits while chasing. As for the fire exits, that's a new one, since it's supposed to send the monster to the opposite teleport with the same ID.
Gonna be gone for a bit though, in the meantime if anyone notices anything in the source code, lemme know
WIll do, might be something with another mod colliding with it
Oh yeah I assume man eaters are triggered by leafboy sounds?
and blind pups?
there's a lot of moons that use AIfix where enemies just go in and then immediately go out which is really annoying
mainly hoarding bugs on Arcadia are super annoying cuz they just keep blinkin in and out
my issue was with asteroid-13 moon, jesters would only come out as soon as they popped into enraged mode and then couldnt choose wether to chase me or to go back to an exit
same with spore lizards, centipedes, etc not even attempting to exit the facility on Kast
I'll see what I can do to address these issues, ty for the reports
Also please check the configs, not every enemy is enabled by default, or if you're using someone else's code/mod pack the values might have been adjusted
I've blacklisted certain enemies that just don't work properly, and I'm pretty sure I've tested the rest (aside from the newest) and had them work.
For example, I saw something about hoarding bugs not attacking players if they escaped outside, but I checked very recently and they most certainly do.
they definitely do, they just bug out a bit sometimes
like they seem to forget to aggro sometimes but eventually they get around to it
I think it's because they have less mobility inside so their aggro meter goes up faster, whereas outside they have more space.
Idk exactly how their AI functions, but I'll look into it and see if I can make it more responsive
Every enemy was on and at 40+. i used imperium for testing and spawned about 10 around near the exits
very few actually ever came out
some not at all to the point that i spawned 30 and the only times they came out was when the pushed each other into the door
Aggro goes up when you are very closeby. Shouldnt be affected by being outside
Would you mind testing on Chaos?
Mmk, maybe they just need a nudge outside then
yeah gimme 5
No rush at all, I'm heading out for a while, so just whenever you get around to it
Oh and since you're using Imperium, if you have the enemy info up that displays their current behavior state, note that they will only randomly path if they're in state 0
Yeah that's just a base game method to make something make a sound and any enemy that listens for sounds goes to that location etc
i got a few out
and they only seem to come out of that one specific fire exit
@gleaming robin How did you make them only go out of one specific exit anyways?
Hope that's fixed soon, or no Enemy Escape on Thursday lol
and this is them trying to choose between me or the exit
Must've been something from the suggested code. It'll be fixed before then, dw
Stack trace:
StarlancerAIFix.Patches.AIFix.JesterAIPatch (JesterAI __instance, System.Boolean& ___targetingPlayer, System.Single& ___noPlayersToChaseTimer, System.Int32& ___previousState) (at <965ea16450594d8ca6cb6e264b46684b>:IL_007E)
(wrapper dynamic-method) JesterAI.DMD<JesterAI::Update>(JesterAI)
I'll peep the vids and log when I get home tonight, I appreciate your thoroughness
this is on repeat in console
Go ahead and send the full log as well
will do
This is the exact error I was getting in the ship as well btw.
it appears it isnt purely the jester thats indecicive
although harder to see on butler, he is also trying to deicde
no errors pop up for butler though
there are quite alot of mods on so it will be a very big log, sorry about that
When your back, just lmk if theres anything else you need
:D
Okay, I think I see what went wrong. When I changed it over to a list, I no longer had things being sorted by EntranceID. I think I need to use "Insert" instead of "Add" so I can have it a specific element
@golden basin Does this look accurate?
private static void EntranceTeleportsAndAINodes()
{
enemiesThatCanEscape.Clear();
outsideTeleports.Clear();
insideTeleports.Clear();
entranceTeleports = FindObjectsByType<EntranceTeleport>(FindObjectsSortMode.None); //Find all EntranceTeleports
for (int i = 0; i < entranceTeleports.Length; i++)
{
int entranceID = entranceTeleports[i].entranceId;
if (entranceTeleports[i].isEntranceToBuilding)
{
//outsideTeleports.Add(entranceTeleports[i]);
outsideTeleports.Insert(entranceID, entranceTeleports[i]);
logger.LogInfo("Finding exterior EntranceTeleports.");
}
else
{
//insideTeleports.Add(entranceTeleports[i]);
insideTeleports.Insert(entranceID, entranceTeleports[i]);
logger.LogInfo("Finding interior EntranceTeleports.");
}
}
}```
And/or @faint copper
This will probably also fix the issue of enemies not pathing properly, since this probably had a bit of a Butterfly Effect
you can only insert into an existing index, so I don't think that works
it seems like maybe you want a dictionary instead? assuming these entrance IDs are not guaranteed to be sequential
or do you need to iterate over them in order of entrance ID somewhere?
ah, then just Add() them and then Sort() them using a custom comparer
uhh I don't think so? you have to fill it with data, it doesn't default-initialize like an array
I may be wrong though
I wouldn't recommend it though, because like I mentioned, you might have gaps in the IDs
if that happens, you'll crash
mmk, I might just set it back to Arrays then
what did the array code look like? were you assigning insideTeleports[entranceID] = entranceTeleports[i]?
Formerly it was:
if (entranceTeleports == null || entranceTeleports.Length == 0 || entranceTeleports[0] == null) //Find all EntranceTeleports
{
entranceTeleports = FindObjectsOfType<EntranceTeleport>();
outsideTeleports = new EntranceTeleport[entranceTeleports.Length / 2];
insideTeleports = new EntranceTeleport[entranceTeleports.Length / 2];
for (int i = 0; i < entranceTeleports.Length; i++)
{
int entranceID = entranceTeleports[i].entranceId;
if (entranceTeleports[i].isEntranceToBuilding)
{
outsideTeleports[entranceID] = entranceTeleports[i];
logger.LogInfo("Finding exterior EntranceTeleports.");
}
else
{
insideTeleports[entranceID] = entranceTeleports[i];
logger.LogInfo("Finding interior EntranceTeleports.");
}
}
}```
how do you guarantee that entranceTeleports[i].entranceId is not greater than or equal to entranceTeleports / 2?
if you're going to use an array, you have to find the highest entranceId first before you allocate or you can go out of bounds
There has to be a matching ID for both inside and outside, and LLL auto sorts them to 0, 1, 2, ...
So there shouldn't be any instance where there is an out of bounds index
yeah...
you're assuming that something out of your control will behave predictably forever
it works for now, but I wouldn't personally do it
with a list, you can:
- Allocate capacity to
entranceTeleports.Length / 2 Add()all entrances for each sideSort((entranceA, entranceB) => entranceA.entranceId.CompareTo(entranceB.entranceId))
although obviously I haven't looked at how you're using this data, other than you mentioning that you iterate them in order
for example, if you have to map outsideTeleport to insideTeleport, and there's a mismatched teleport, then you're not gonna get the matching teleport between outsideTeleports[i] and insideTeleports[i]
but I will say, I've seen interiors that have stray teleports that weren't accounted for
I don't think it's entirely within LLL's control, unless Batby added more checks and cleanup
As in LLL/vanilla might change, or people would somehow break things in a weird way? If the former, that raises a good point, but for the latter if anything the error exposes the fact that they've done something incorrect
The code has certainly caught ETs not spawning correctly for custom interiors, which leads to entrances saying "blocked", though I suppose that if an interior is purposefully only allowing one fire exit that could be an issue that hasn't yet arisen.
Here's how I iterate in order to link teleports when moving inside/outside:
for (int i = 0; i < insideTeleports.Count; i++)
{
if (Vector3.Distance(insideTeleports[i].entrancePoint.transform.position, enemy.transform.position) <= TeleportRange)
{
enemy.agent.Warp(outsideTeleports[i].entrancePoint.transform.position);```
If the former, that raises a good point, but for the latter if anything the error exposes the fact that they've done something incorrect
While I agree, it's still something that people will complain to you about first (which I've experienced multiple times in relation to interiors)
As in LLL/vanilla might change, or people would somehow break things in a weird way? If the former, that raises a good point, but for the latter if anything the error exposes the fact that they've done something incorrect
Both things apply
any mod can just go ahead and spawn a random entrance teleport anywhere it wants to at any time, and it doesn't have to be connected to anything
the entrance teleports don't even connect until they're used iirc
based on the code snippet you sent there, it looks to me like you really just need a bidirectional mapping
order shouldn't matter there
any mod can just go ahead and spawn a random entrance teleport anywhere it wants to at any time, and it doesn't have to be connected to anything
Fair
the entrance teleports don't even connect until they're used iirc
Not sure what you mean by that though
with a list, you can: ...
So the sorting would occur per list, and it would sort the entranceID sequentially within it's own order? :
if (entranceTeleports[i].isEntranceToBuilding)
{
outsideTeleports.Add(entranceTeleports[i]);
outsideTeleports.Sort((entranceA, entranceB) => entranceA.entranceId.CompareTo(entranceB.entranceId));
logger.LogInfo("Finding exterior EntranceTeleports.");
}
else
{
insideTeleports.Add(entranceTeleports[i]);
insideTeleports.Sort((entranceA, entranceB) => entranceA.entranceId.CompareTo(entranceB.entranceId));
logger.LogInfo("Finding interior EntranceTeleports.");
}```
