#Starlancer AIFix v3.13.2 | EnemyEscape v3.0.0

1 messages · Page 9 of 1

rustic plume
#

this mod is still really good

golden basin
#

Wdym "fix"

rustic plume
#

but a workaround i guess

#

to make it serversided

#

idk if this mod alr does that

golden basin
#

Definitely not

#

That would be stupid lol

rustic plume
golden basin
#

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

rustic plume
golden basin
#

Lethal escape was very buggy too

rustic plume
#

it was a mod that all clients needed it before

#

it updated and its serverside now

golden basin
#

But ignoring the buginess, I don't think most people enjoyed randomly figuring out that it was installed by host

rustic plume
#

the lethalescape owner randomly abandoned the mod 😭

normal wagon
rustic plume
#

@gleaming robin

#

i "reworked" the way Slarlance AIFix works, by making their ai smarter, a more efficient mod, just better

#

do u want it

cunning rivet
#

ayo👀

rustic plume
#

what i mean by smarter ai, they are just gonna make smarter decisions on what to do

#

and its really optimized

gleaming robin
#

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

severe pewter
#

ok, this is interesting

rustic plume
severe pewter
rustic plume
severe pewter
rustic plume
#

as another Starlancer AIFIX variant

severe pewter
#

oh wait, it's AIFIx, I throught it was EnemyEscape lol

rustic plume
#

its AIFix

#

XD

severe pewter
#

but hey, I hope everything works perfectly

golden basin
#

do you not have a github?

rustic plume
golden basin
#

can ya post it so we can take a look?

rustic plume
#

sure

golden basin
#

AIFix seems pretty perfect to me rn, so im just curious what u could've improved

rustic plume
#

used LCSpawnOnPlayerFix as a template lol

gleaming robin
#

That's not really a source code repository, that's just a download link

rustic plume
#

the source is inside it

golden basin
#

can you instead post the github with code inside it rather than a zip?

golden basin
rustic plume
#

a zip cant really do nothing

golden basin
gleaming robin
#

it's also easier to view the code through github

rustic plume
#

im feeling lazy perceive

severe pewter
#

better be sure than risk something

gleaming robin
gleaming robin
#

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

latent kettle
rustic plume
#

done

#

its LCSpawnOnPlayerFix because i used it as a template

#

wait one sec

#

i must fix a thing

#

done

faint copper
#

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?

rustic plume
#

yeah

#

used dnspy

faint copper
#

oh boy

rustic plume
faint copper
#

you'd probably be better off re-applying your patches from memory/referencing that than doing this

#

this is not PR-able at all

rustic plume
faint copper
#

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

rustic plume
#

guess what i think the main source is better lmao

#

stay with it

faint copper
#

you could describe your improvements if you'd like him to look at them

rustic plume
faint copper
#

that's not really specific enough

rustic plume
#

ye

#

im just gonna use it for myself

golden basin
#

using the code from starlancer's github but im probably building the dll wrong lol

faint copper
#

thonk not sure

#

I mean, other than game version mismatches

#

are you on the beta? it looks like EnemyAI.Awake() doesn't exist there

golden basin
faint copper
#

I guess not judging by your error there lol

golden basin
#

hmm nah it looks just fine loading it with the original DLL

rocky fable
#

@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

golden basin
#

we dont know that

faint copper
#

we don't know what it does lol

#

but the name did sound familiar

#

I'm not bothered by it either way

rocky fable
#

Fair lol, but you did say there was a lot of stuff that was wrong

golden basin
#

nothing wrong, just odd way of doing things, and some stuff that made it hard to compare

faint copper
#

it's just decompiled so the diff is useless

faint copper
#

and if one can't explain the changes that they made to some code, then that code is just not going to be merged

rocky fable
#

So I just misunderstood lol

faint copper
#

so shrug

golden basin
gleaming robin
rocky fable
#

So Zeekerss just yeeted it

#

Lol

gleaming robin
rocky fable
#

Did you find what it needs to be replaced with? There were some changes to EnemyAI

gleaming robin
#

I think the error was unrelated actually, check the other discord 🤭

faint copper
#

I'd imagine zeekers just removed it in favor of some other event like Start

gleaming robin
faint copper
#

oh huh

#

my guess was wrong then

#

how did that error happen? thonk

gleaming robin
faint copper
#

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

gleaming robin
#

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

golden basin
rocky fable
reef salmon
#

can you run over outside inside enemeis with the cruiser?

gleaming robin
#

Enemies can die via spikes inside, yeah?

tired ore
#

yes

#

had them pop butlers

faint copper
#

the method has to be declared to exist, unless the unity runtime is telling mono to generate the method, which would be pretty pointless

gleaming robin
faint copper
#

yeah, that is very strange

coarse crescent
#

Let hoarding bug drive the cruiser.
Thats all.

normal wagon
#

masked should be

tulip vault
#

maybe?

faint copper
#

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

tulip vault
#

still has to recieve calls tho right?

#

adds up at scale

faint copper
#

hmm, that's true

#

you could be right about that, it probably registers them into a list somewhere

reef salmon
#

the new v55 inside enemy seems to not get ai fixed

rocky fable
reef salmon
rough echo
#

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

gilded talon
golden basin
#

like, realistically you shouldnt expect a few of these channels to be spoiler free

gilded talon
#

yah but like

#

||it ain't hard to do this||

golden basin
gilded talon
golden basin
#

announcement doesnt apply to these mod channels where related + #dev-general lol

gilded talon
#

it doesn't really say that anywhere in the message, but I guess you'd know

golden basin
#

same expectations as in when v50 released

gilded talon
#

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

golden basin
#

its not silly at all, you're reporting a bug

gilded talon
golden basin
#

not really

gilded talon
#

bro I got everything spoiled both outside and inside mod threads for v50 😭

golden basin
#

oh i thoguth u meant

#

they spoiled as in

#

use the spoiler feature

#

yeah you're right lol

gilded talon
#

like, peeper thread spoiled me, clips channels didn't have spoiler tags and some stuff in the artwork channel wasn't tagged either

golden basin
gilded talon
#

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

golden basin
#

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

gilded talon
#

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

golden basin
#

you just gotta close discord and experiecne it before coming back tbh, its what i did

gilded talon
#

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

compact phoenix
#

well, i hope u remember to how not to get spoiled when v60 comes alright

gilded talon
#

I hope people remember to have common courtesy as well

random shadow
#

any idea why config files might not be generating for me for this mod?

reef salmon
random shadow
#

for aifix

reef salmon
golden basin
#

oh i was thinking of enemy escape

#

whoopsie

rustic plume
#

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

reef salmon
rustic plume
rustic plume
reef salmon
#

why do you even want it to be host only?

rough echo
gleaming robin
reef salmon
rustic plume
#

for me it had no desync, but alright then.

potent hemlock
#

Works on My Machine ™️

rough echo
#

I wanna commit drive into hoarding bug

gleaming robin
short lagoon
#

hey

#

uhm

#

Does ur mod work with LethalEscape?

#

in any way?

gleaming robin
# short lagoon in any way?

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

short lagoon
#

Someone else was using them both together

#

EternalX

#

Starlancer EnemyEscape and LethalEscape

gleaming robin
#

Yea it's redundant to have both lol

round blade
#

b-but what if i want two times the escape so that my enemies can double escape?

gleaming robin
short lagoon
#

Hello Mr Starlancer

#

I have returned

#

And I must ask of a question of importance

#

What might this setting inquire? Seconds or Minutes?

cunning rivet
#

thats how many seconds until it picks if it wants to escape or not

short lagoon
#

Thank you kindly

gleaming robin
#

kirboi is correct

reef salmon
#

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

rocky fable
#

By ButteryStancakes

reef salmon
#

are old birds capable of attacking aifixed enemies yet? and can brackens go outside via enemyescape yet?

spice kindle
gleaming robin
gleaming robin
golden basin
gleaming robin
golden basin
#

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

gleaming robin
#

Though it might be worth reaching out to the author and seeing if they can fixing compatibility with it @spice kindle

short lagoon
#

Wait Bellcrab had problems with enemy escape?

gleaming robin
gleaming robin
short lagoon
#

Huh

golden basin
short lagoon
#

glad I don't set modded enemies to escape

golden basin
#

The problem is likely how it's spawned

short lagoon
#

in or out

golden basin
#

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

gleaming robin
golden basin
#

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?

gleaming robin
#

Ahhh that could be, especially if it stopped erroring after a moment

golden basin
#

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

gleaming robin
gleaming robin
reef salmon
#

🥹

gleaming robin
#

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]

reef salmon
#

can you add a guy that politely asks it to go outside to circumvent that

reef salmon
#

does this mean yes

gleaming robin
#

it means I have no idea how I would do that lol

reef salmon
gleaming robin
#

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

reef salmon
#

would trying to force it to target an outside player work?

gleaming robin
#

I think I tried that before, but I'll experiment at some point

rocky fable
#

Always makes me happy to see you return

#

c;

reef salmon
#

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

gilded talon
#

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

gleaming robin
reef salmon
#

randomly wandering inside as normal 😔

reef salmon
#

enemyescape thinks barber is a mod enemy

golden basin
#

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

reef salmon
golden basin
#

oh

#

then maybe he might need to update a list

#

lol

rocky fable
#

Yeah Starlancer probably would need to update the mod, it's registering them though so i think the issue is minor

gleaming robin
#

U right

#

Completely forgot that lol

#

Can someone test those enemies at 100 and make sure they don't error out or anything

short lagoon
#

Yo Kidnapper, you good bro?

gleaming robin
#

Probably general log code that Zeekers used, like the nutcracker and blob

golden basin
#

a

#

yeah i have unity open

#

i've been messing around with editor scripts for a couple hours lol

gleaming robin
#

Can you show me an EnemyAI prefab?

golden basin
#

yea lemme load one up

wind spire
#

EnemyType is a shared ScriptableObject between all monsters of the same species

#

you can't dynamically alter it on an enemy-by-enemy basis

golden basin
#

ye

#

and for further stuff cuz u asked, the right is the enemytype all my enemies share for snailcat

#

left is the prefab*

wind spire
#

EnemyType also contains the values for the enemy's current spawn count and max spawn count

golden basin
#

script references enemytype

wind spire
#

so if you have two dogs with separate enemy types, they would each have their own spawn counts which is probably not intended

golden basin
#

enemytype also references a prefab

wind spire
#

etc.

gleaming robin
golden basin
#

bit of a big one

#

ignore the last one "target enemy" that's part of my class

gleaming robin
#

No prob, it's just a lot more convenient for me to see the component like this instead of a decomp

#

ty

gleaming robin
#

@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?

wind spire
#

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

gleaming robin
#

kk

wind spire
#

same for if they're in outdoor list

gleaming robin
#

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;
    }
}```
golden basin
#

wouldn't getting rid of .ToString() and .enemyType.name get what ya want?

gleaming robin
#

Unfortunately no, because currentLevel.Enemies is a List<SpawnableEnemyWithRarity>

golden basin
#

hmm

gleaming robin
#

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

golden basin
#

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

wind spire
#

you can do

gleaming robin
#

return true would be unnecessary with else if statements, wouldn't it?

golden basin
#

return true means u continue the function, so no real difference

wind spire
#
[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;
    }
}
golden basin
#

ah yeah .Any instead of just loopin with a foreach lol

wind spire
#

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

gleaming robin
#

Ahh okay, awesome, yea that's much nicer than ToString()'ing it lol

wind spire
#

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

gleaming robin
#

Just to be clear, that OR should be a part of the outside enemy list check?

golden basin
#

i think so ye

#

cuz otherwise the fox will trigger it too even if its inside and doesnt belong inside

gleaming robin
#

mmk

#

I'll throw it at my personal beta tester

gleaming robin
#

Oh and I added __instance.removedPowerLevel = true; to my EnemyAI.Start() patch as was suggested

wind spire
#

just as a note

wind spire
#

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

gleaming robin
#

Fair point

#

and since your prefix to SFPL is just setting removedPowerLevel my postfix shouldn't cause any problems there, yeah?

wind spire
#

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

gleaming robin
#

Trial run has been a success. I'll probably give it another look tomorrow and see if I notice anything, then upload it

carmine shale
#

I'm planning a session where I add nearly every custom enemy made

#

Thinking adding enemy escape on top of it would be hilarious

gleaming robin
carmine shale
#

hehehe

rough echo
#

Expect things to break 😛

carmine shale
#

I think i have around 16 that confirm work

#

another 16 I get to sort through

rough echo
#

Please keep me updated cuz I'm curious

carmine shale
#

Hell yeah'

normal wagon
reef salmon
#

very functional hygrodere

#

exists for 2 frames and no more

gleaming robin
#

lmaooo

#

why did it kill you and no one else

compact phoenix
normal wagon
normal wagon
#

also is the jester not going back in its box a bug in this mod?

gleaming robin
normal wagon
#

I think Ima disable jesters escaping for now, because it kinda locked me out of the facility

carmine shale
gleaming robin
#

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.
normal wagon
#

YESSS

gleaming robin
#

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

normal wagon
#

niiice

rustic plume
gilded talon
#

cuz I can't find em in the list here

gleaming robin
gleaming robin
gilded talon
#

ah makes sense

rustic plume
#

still not released to the github

stiff pulsar
normal wagon
#

huh

gleaming robin
#

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

normal wagon
#

no stress, cooking takes time

rocky fable
#

Dude likes to just stir up trouble

#

He was also warned not to do the same stuff again

gleaming robin
# normal wagon no stress, cooking takes time

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

golden basin
#

Starlancer is currently cooking the biggest update to his life, I'm talking 20 monsters, 10 interiors, minimum 30 moons

#

And more

normal wagon
#

he's working on lethal company 2

rocky fable
#

I still wanna know why Forest Giants no longer spawn on Auralis

#

Something is broken with Auralis

#

😦

gleaming robin
#

You forgot the new game I'm putting in LC that you start by completing S0 with negative scrap in your ship

golden basin
#

I ate em

gleaming robin
normal wagon
rocky fable
#

😦

rocky fable
gleaming robin
gleaming robin
#

Ughhhh alright, I'll look at it later tonight then 😋

rocky fable
#

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

#

🤭

reef salmon
#

is the testing pack just starlancer moons?

rocky fable
#

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

gleaming robin
#

I'll let everyone know if I figure it out 🤭

rocky fable
rough echo
gleaming robin
rough echo
#

Damb NoaDisappointedKomaCafe

gleaming robin
#

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

rough echo
old root
#

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:

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;
    }
}```
gleaming robin
#

Oh, I could just use Zeekers' hardcoded division I guess

#

But only for the company building

old root
#

yeah it's probably not ever noticeable anywhere else tbf

old root
#

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

gleaming robin
#

Damn, u right

#

Easy fix, thanks a bunch for bringing it to my attention and for allowing me to add it to AIFix!

old root
#

np 🙂

rocky fable
#

Is this related to why Wesley suddenly dropped dead at The Company building earlier?

#

LOL

gleaming robin
#

Lmao possibly

rocky fable
#

🤭

#

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

golden basin
#

n-no?

#

this looks like enemy stuff?

old root
#

this wouldnt cause random deaths 🤔

golden basin
#

yeah

#

this is just enemy detection from what i can tell

old root
#

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)

rocky fable
#

LOL

#

I have no idea what it is tbh

gleaming robin
#

Maybe @spice latch is just trolling everyone 🤭

rocky fable
#

Lmao

gleaming robin
#

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.
#

@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.

spice latch
rocky fable
#

🤭

#

Gotta hope rng is on our side and we get an inside worm

reef salmon
gleaming robin
#

So I just told it to ignore that bit of code if it's inside

trim orbit
#

No worm on Bunker 😦

gleaming robin
trim orbit
#

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.

gleaming robin
#

Please do and report back :3

trim orbit
#

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. 👍

gleaming robin
#

Yaaaay

gleaming robin
#

Finally, after all this time, the sandworm WORKS

trim orbit
#

^^ 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.

gleaming robin
#

Well it won't be perfect, but it works :P

trim orbit
#

My worms can finally devastate Infernis ^.^ yaaaaaaay

rough echo
#

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

gleaming robin
rocky fable
#

It's such a strange bug and idk what could be causing it

gleaming robin
#

I don't see how AIFix could possibly cause that

rocky fable
#

Yeah it's very strange lol

severe pewter
#

and I have all my 230 mods updated

rough echo
warm basalt
gleaming robin
rough echo
#

Yeah I'll see if I can find a way to test her without Imperium to see if it's an Imperium quirk

short lagoon
#

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

golden basin
#

That's imperium

#

The errors are imperium

gleaming robin
#

Yea I had imperium spaz on me a bit too

thick bison
#

StarlancerAIFix allows indoor enemies to spawn outside right?

short lagoon
#

Indeed

short lagoon
#

I need Imperium

#

UUUUUUUGGGGHHHH

thick bison
short lagoon
#

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

thick bison
#

yea is there a way to disable that tho? Cause I don't wanna deal with brackens outside lmfao

short lagoon
#

and if you want them to Escape from inside or go inside

thick bison
#

Like on some modded moons brackens spawn outside

#

same with sporelizards

short lagoon
short lagoon
thick bison
#

Thanks

short lagoon
#

No problem

storm citrus
#

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

reef salmon
gleaming robin
storm citrus
#

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

gleaming robin
storm citrus
#

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

hollow kraken
#

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

gleaming robin
#

No one ever really mentions interior old birds, what broke?

normal wagon
hollow kraken
hollow kraken
#

Nothing wrong behavior wise, just thought I would suggest that

gleaming robin
#

Gotcha. Unfortunately I don't think it'd work very well bc the stationary form is a nest prefab

hollow kraken
#

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

normal wagon
#

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?

gleaming robin
normal wagon
#

(using imperium)

gleaming robin
#

Odd. What moon and interior?

normal wagon
#

erm facility, interior range was 20

#

it kept walking past it, I spawned it in the main entrance room usign imperium

gleaming robin
#

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

night creek
#
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

rocky fable
#

@night creek That error is usually if an interior fails to generate an entrance

#

Check for blocked entrances and see what interior you got.

tulip vault
#

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)

gleaming robin
#

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

gilded talon
#

@gleaming robin are modded enemies automatically blacklisted by enemy escape?

gleaming robin
gilded talon
#

good to know though

fallow marsh
#

im gonna guess starlancer enemy escape and this mod go hand in hand

#

i cant find enemyescape config files

gleaming robin
fallow marsh
#

i opened and closed the game a couple times and it's there now. thank you!

patent epoch
#

@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

gleaming robin
patent epoch
#

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

golden basin
#

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

patent epoch
#

I mean I can try

patent epoch
golden basin
#

oh

patent epoch
#

o wait

golden basin
#

did u look at "istargetable"

patent epoch
#

i think i might be le stupid

golden basin
#

thing

#

oh?

patent epoch
#

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

golden basin
#

lol

#

kinda my ass i was right 😂

gleaming robin
patent epoch
gleaming robin
#

I definitely thought EntranceTeleports controlled "isInFactory", do they not?

patent epoch
#

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 ??

gleaming robin
#

🤔

#

I can try to look later, but I'll be busy for the rest of the day

patent epoch
# gleaming robin 🤔

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?

gleaming robin
patent epoch
gleaming robin
#

Even though it may be unideal, it isn't running every frame however (at least I don't think it is)

golden basin
gleaming robin
golden basin
#

Unrelated and I could be wrong but I think that getcomponent might always be true

#

You might need to do != null

gleaming robin
#

I'm not sure how it'd always be true

golden basin
#

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

golden basin
#

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

golden basin
#

If I add the component to an enemy

#

I add em to a static list

#

And then check if they're inside that list

gleaming robin
#

I agree that's a good idea, but I'm still confused about the GetComponent thing 🤭

golden basin
#

I'll see if I can find a source, but basically what do you think is the result of the getcomponent?

gleaming robin
#

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

golden basin
gleaming robin
#

Does it not return a bool?

golden basin
#

If I were to do:
PlayerControllerB player = thing.GetComponent<PlayerControllerB>();

#

Would that help?

gleaming robin
#

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

patent epoch
golden basin
patent epoch
#

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

gleaming robin
#

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
golden basin
#

It wouldn't be a string list, it's just be an enemyai list

gleaming robin
#

Would there be a functional difference?

golden basin
#

Looks prettier

gleaming robin
#

How? xD

golden basin
#

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)

gleaming robin
#

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
golden basin
#

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

gleaming robin
#

Oh neat

golden basin
#

Yeah there aren't really many reasons why you'd ever use an array over a list

#

So I don't use arrays

gleaming robin
#

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

gleaming robin
golden basin
#

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

gleaming robin
#

kk

golden basin
#

The actual syntax is like new List<EnemyAI>() but we can shorten it

gleaming robin
#

Apparently it can also just be []

golden basin
#

Yep, it can get pretty short lol

gleaming robin
#

Seems like [] is a relatively new addition to the syntax, at least for List

#

Now to wait for my beta tester

patent epoch
golden basin
patent epoch
#

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

golden basin
#

Yeah its just a lot of micro optimisation though

patent epoch
#

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

gleaming robin
#

Seems in this case a list is appropriate then

#

assuming everything works

gleaming robin
#

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.
patent epoch
#

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

gleaming robin
#

dunno, but it is nice not to have to consider a 4th enemy type with AIFix/SEE

patent epoch
#

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

gleaming robin
#

yeet

#

Guess I might as well rip the beta

#

@_@

rocky fable
patent epoch
#

I liked the weed system, it was unique, although it could have used some adjustments

rocky fable
#

I never liked it

#

It was unoptimized as shit and went out of control so easily

gleaming robin
#

I never experienced it

patent epoch
#

what howge

gleaming robin
#

My lord, I do not play Lethal Company, I merely exist to craft additions upon it

patent epoch
# rocky fable It was unoptimized as shit and went out of control so easily

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

patent epoch
#

rest is just starting and closing the game over and over and over and over

gleaming robin
#

180, probably played like 70 or 80 with friends

gleaming robin
#

Irrelevant now 🤭

chrome night
#

The eyeless dog stands in place, unfortunately

rocky fable
#

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

lean cargo
#

Wasn’t this added a while ago?

#

Yeah, seemingly added in 3.8.0

rocky fable
#

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

lean cargo
#

Ahhh, I misunderstood

rocky fable
#

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

gleaming robin
#

Yea, it's possible that v60 (or the new beta) may have broken it somehow. Perhaps someone will fork it or something

reef salmon
#

how do jesters work with enemyescape? do they chase you outside?

gleaming robin
#

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

winter flume
gleaming robin
wind spire
#

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

normal wagon
#

currently enemy escape is broken for me whenever a mineshaft spawns, this is known, correct?

gleaming robin
normal wagon
#

I thought it may be because the main entrance is unreachable for the enemies

gleaming robin
chrome night
#

Trisk is weird but so cool

#

ALSO I'M SO HAPPY I FOUND PLANET SZ ON MY OWN AHHHH

#

No spoilers though

chrome night
gilded talon
gleaming robin
#

he's got places to be

chrome night
lean cargo
#

PFFT

gleaming robin
#

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.

gleaming robin
#

Spider escape success

#

Blob escape success

#

@long minnow thank you for your information a while back regarding warping Spiders and Blobs :3

long minnow
#

np, glad i was able to help :)

true kite
#

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

gleaming robin
#

Thanks! Pushing an SEE update soon, but I'll look into Jester behavior later.

gleaming robin
#

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.
gleaming robin
golden basin
#

Hopefully this also fixes the fake errors with the component getting removed

gleaming robin
#

We'll see, I guess 🤭

golden basin
#

Mhm

golden rain
#

Well at least Woah is a good motivator

severe pewter
#

Woah

normal wagon
gleaming robin
golden rain
#

I wonder if it still counts the outside as scary and transforms, or if it needs to be picked up to be scared

severe pewter
gleaming robin
#

Or rather if it's outside + not held + not in the ship

golden rain
#

babyCrying means held? Thats an odd description

gleaming robin
#

Well you can make it stop crying by doing something while holding it, yeah?

#

I truly know very little about it 🤭

golden rain
#

Yeah...

flint vector
#

hmm

#

new update give me this is

rocky fable
flint vector
#

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

gleaming robin
#

Oh weird, I didn't expect that to happen

#

My bad, idk how to prevent that with future updates

tulip vault
#

@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; }
gleaming robin
#
  1. Gotcha
  2. I knew I'd miss something
rocky fable
tulip vault
#

@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)

gleaming robin
#

Gonna go ahead and swap these in while I'm here

gleaming robin
# tulip vault in `EscapePatch.EntranceTeleportsAndAINodes` `FindObjectsOfType` can be replace...

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.");
        }
    }```
tulip vault
#

Ye

#

Do you want a fun idea to think about

gleaming robin
#

Always

tulip vault
#

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

gleaming robin
#

Interesting. Wouldn't that cause a fairly noticeable stutter while it's calculating all that?

gleaming robin
#

I'll give it a try this weekend, it sounds like a fun experiment if nothing else

wary quartz
#

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

rocky fable
wary quartz
#

ohhhhh

rocky fable
#

Yeah

wary quartz
#

thank you!

rocky fable
#

Yw

wary quartz
#

wasnt expecting it to be that simple lol

#

oh wait, config for which mod? I only have starlancer ai fix

rocky fable
#

Oh I thought you were talking about enemy escape

#

Lol

#

My bad XD

faint copper
#

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

gleaming robin
# wary quartz

This looks like an old error that we encountered a while back. What moon was this on?

gleaming robin
faint copper
#

oh does it need to be in a list for something else?

gleaming robin
#

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

faint copper
#

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

gleaming robin
#

Welp, I definitely didn't know Clear() would be called on an array

faint copper
#

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

gleaming robin
#

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

faint copper
#

I think so? sorry, that sounds backwards, but I think you get the idea

gleaming robin
#

It's all micro-optimizations really, but fun to play around with

faint copper
#

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

gleaming robin
#

Understandable, but I have seen fun things done with lists, especially to shorten # of lines 🤭

faint copper
#

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)

gleaming robin
faint copper
#

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)

gleaming robin
#

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"?

faint copper
#

essentially, yeah

#

if you think you may mutate it in the future, though, I wouldn't bother converting it

gleaming robin
#

👍

gleaming robin
#

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.
wary quartz
gleaming robin
#

Is that a new moon? If so, the errors might be stemming from AudioReverbTriggers not being set up correctly

wary quartz
#

Ah ok I’ll try taking the logs rhere

fallow marsh
#

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?

hollow kraken
#

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)

fallow marsh
#

i guess that's fine

gleaming robin
#

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

autumn panther
gleaming robin
gleaming robin
#

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"
brisk lynx
#

I read it as you won't be supporting your AI Fix mod going forward but only your escape mod lol

gleaming robin
#

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.

brisk lynx
gleaming robin
#

Nah, I need the ego boost that comes with it 🤭

random thicket
#

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?

severe pewter
#

and I like how some monsters are triggered by Leaf-Boys from @gilded talon's Biodiversity mod inside the facility

golden rain
gleaming robin
#

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

random thicket
#

WIll do, might be something with another mod colliding with it

gilded talon
#

and blind pups?

gilded talon
#

mainly hoarding bugs on Arcadia are super annoying cuz they just keep blinkin in and out

random thicket
#

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

gleaming robin
#

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.

gilded talon
#

like they seem to forget to aggro sometimes but eventually they get around to it

gleaming robin
#

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

random thicket
#

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

golden rain
gleaming robin
gleaming robin
random thicket
gleaming robin
#

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

golden basin
random thicket
#

i got a few out

#

and they only seem to come out of that one specific fire exit

rocky fable
#

@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

random thicket
gleaming robin
random thicket
#
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)
gleaming robin
#

I'll peep the vids and log when I get home tonight, I appreciate your thoroughness

random thicket
#

this is on repeat in console

gleaming robin
#

Go ahead and send the full log as well

random thicket
#

will do

true kite
random thicket
#

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

gleaming robin
#

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

faint copper
#

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?

gleaming robin
#

I do iterate, yeah

#

I can set the length of a list, right?

faint copper
#

ah, then just Add() them and then Sort() them using a custom comparer

faint copper
#

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

gleaming robin
#

mmk, I might just set it back to Arrays then

faint copper
#

what did the array code look like? were you assigning insideTeleports[entranceID] = entranceTeleports[i]?

gleaming robin
#

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.");
                    }
                }
            }```
faint copper
#

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

gleaming robin
#

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

faint copper
#

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 side
  • Sort((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

gleaming robin
# faint copper you're assuming that something out of your control will behave predictably forev...

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);```
faint copper
#

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

gleaming robin
#

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.");
}```