#Starlancer AIFix v3.13.2 | EnemyEscape v3.0.0

1 messages · Page 6 of 1

faint copper
#

it obviously doesn't hurt to have that mod too, but I feel like for the purposes of testing EnemyEscape, it may mask some issues

#

especially if it updates the AI nodes in DoAIInterval still

hallow sigil
#

I'm guessing that EnemyEscape is separate to not break AIFix since there are currently problems with the AI switching and behaviour. Because AIFix is the base for the AI of inside enemies to work outside and vice versa.

faint copper
#

unless I'm missing something, it's not required for AI to work outside in EnemyEscape

#

SetEnemyOutside sets the AI nodes so that they can function in the opposite environment

hallow sigil
faint copper
#

AIFix initially was set up to just set the AI nodes based on where the enemy is when it was spawned, then it was changed to update that every interval to allow LethalEscape to work, from my understanding

#

but LethalEscape didn't call SetEnemyOutside, so the AI nodes were incorrect, and that was what AIFix changed

#

it doesn't apply to EnemyEscape

faint copper
gleaming robin
#

There might be a slight issue with some enemies in current Enemy escape, but AIFix fixes certain issues that arise from enemies being in the wrong place, like the outside coilhead slide, sandworms always resetting to the same node after attacking indoors (still need to figure out why they only work in the factory, but that's a later problem), and the Jester not functioning correctly outside

hallow sigil
gleaming robin
#

Rather than put those fixes into a new mechanics mod, I'd rather just make the new mechanics depend on the fixes

#

EnemyEscape handles the teleport inverting the ai, but not the spawn-in-non-native-area AI

gleaming robin
#

Np :3

faint copper
tall merlin
#

Nope, nothing like that in our mod that I know of

#

Why? Whats up?

gleaming robin
#

You were mentioned up here, so I just thought I'd ask

tall merlin
gleaming robin
#

Yea sorry a few messages down from that

tall merlin
gleaming robin
#

mmk, it should be fixed next update regardless I hope

gleaming robin
#

Would you really want it configurable per enemy, or a global inside and global outside range?

#

I mostly just don't want to set up more stuff for presets ; w ;

#

though I guess I could just set them to 50 inside 200 outside as defaults and let people do w/e from there without presetting things
plus it'd be funny to have the Chaos preset default to 1000, but that's something again that people can choose to do if they set it to Chaos I suppose

turbid wave
turbid wave
gleaming robin
#

mmk, I'll whip up a quick config binding for it, I'm almost done with a massive improvement to the AI of EnemyEscape lmao

#

Much like the AIFix, it was relatively simple to make a Proof-of-Concept, but this is taking some COOKING to get good

gleaming robin
#

Alright, it's unfortunately gotten really late, so I'm not gonna release the update tonight. Tomorrow I'll add the range configs and probably some extra logic for specific enemies, most notably the Hoarding Bugs and Baboon Hawks, since they need to dynamically create a second nest when they either go in or come out of the facility.

#

I've done so much today ; w ;

#

and no, the picture is not meant to be legible

tulip vault
#

you been grinding

gleaming robin
tulip vault
#

lll be like

#

at some point you'd still totally crush lethaltoolbox related stuff i bet

#

editor tooling is also really fun to play with

gleaming robin
wary bough
#

I was playin with the mod today N forgot that dogs can go into the building, it scared the shit out of me

#

Wish I had a clip of it

wary bough
spiral ermine
#

Cruel

#

and unfiltered hatred

spiral ermine
#

Holy fucking shit

#

I just discovered something radical

#

Fuck

#

its

#

not 100%

#

hold this

#

oK

#

The relationship between SnatchinBracken and EnemyEscape is strong

#

But

#

there are

#

issues

#

using EnemyEscape the bracken can sucessfully path from outside to inside the facility to the bracken room

#

however

#

it uh

#

get stuck whenver trying to go through the fire exit

#

specifically

#

the one on experimentation

#

where it tries to go through it

#

but cannot touch it

#

because its holding you inbetween it and the fire exit

#

OH WAIT A SECOND

#

ITS BECAUSE HE STILL HAS THE CHACNE TO USE THE TELEPORT

solid wyvern
#

Ey @gleaming robin found a bug with the starlanceAi 3.5.1 (probably 3.5.0 too) were slimes got compact into a ball and did no damage. Downgraded to 3.4.1whatever and seems to work fine. I'm playing on v49 so that may be it

#

didn't take a screenshot unfortunately

turbid wave
spiral ermine
#

It can path to the inside facility room

#

However

#

its teleportation of that pathing sucks

turbid wave
spiral ermine
#

From the second he grabs me he paths towards the fire exit closest to the bracken room

#

wacky am i rite @wintry wind @gleaming robin

#

going to try one more time with aipathfinding lag fix

tired ore
#

esp in diversity

spiral ermine
#

?

#

uh

#

idk

tired ore
#

damn

spiral ermine
#

I am not educated in the full changes of AIPathfindingLagfix

#

Also 900% sure diversity is borked in v50

tired ore
#

yeah you're probably right

turbid wave
#

That's a lotta percent

spiral ermine
#

there's a lot to break

tired ore
spiral ermine
#

HOLY FUCKING SHIT

tired ore
spiral ermine
#

SUCCESSFULL TEST????

gleaming robin
#

Huh

#

That's unexpected actually

gleaming robin
turbid wave
#

maybe zeekers cooked something into the SetEnemyOutside methods, such that they realize that they need to path inside first?

#

We need to get to the bottom of this. Maybe there's some system that we have overlooked and broken in the process

#

Do note that Mi6k is spawning the bracken outside. It is not a bracken that has left the facility using the mod

#

Maybe the game has hidden support for enemies pathing between the outside and inside? Have you tried to tell an enemy to path outside, without the mod?

#

Or maybe this is code from SnatchingBracken, that has been created to support brackens that have been spawned outside?

gleaming robin
#

I don't see anything in it

turbid wave
spiral ermine
#

And even with Snatchin + AiFix

#

Bracken didnt path inside

#

Or towards the facility

#

rather a corner of the map somewhere

turbid wave
spiral ermine
#

Its only with Snatchin + AIFix + EnemyEscape + Pathfinding fix (maybe) everything worked in that test

turbid wave
#

it's trying to get closer to the real location within the scene

#

well, that's most of my theories on why it happens out the window

turbid wave
#

maybe it's able to use that node?

gleaming robin
#

So at Batby's suggestion I instead made new objects with the OutsideAINode/AINode tag to allow for random pathing to an entrance, but they don't affect actual navmesh

#

Unless I'm incredibly mistaken, there's nothing actually linking inside to outside navmesh-wise here

turbid wave
gleaming robin
#

yea that was initial release

turbid wave
#

i guess maybe it would be worth checking the behavior without those nodes?

#

just to sanity check ourselves, and maybe this will lead to a better solution for everything

gleaming robin
#

next update might not even have them

#

so actually yea I'll test without them

turbid wave
#

also rerun the test with them still. To confirm that this is not something that happens only for Mi6k

gleaming robin
#

@spiral ermine idk if you've used the UnityExplorer mod, but could you do a bracken test with disabling the nodes in the scene?

spiral ermine
#

h uh

gleaming robin
#

Yep

spiral ermine
#

i dont think im qualified for this one chief, you mau have to tell me how to do that

gleaming robin
#

Go to experimentation. In game, F7 will turn the overlay on and off, on the left will be an object window, use the dropdown for switching to Experimentation scene, then use the search bar for EnemyEscape and disable the 4 objects that come up

#

then test the bracken again

spiral ermine
#

ok

gleaming robin
#

also what mod are you using to freecam and spawn and stuff?

#

and visualize pathing

tired ore
#

im pretty sure

gleaming robin
#

noice ty

turbid wave
#

this would have been handy when debugging the path to door code

gleaming robin
#

yea ; w ;

#

@turbid wave I can't believe it, but yea it actually works

#

just checked current release

turbid wave
#

does imperium have tools to manually order pathing?

gleaming robin
#

well I'm not using imperium

turbid wave
#

well if it does have those tools, then we could test without SnatchingBracken. And test on other enemies too

gleaming robin
#

I'm not sure I follow

turbid wave
#

if imperium let's you order an enemy to path somewhere.
We could order a nutcracker to path somewhere on the outside, then back inside

#

and also eliminate the possibility that there is something special about SnatchingBracken that is influecing things

gleaming robin
#

I see

#

alright well it gets weirder

#

without the nodes, the bracken doesn't take me to the experimentation fire exit lmao

gleaming robin
#

Okay so I had a suspicion, and I think @golden basin will love to know that this is just a case of Experimentation being wacky. There's navmesh into the building, so what's happening is that the Bracken is trying to go as far from the main entrance as it possibly can, as per its code, so it goes to the fire exit thinking it'll go through it and follow the navmesh (which it cannot), hence why without a successful teleport roll it just mashes its face against the door

#

So this is just an incredible coincidence @turbid wave

#

@spiral ermine

golden basin
#

It becomes kinda blind

gleaming robin
#

Silly Zeekers

golden basin
#

But it serves experimentation purpose

#

Of an experiment

gleaming robin
#

#ZeekersMoment™️

spiral ermine
#

wacky

#

and wild

gleaming robin
#

however

#

that doesn't explain why it didn't happen without the nodes I placed by the door

#

bc it's not like it adds navmesh

#

idk ; w ;

gleaming robin
turbid wave
gleaming robin
#

I ran it a few times in different spots

turbid wave
#

although it's interesting how Mi6k said that this didn't happen at all when not using the SLEsc

gleaming robin
#

Anyways, since it's an inconsistent event entirely brought on by Zeekers' toying around, I'm not gonna worry about it

turbid wave
#

i think there is a barrier that zeekers put at the door, to prevent things from randomly pathing into that navmesh. And your node somehow allows it to step over the barrier

faint copper
turbid wave
#

shame this this is not a stable feature. If this mod worked like that for every map reliably, it would be perfect

gleaming robin
#

uh, I may have been mistaken regarding the Experimentation navmesh

gleaming robin
#

I was looking at a bad angle, so I thought it was going through the fire exit door, but it's not

#

which means I am once again confused

tired ore
tulip vault
#

you can totally add a big navmeshblocker in that room via super arbitrary code before it does the runtime bake btw

gleaming robin
#

Also found some code that will allow me to calculate the actual distance of the navmesh path between the enemy's position and the entrances, so the value of "range" will be more accurate

var corners = pathToTeleport.corners;
var pathDistance = 0f;

for (int i = 1; i < corners.Length; i++)
{
    pathDistance += Vector3.Distance(corners[i - 1], corners[i]);
}```
faint copper
tired ore
#

i dont think i can describe it in more detail tbh, it might even be some vanilla pathfinding shenanigans. happened on a mansion tileset once is all i can remember

faint copper
#

how long does it stand still?

tired ore
#

dont count on it being 100% reliable cause it happened like some time ago, but at least for the anger duration he was standing there

#

but honestly i dont think that until diversity gets a v50 patch its something worth looking into

faint copper
#

oh, if he was in the anger state then it doesn't affect it at all afaik

#

the patch affects the running away state

#

any side effect would be due to making use of a search coroutine field that bracken wouldn't need for chasing a player because he's all-knowing

tired ore
tulip vault
#

Can’t wait for @gleaming robin to fall too deep in the ai rabbit hole and think about ai teammates

gleaming robin
#

Don't tempt me

#

Someone would need to pay me for that for the amount of time I'd probably put into it

gleaming robin
gleaming robin
#

Okay, Imperium is astounding

spiral ermine
#

hours of bugtesting reduced to mer minutes with how much it does

gleaming robin
#

@patent epoch tysm for Imperium :3

#

being able to SEE the current navpath is an absolute gamechanger for testing this mod ; w ;

spiral ermine
#

Hey

#

off topic question

#

is this mod still a need in v50

gleaming robin
#

¯_(ツ)_/¯

patent epoch
gleaming robin
#

Awesome!

spiral ermine
#

well if Knight doesnt know maybe @faint copper ?

faint copper
#

for the dog thing?

#

I'm not sure

#

I never looked at the dog hitreg issue actually

#

it has always worked to shoot them, it's just not reliable, which makes me think it's just how the colliders are set up

gleaming robin
#

@patent epoch if I may offer one suggestion, when I was invisible enemies could still hear me, so maybe disable any noise from the player while invisible?

patent epoch
gleaming robin
#

ah okay

#

still gotta figure out the blob weirdness lol

patent epoch
gleaming robin
#

yep, but once I set it on its path to the teleport it gets solid :3

patent epoch
#

hmm, interesting

#

I haven't actually used your mod myself yet as I don't play with mods that often

opal bane
#

@gleaming robin
Questions as I am out of the loop.

Does this work on v49?
Will this work for modded enemies?
Will this work for all moons and modded interiors?

spiral ermine
gleaming robin
#

^

opal bane
#

lol thanks team!

gleaming robin
#

:P

opal bane
#

Also. Thank you for allowing me to make Shattered Company even more painful. If people are not pissing or shitting their pants. Have I really done a good enough job?

opal bane
#

How does it work? Does it just attach an AI path node to every door slot?

gleaming robin
#

Current release, kinda

#

Not the best implementation

#

New release (coming soon™️) waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay better

rancid brook
#

Tomorrow at 10pm

opal bane
#

Ohhhh interesting. I like the unexpected Bracken drag haha

spiral ermine
opal bane
#

XD

gleaming robin
#

Powered by something idk

#

I think maybe what it was, was that the node I placed at the fire exit just HAPPENS to be the farthest from the entrance path-wise on Experimentation, so it becomes the bracken's favorite spot

gleaming robin
#

Okay, I keep doing that thing where I change a little bit of code, break something, and then can't figure out what exactly broke, so I've learned my lesson and I've made a backup of the working plugin on my desktop

gleaming robin
#

Current state of things:
When an enemy spawns, all cooldowns are set.
When the pathing cooldown reaches 0 (or less), it rolls the dice on leaving the facility.
If successful, it calculates the path to each teleport, and for any that return valid, it checks the length of the path, and if the path is close enough, it navigates directly to the teleport. (My check for the behaviour state should allow it to break out of this and go after players)

golden basin
#

figured

gleaming robin
#

I just haven't learned how to use it properly

faint copper
#

you don't need to even use GitHub, just use a local git repository blease DORIME

#

I was gonna say that before you had an issue like this but uhh too late now I guess

#

if you make granular changes and commit them to a git repo it makes it WAY easier to tell where you went wrong

#

the granular commits thing being the most important part that a lot of people skip, it's more work but it's absolutely worth it when you have some weird issue and you don't have to sift through 500 lines of code changes to find where you broke things

#

for example, I had someone point out a performance regression in OpenBodyCams, and I was able to bisect down to the exact commit where I broke it and that left me with iirc less than 20 lines to look at

#

vs probably hundreds of lines that I changed in the course of that release that broke things

#

if you ever want help using git, I can give you some tips

#

first tip: use VSCode to stage your changes, its diffing is very good

gleaming robin
#

Ah, I was wondering about the differences between VSCode and VisualStudio

gleaming robin
faint copper
#

oh, I forgor then I guess

#

or maybe I didn't go into depth

faint copper
gleaming robin
#

.

faint copper
#

I run VS for developing my mods, then open VSCode to stage and commit changes

faint copper
rustic plume
#

it will just will follow you out the door

gleaming robin
#

baby steps

opal bane
#

Having this spam in v49

[21:24:17.5263820] [Error : Unity Log] NullReferenceException: Object reference not set to an instance of an object
Stack trace:
StarlancerAIFix.Patches.AIFix.AIUpdatePatch (EnemyAI __instance) (at <ddb6fba65f4f4f1fadedc0d7e02023e4>:IL_006F)
(wrapper dynamic-method) EnemyAI.DMDEnemyAI::DoAIInterval(EnemyAI)
MaskedPlayerEnemy.DoAIInterval () (at <af9b1eec498a45aebd42601d6ab85015>:IL_0000)
(wrapper dynamic-method) EnemyAI.DMDEnemyAI::Update(EnemyAI)
(wrapper dynamic-method) MaskedPlayerEnemy.DMDMaskedPlayerEnemy::Update(MaskedPlayerEnemy)

#

[21:27:35.6559542] [Error : Unity Log] MissingMethodException: Method not found: void .EnemyAI.SetEnemyOutside(bool)
Stack trace:

faint copper
#

looks like you're trying to run it on v49 there

#

presumably you should downgrade to a previous version that was intended for v49

gilded zealot
opal bane
opal bane
faint copper
#

that definitely would, it won't work on v49 without a backport

gleaming robin
#

In theory the new AIFix should still be v49 compatible, but I'd just look at the version release dates.

I can say nothing for EnemyEscape v49 compatibility :P

gleaming robin
golden basin
gleaming robin
#

Hopefully it's just special characters in its name, the next update should account for that

rustic plume
#

the only monster that actually escapes (the most chance) is thumper (in enemy escape)

#

and its not like lethal escape that it leaves automatically without chances

gleaming robin
#

dude chill

#

I have a massive update coming

rustic plume
#

i'm saying a feedback

gleaming robin
#

the way it was phrased was like a demand

rustic plume
#

not a demand

#

but ok

#

just a feedback

faint copper
gleaming robin
#

...

#

u right

#

Forgot I changed that lol

faint copper
#

Saved I thought we had a conundrum on our hands

#

it's good that you're using that though

gleaming robin
#

yea, I did it for you lol

#

@faint copper any idea why I can't reference a public static variable from LC's assembly?

faint copper
#

huh, which one?

#

that does seem odd

gleaming robin
#

BaboonBirdAI.baboonCampPosition

faint copper
#

ew why is that static

gleaming robin
#

idk but I can't access it

faint copper
#

you definitely should be able to access that though

#

show code with error?

gleaming robin
#

...nvm suddenly I can access it

faint copper
#

ope

gleaming robin
#

wait

#

wth is going on

#

it disappeared xD

#

Okay I thought I understood how this particular aspect of coding worked but apparently not

faint copper
#

hmm? wdym?

#

you set it in the line above the one you're typing

#

you can't access static fields by going through an instance in C#

gleaming robin
#

ohhhhhh okay

faint copper
#

Java lets you do that but C# doesn't lol

gleaming robin
#

ugh

#

well I wanted to make it so that a new camp position got created on warp (which I would cache inside/outside)

#

wait

#

nvm, I had the thought about moving the static but then that'd mess things up if some were in and some were out

#

I'm not sure of the solution here 🤔

faint copper
#

well

#

their nest is a physical object as I understand it, so spawning one in the interior would get a little screwy, but if you really wanted to you probably could

#

then you'd have to do a bit of transpiling to make them use your inside nest location instead of the outdoor one

#

or you could instead make a transpiler to make them path to the exit when they're inside and trying to go to the nest

autumn panther
#

silly giant spikes with the head on them

faint copper
#

that way they can actually make it out

gleaming robin
faint copper
#

it takes some learning

#

for this it shouldn't be super involved but you still need to know the basics of how stack machines work

#

and read documentation of the IL instructions in the functions you're interested in

gleaming robin
#

Well before I worry about that, this is all that the nest object is for the baboon hawks

#

so it only serves as a home base if that makes any difference

#

man, this is irrelevant, nvm

#

a nest only even gets spawned if there are 3 hawks

faint copper
#

I think it would feel kinda odd if they had an invisible nest in the interior and just ignored their outdoor one

gleaming robin
#

I'm not pursuing this any longer bc my understanding of its purpose has changed, but my original idea was: If a baboon hawk warps inside, it picks a node inside to act as its camp, if it warps outside, it uses the original camp position

#

the issue I'm running into is that if a baboon hawk picks up scrap inside, it glitches out and gets stuck in place pretty much

#

but only if it was originally outside I think, unless I just fixed it

faint copper
#

looking at their code, it seems like as soon as they pick up scrap they try to directly path to the nest, so that makes sense

#

if you inject a call to your own function to replace that destination with the exit if they're inside, then they should not get stuck

#

it's the easier solution than replacing the nest location when inside, and it would make more sense to players for them to take the scrap to the visible nest prefab than some arbitrary point inside

gleaming robin
faint copper
#

admittedly I don't know which behavior belongs to the one where they are trying to drop off scrap, but I believe it's under case 1 of the switch in DoAIInterval()

gleaming robin
#

lmao I really did just miss that

gleaming robin
faint copper
#

prefix which?

gleaming robin
#

the DoAIInterval

#

I wouldn't actually randomly pick a spot every interval tho

faint copper
#

if you prefix DoAIInterval your destination would instantly get overridden

gleaming robin
#

ahhh right

faint copper
#

you could technically postfix it but that's kinda ugly

gleaming robin
#

wait

faint copper
#

don't say it

#

prefix returning false is bad ...

gleaming robin
#

the position of baboonCampPosition is set on start() tho

#

nonono lol

faint copper
#

oh good

#

wait you wanted to do this in Start()?

gleaming robin
#

no

faint copper
#

ok then I don't know where you were going with that

#

oh wait, were you saying you'd overwrite the nest position at the start DoAIInterval and then reset it after?

#

then you'd probably have the baboons drop the items at the door

gleaming robin
#

My thinking was that while it's inside, the DAII would refresh the position each call, and if outside replace it with a cached original, but looking at it now that would fall apart if the hawk starts inside

#

so I need something to just reassign the nest position after warping, that adapts to whether the hawk spawned inside or outside

faint copper
#

reassigning it isn't a good idea

#

you gotta look at all the references to that field

#

it checks the distance to the nest to determine whether to drop items among other things

gleaming robin
#

ah

#

so the solution is to change the destination while an item is held instead

#

which would be, take the item to the exit, leave and bring it to camp

#

prefixing DAII won't work, postfixing is ugly, idk how to transpile, so I might have to postfix

#

but I've also thought of a niche case that my mods enable

faint copper
#

you need to inject into DoAIInterval to modify what it sends to SetDestination

#

if the baboon is holding the item and the destination is the door, it'll drop it at the door

gleaming robin
#

it only drops the item if its within x units of the camp

faint copper
#

modifying it in postfix might work, but that means you have to integrate every existing condition in the postfix to make sure you don't overwrite the destination at the wrong time and make it do weird things

#

which is why I'd recommend trying to learn to make a transpiler for it

#

it's really not that bad a way to start with transpilers, this isn't a difficult one like other ones I've looked at

gleaming robin
#

should I just peep the harmony docs, or do you have a better resource/wanna teach me yourself?

faint copper
#

I think the best approach would be to take a look at others' transpilers

#

she uses MonoMod's ILManipulator which is easier to use, but there's also CodeMatcher in HarmonyX which doesn't require the patcher

#

basically though, you just need to look at ILSpy in with the IL view (probably want the combined IL and C# view to make it easier to understand)

#

that way you can figure out what instructions line up with the function call you want to hook into

#

if you hover over each instruction it has a little explanation of what it does

#

you can start by making your transpiler/ILManipulator do nothing and just check if you can match the instruction you want

#

(I'm playing a game rn so I'll try to get some resources later if you'd like to pursue it, I mostly just got started with pre-existing knowledge and experimentation)

gleaming robin
#

oh I've been using IL with c# for debugging lately lol

gleaming robin
faint copper
#

depending on how you're matching the code, but yeah, generally I would just print it out to verify it

#

from what I saw, CodeMatcher lets you print an error if it fails to find a position

rustic plume
#

welp, when is the enemyescape mod updating

faint copper
#

ILCursor should work with the latest BepInEx through the HarmonyILManipulator annotation like in the code here, but as you can also see in that linked issue, it will have issues if there's a transpiler and a manipulator on the same function when using the version of BepInEx on Thunderstore

#

I write mine pretty manually with some utility functions so I wouldn't recommend my own code as a reference for this

gleaming robin
gleaming robin
#

@faint copper I figured out the issue with the blob I think. It can't climb or jump, so on experimentation when it left (which was where the screenshots were taken) all of the AI nodes are past the ladders, which only have jump and climb links 🤭

#

So I think that's why its blobby body didn't want to cooperate

faint copper
#

oh, you mean it wouldn't path anywhere? or was it an issue with its edges?

gleaming robin
#

it wouldn't path, which I think prevented it from gathering itself properly

faint copper
#

ohh, I see

#

interesting

gleaming robin
#

I tested it on March and it came right out of the door

turbid wave
#

The underlying issue is that the baboon hawk being inside tried to pathfind to the nest, which is on the outside navmesh

#

The same issue would be valid for snatching bracken. When trying to pathfind to the favorite room with a body snatched outside

#

We can describe those issues as an enemy trying to pathfind to a location on the other navmesh.
Inside to outside. And outside to inside

#

Maybe it could be caught after the base class enemyAI tried to navigate somewhere and failed.
Then we just compare the height of the AI agent and that of the destination.

#

If this comparison gives us a high difference in height we can determine that the enemy has failed to find a path to the other domain

#

Then from this we can call a function of yours to let your code handle returning to the original domain

#

Something like AIwantsOutside
AIwantsInside

#

Those functions would skip the cooldown and random chance code. And force cause the AI to escape / return

#

Idk how this is handled in code. But maybe it could also capture the failed destination and attempt to restore that destination pathfinding after the enemy has made it to the correct domain

#

If this works it would solve the problem for every enemy. Future vanilla enemies, and custom modded enemies alike.

#

Also it would make it possible to create a modded enemy that pathfinds between outside and inside destinations, as a part of its mechanic.

#

Such a mod would only need to depend on this mod, and set the destination from the other domain. Then let this mod handle transferring to the other domain

spiral ermine
#

Oh yea

#

@gleaming robin

#

Reguarding your music mod

#

first couple times you turn on the boombox there is slight stuttering

faint copper
#

this could be a hook in SetDestination, if that's the only point at which enemies set a destination outside their current domain

spiral ermine
#

Also wow how deep have yall been studying the transitioning of pathfinding

faint copper
#

I would tend to say the best way to check that would be what Audio Knight is already doing, checking distance to each node, but it would be good to profile the cost

#

if it's too bad there are shortcuts

gleaming robin
spiral ermine
gleaming robin
#

🤭

spiral ermine
#

I feel ya

#

accidental scientific discovery

gleaming robin
#

Also I'll give a proper look in a bit at what all you've sent @turbid wave . I also need to figure out how to deal with the bracken not wanting to leave its spot and a weird issue with the spider that I don't know how to describe

turbid wave
#

Take your time.

gleaming robin
#

Also I think I'm gonna put manticoils and circuit bees on the "ignore" list for the mod, they don't roam normally like other enemies

twilit drift
#

and sometimes they wander after players 🤭🤭

#

and you can hide inside to get rid of them 🤭🤭🤭

gleaming robin
reef salmon
#

are the chances in the config change to teleport outside or chance to wander to the door?

gleaming robin
#

Currently chance to teleport

#

future - chance to go to door and teleport

gleaming robin
#

@faint copper @tulip vault

golden basin
#

Ooo

#

Wait hold on what's inside that folder

#

This looks suspiciously close to the folder that contains dll and assets

gleaming robin
#

I've entered the bronze age

gleaming robin
golden basin
#

Open it :3

gleaming robin
golden basin
#

Oh wow so actually did do it right

gleaming robin
#

yep, and bin/obj/editorconfig are in the gitignore

golden basin
#

You git ignored game stuff too right?

#

Like assembly csharp

gleaming robin
#

my coding is separate from unity

twilit drift
gleaming robin
#

but yea

golden basin
#

Is it a public repository?

gleaming robin
#

the entirety of the referenced dlls and stuff are ignored

gleaming robin
#

and I'll pull out the plugin dll once I plan to push

golden basin
#

Gotcha

gleaming robin
twilit drift
#

i saw the timestamped folders and went "nuh-uh"

#

why are you tormenting yourself

gleaming robin
#

lazy

#

but in the way that makes more work

twilit drift
#

like literally it's that easy

#

🥺

gleaming robin
twilit drift
#

dum-dum

gleaming robin
#

ye

twilit drift
#

no lazy 😦

#

i remember the time i've used github only to get the sweet education edition perks

#

and there my entire project went missing

#

and i'm using git lol

gleaming robin
#

I'm using github desktop cuz it was easy to setup

twilit drift
#

i was about to recommend it to you 😅

#

cause it it easier than cli

gleaming robin
#

yee, easy integration to the repo was the main thing

twilit drift
#

it's good for the simple stuff

#

but when you need to do anything advanced you're out of luck

#

but adding commits, changing branches and reverting stuff is trivial

gleaming robin
#

okay wow

#

joke's on y'all

#

I made a mistake and github desktop deleted my plugin file, BUT GUESS WHO SAVED HIS DLL AND PDB LAST NIGHT

faint copper
faint copper
#

I hope GitHub desktop warns you when you're about to discard a bunch of changes

gleaming robin
#

I pushed a branch as a test and then deleted that branch, not realizing that it would remove it from my local repo as well

twilit drift
#

welcome to git

gleaming robin
#

sooo kinda freaking out a bit

faint copper
#

unless Git desktop is stupid or something

gleaming robin
#

it's not there is all I know

faint copper
#

is your remote GitHub?

gleaming robin
#

yea

#

wait

faint copper
#

you can use git reflog to get back your branch

#

as long as the changes were committed anyway

gleaming robin
#

oh wait I didn't delete my old local non-git, I swear I couldn't find it before

#

ughhhhhhhhhhhhhhh thank god

faint copper
#

you mean your old backups?

gleaming robin
#

literally just what I had last night before I shut down

#

so everything is fine (?)

faint copper
#

if you ever have this kind of thing happen again, as long as you didn't discard uncommitted changes, you can recover

#

run git reflog in your terminal and you'll see every change you've made

#

when you find the commit you lost in there, you can just do git checkout [hash] and you'll have a detached head of the changes at the point where you committed

#

then you can git checkout -b [branch name] to create a branch from it

#

with this power you can mess around with git without fear

gleaming robin
#

oh sweet

turbid wave
#

git makes it really difficult to accidentally lose progress. If you know how to use it you can almost always recover

gleaming robin
#

phew

turbid wave
#

It's almost an issue, when you end up pushing some confidential password into the internet. And you need it to disappear. But git won't let you remove it form history

gleaming robin
#

To prevent this from happening in the future, should what I do be work on stuff saved in a separate folder and just put stuff in my git when I want to do some version control?

faint copper
#

oh also if you want to restore your changes onto an existing branch, you'd do

  • git reflog, find commit hash that you lost
  • git checkout [branch to restore to]
  • git reset --hard [hash]
    this is obviously a little "dangerous" because you're overwriting that branch completely, but if you know what you're doing with it it's totally fine and useful
faint copper
#

git is your safety net not some random folder

#

just commit often

#

and be careful with the discard changes button like mrov mentioned

gleaming robin
#

mmk

faint copper
#

using git to look over your changes before you commit them is also a very good habit to have so that you can make sure you didn't miss something

#

reviewing your own code isn't nearly as effective as someone else doing it, but you will still catch plenty of bugs that way

turbid wave
#

the discard changes is like reloading a checkpoint in a game. It returns you to the state of your last commit.

#

So committing often, is similar to saving often

twilit drift
#

yeah

#

the default screen shows the changes from the last commit

turbid wave
#

except here you give each commit a short description of what you changed.

faint copper
#

(preferably making each commit one granular change that compiles and ideally runs without breaking anything)

turbid wave
#

so that you can then look at the history of savepoints, and see what changes in each savepoint

twilit drift
faint copper
#

indeed

twilit drift
#

because less files affected each commit == easier manipulating later

faint copper
#

bisecting for bugs is much easier that way too

#

if you have half your commits not compiling or running it becomes very difficult

#

oh also @gleaming robin prefer stashing over discarding if you want to be safe

gleaming robin
faint copper
#

you can always discard your stashes later

#

np!

gleaming robin
#

once I seriously clean this mess up, I'll happily share the source repo

faint copper
gleaming robin
#

tempting to follow up on what Batby told me and make public fields into properties, but I haven't really done get/set stuff (nor do I know exactly when to use them)

turbid wave
#

Imo, if you don't know why you should be using something, then don't use it.

#

Just leads to misusing the thing, and to a worse overall situation

faint copper
#

I would only worry about that for things that you expect other mods to need to use that you may need to react to changes to

#

and generally you could prefer internal over public if you don't want something to be treated as public API

turbid wave
#

If you're pushed into using something, then research why it would be a good idea first before committing to it

gleaming robin
faint copper
#

hmm, which fields were you thinking needed to be properties then?

gleaming robin
#

well that's just it, I'm not really expecting other mods to do things to EnemyEscape so idk

faint copper
#

oh, then don't do it

gleaming robin
#

Despite my ambitions, my serious coding only starting in January lol

#

before then I had only taken 1 java class 10+ years ago and a python class like 8 years ago

turbid wave
turbid wave
gleaming robin
#

ah not yet, I was too busy freaking out about my git stupidity 🤭 I'll check it out now

#

The main difficulty is calculating the fact that the desired position is on the other half of the level. Height is sort of okay, but without re-implementing the calculations I did away with in previous versions of AIFix, I'd have to use a "magic number" to set a division height.
I think for the short term I might patch the BaboonHawk to just not pick up items while inside
I'm not sure what do about the bracken tho, bc its DoAIInterval tells it to path to its favorite spot while passive, so my component can't effectively override that

#

@faint copper I know that I should generally avoid prefixing, but when would you say prefixing is okay?

#

bc in theory I could prefix the hawks InteractWithScrap() method to just say if (!isOutside) { return; }

#

(as a temp measure until I figure out how to get it back to its original location)

turbid wave
gleaming robin
turbid wave
#

But Batby said that this also breaks assumptions that LLL is making, so i guess it would be save to pick such a "magic number".
Maybe you could even soft dep on LLL to get that "magic number" dynamically

gleaming robin
#

and yea the Spacestation was what lead to me making AIFix more accurate, so that above-exterior dungeons would still function with it

#

Alright I'm taking matters into my own hands

[HarmonyPatch(typeof(BaboonBirdAI), "Start")]
[HarmonyPrefix]
[HarmonyPriority(1000000)]

private static void takeCareOfThoseLittleBastards(EnemyAI __instance)
{
    __instance.KillEnemy();
}```
turbid wave
# gleaming robin and yea the Spacestation was what lead to me making AIFix more accurate, so that...

Just thought of another way to distinguish which domain the location is in.
I'm assuming that the interior navmesh and exterior navmesh can be easily differentiated by their reference.
You could calculate their bounds after scene loads. The highest and lowest value for each axis, that is still within that navmesh.
Then you only check if the location is within bounds of one navmesh or the other. No magic numbers included.

gleaming robin
#

The exterior navmesh gets rebaked at runtime, so I think all the navmesh in the scene falls under one reference unfortunately

turbid wave
#

Or you could use the bounds of the interior directly, i recall those were mentioned in the Mimics thread

gleaming robin
#

Hm... I wonder if postfixing DoAIInterval() with if (current path is unreachable) { drop held item and sync } would work

faint copper
faint copper
#

the magic number is -80f

gleaming robin
#

Nothing to do with the destination, just prevents them from picking up scrap. The idea would be fruitless though

faint copper
#

that does sound like a way to discover whatever other ways that the AI wants to break lol

#

I think dungen calculates a bounding box for the interior, but I'm not sure

#

I personally haven't had a reason to use it so I wouldn't necessarily trust it

#

I think the options are:

  • magic number
  • find closest node among both sets
turbid wave
faint copper
#

to both things, unless LLL starts patching the vanilla checks, there's no reason to behave differently

#

LC_Office extending too far up is an issue with the interior that Batby seeks to fix eventually by shifting the dungeon root after generation

#

at least as far as I know

turbid wave
#

future proofing, sure

faint copper
#

that will also make Space Station conform, to its detriment, but there will have to be a lot more work to make something like that function the way it should

#

perhaps work that only Zeekers can do

#

which means I don't really see it happening without some trickery to make those assumptions still true

turbid wave
gleaming robin
#

star wanted to support those interiors with the aifix

it was more that Spacestation gave me a push to do what I needed to do anyway

turbid wave
#

the interior bounding box could be a way to determine the domain, without dropping support for interiors above -80f

#

But that would depend on authors of custom interiors correctly setting those up. I could see that happening, if those bounding boxes started causing errors.

#

or if all else fails, maybe differentiating the navmeshes would be a feature for LLL to handle after loading the scene.

faint copper
#

the tiles themselves have bounds that are calculated based on their transforms, you can just take the union of those

#

but if we're trying to account for moon/interior authors doing screwy things, then I think the only solution is to scan all the AI nodes

#

unless the NavMeshAgents have some way of indicating what object they're on

turbid wave
faint copper
#

AI nodes != navmesh

turbid wave
#

oh you mean start the scan on the root, and walk all the connected nodes?

faint copper
#

no, I mean the waypoints that Zeekers and mod authors create

gleaming robin
#

also @faint copper I just tested in Lan and I think you'll be happy to hear that the special nodes I instantiate do indeed register for both host and client

faint copper
#

nice that's good

#

pretty much what I did for AIFix initially was for each ainode just log the max and min of inside vs outside and find a midpoint between the two to act as the divider
I thought you had some code at some point that found the closest AI node to an enemy to determine which they were on?

#

that's what I'm suggesting here, although it's obviously not the most efficient method

#

I would honestly just suggest that you make the same assumption vanilla does

turbid wave
#

you know, the easiest way to do all of this would be to place offmeshlink's for the entrance teleports.
Enemies don't need to actually walk through the links. But those would allow the agent to realize the best path, including the domain transfer.
Then we just need to detect the attempt at using the link, and handle the TP.

celest isle
#

going through your configs and found enemies i havent heard of who is maggie? and whats the crystal ray?

turbid wave
celest isle
#

damn was hoping i found new enemies

#

should i still use fair ai if im using starlancers ai fix?

turbid wave
faint copper
turbid wave
#

also, I'm not sure how possible it would be to place those links for modded moons / interiors

turbid wave
faint copper
#

was something wrong with that method?

gleaming robin
#

with the max/min?

#

also @faint copper with transpiling, I can alter specific lines of code yes? So if I transpiled the Bracken's AI interval, I could have it check for my own condition and tell it do or do not do what it was originally going to do?

faint copper
#

indeed

gleaming robin
#

alright time to become transpile-pilled

#

there's really no other way to fix these inconsistencies lol

faint copper
faint copper
#

which thing are you looking at with Brackens?

gleaming robin
gleaming robin
faint copper
#

looks like it's using SetDestinationToPosition there to me

#

why not inject into there like Piotr suggested?

gleaming robin
#

so if (pathingToTeleport) change that line to the teleport location?

faint copper
gleaming robin
#

I could (in the same function) node.transform.position and store it in a separate array

faint copper
turbid wave
turbid wave
gleaming robin
faint copper
#

it would certainly be the ideal solution if it's possible to set up at runtime

turbid wave
#

this chance of escaping seems to be messing with the intended behavior of enemies.
And using OffMeshLinks would allow the enemy behavior to have proper control of the situation. But then we lose the ability to config the chances

gleaming robin
#

However, that sheer freedom might be what people would prefer

turbid wave
#

Hmm, if we could determine between the enemy randomly wandering and actually pathing to a specific destination.

#

during random wander we could roll the chance and on the result disable the link, so that the enemy doesn't have that option during random wander.
But when pathing with intent, we leave the link enabled, and it finds the route correctly

#

Just set this bool to false, when enemy state is idle, and it didn't make the last dice roll it did.
Set it back to true as soon as it is done pathfinding. To let other enemies use it separately.

#

This would require a transpile on the EnemyAI class, before and after calling SetDestination()

#

and an assumption that state idle is a good way to determine random walk

faint copper
#

we'd need a way for each agent to have its own link then

#

agent pathfinding is done asynchronously

gleaming robin
#

I'm trying to cook up a dumb idea

#

Can someone tell me what layer NavigationSurface is on?

#

I don't wanna open unity lol

faint copper
#

UnityExplorer can tell you too

turbid wave
faint copper
#

I would assume

gleaming robin
#

oh maybe

#

nope, just has the name

turbid wave
#

wait how does the random wandering code work for LC enemies?
can it even consider a location for SetDestination that is through an OffMeshLink?
or is that something that would have to happen when another situation is causing it to consider that location

faint copper
#

the Unity documentation specifically says that it runs pathfinding async from what I remember

faint copper
#

with that we would be limited to 32 enemies

turbid wave
#

ah

#

kinda sounds like enough, but alright

turbid wave
#

this isn't about using a different area bit for every enemy.
Each enemy has it's own area mask, that we could set one bit in to tell the agent if that enemy is allowed to consider the link for this SetDestination call

#

it would be a prefix on SetDestination, that checks if enemy state is idle, and checks the result of last roll of the dice to disable the mask bit.
else enable the mask bit.

#

and re-roll the dice every cooldown

#

hmm, but if the random wandering code is capable of choosing locations through that link, it could still pick that location. And disabling it last minute would make it temporarily unable to find path

short lagoon
#

So with this mod you can configure what goes in and what goes out?

turbid wave
#

yeah, there are chances in the config, and if you set it to 0 it will never attempt

short lagoon
#

Nice

short lagoon
#

You can do this for specific monsters?

faint copper
#

I was still thinking about duplicate links

short lagoon
#

Like if you want just dogs to go in and out

gleaming robin
short lagoon
#

Oh nice

turbid wave
#

I know nothing about how enemies pick locations to wander to. Is there a method that they call to figure out where they could move?
Prefixing a method like that would be even better, since it won't affect pathing attempts to a deliberate location.
And it would prevent them from considering a location before they even try to go there

short lagoon
#

And this is host only?

gleaming robin
#

Honestly not sure! 🤭

short lagoon
#

Thats so real

short lagoon
#

But fr though I’d assume so

#

Its just enemies going in and out

turbid wave
gleaming robin
#

ooh I might've found it actually, gonna test again

turbid wave
#

So that test is something that you should make a branch for in your git repo

#

but i doubt you'd want to deal with it

gleaming robin
#

The test would really just be to see if it could work, but I think the method I have going already is a little more controllable

#

And rather than spending more time on the OML attempt, I'm gonna get back to the working code :P

#

But I appreciate the idea!

turbid wave
gleaming robin
#

@faint copper is CodeMatcher something I have access to natively in my current setup, or do I need to install something? And I'm guessing the lethal wiki link you sent me would require me to use depend on MMHOOK?

turbid wave
gleaming robin
twilit drift
#

haaaaave you imported HarmonyLib (using HarmonyLib;)?

gleaming robin
#

ye

twilit drift
#

umm

#

this is my code:

using System.Collections.Generic;
using System.Reflection.Emit;
using HarmonyLib;

[HarmonyTranspiler]
    [HarmonyPatch]
static IEnumerable<CodeInstruction> PatchPatch(IEnumerable<CodeInstruction> instructions)
    {
      CodeMatcher codeMatcher = new CodeMatcher(instructions);

...

return codeMatcher.InstructionEnumeration();
    }
#

and it's working 🤔

gleaming robin
#

¯_(ツ)_/¯

rustic plume
#

is it gonna update today

#

🙂

rustic plume
#

tested it

short lagoon
#

Nice

faint copper
#

if CodeMatcher isn't there, perhaps the BepInEx versions you have differ?

gleaming robin
twilit drift
#

How's your Harmony defined in .csproj?

#

I'm using

        <PackageReference Include="Lib.Harmony" Version="2.2.2" />

from nuget

#

which i don't know if it's bad or not but it works 😆

gleaming robin
#

I'm not using a package reference, I was referencing the included 0Harmony.dll

gleaming robin
gleaming robin
#

lemme try just doing a ref like that

gleaming robin
#

@faint copper it was all @twilit drift's fault

gleaming robin
#

using Lib.Harmony 2.3.3 instead fixed it

twilit drift
#

throwing me under the bus lol

gleaming robin
#

I still have to, y'know, learn how to transpile something, but it's a start

golden basin
#

We have good docs

#

In the lethal wiki

twilit drift
#

😳

#

the preacher

#

the converter

faint copper
#

the docs certainly are nice

#

and being able to use it without the patcher is nice (if BepInEx updates there'll even be no downside!)

gleaming robin
golden basin
gleaming robin
#

Zaggy just said

and being able to use it without the patcher is nice (if BepInEx updates there'll even be no downside!)
😭

golden basin
#

Plus it'll get better as time goes on, hamuniis cooking stuff up to make it better

golden basin
#

Whoops * doesn't work when multiple

gleaming robin
#

lmao

#

Well if MM is significantly easier as the wiki suggests, I haven't really gotten started on the Harmony transpiling so maybe I'll just do MM instead and add hookgenpatcher as a dependency

#

I would need it as a dependency yeah?

tulip vault
#

#1203485438497787954 & #1204237353670148137 might be worth reading @gleaming robin

#

xilo running me through my first couple transpilers step by step with little to no offtopic talk

gleaming robin
#

oh cool

#

except I'm being pulled towards two transpile methods and I have no idea which would be better for me 🤭

tulip vault
#

im always team harmony but

gleaming robin
tulip vault
#

for transpilers i don't really have a case

#

other than vibes 😛

gleaming robin
#

@_@

#

@golden basin make your case against Harmony

golden basin
#

Less intuitive by a long shot

#

Plus I can autocomplete what I'm looking for in patches with intellisense and it'll auto make the method including parameters

#

So as long as I know what I want it'll set it up for me in a couple seconds

#

Also we really do just have a lot more docs for monomod here

#

Like we have a lot hamunii made lol

gleaming robin
#

oh neat

#

Sorry @tulip vault, looks like I'll be Monomod-pilled (at least for transpiling)

golden basin
#

All the docs are in lethal.wiki

gleaming robin
#

mmk, time to figure out how to actually set the patch up :P

gleaming robin
#

welp I'm already confused, I just wanted to copy over an example from the page so I could just see how it looked, and I don't know if these packages are actually required or if I've done something wrong before even starting

rustic plume
#

not to be a skid, but instead, use ai to find errors in ur code and correct it for you

gleaming robin
#

Because I'm trying to learn it somewhat on my own first. I don't mind nudges (or in this case just an answer to if these packages are what I'm actually looking for), but I don't want to just be outright given the code

golden basin
#

Don't you just need to reference MMHOOK assemblies?

gleaming robin
#

ahhhh that'd be where I'm going wrong probably xD

faint copper
#

the downside is that if you do that to the same method as a HarmonyTranspiler function did, then it'll fail

gleaming robin
#

ahh okay

#

so safer to just use monomod in a general sense
though it probably wouldn't matter for this particular case since who else would modify the hawk returning to camp with scrap 🤭

golden basin
#

Me for my next mod

#

/s

copper yew
gleaming robin
#

Well I have the example mostly working except it says this variable doesn't exist. It's a private variable, but I thought since it was in the tutorial it was somehow exposed due to MMHook or something

copper yew
#

that still refers to the game's assemblies itself

#

so you'd want to publicize that

gleaming robin
#

hmm, okay

#

Is that a method related to mmhook or am I needing a different using?

copper yew
#

playerSlidingTimer is a private field in zeeker's code itself

#

have you publicized the assembly before? if not, add this:

<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.1" PrivateAssets="all" />
gleaming robin
#

ah, never have lol

copper yew
#

yeah that's why then

gleaming robin
#

didn't know that was a thing

copper yew
#

and for the LC package reference, make sure it has Publicize="true"

<PackageReference Include="LethalCompany.GameLibs.Steam" Version="50.0.1-ngd.0" Publicize="true" />
gleaming robin
copper yew
#

inside your .csproj

gleaming robin
#

nah I know where to put them (or in the nuget package manager which is what I'm doing)

#

I just thought maybe I should have already been having them

copper yew
#

ohhh thats what you meant

#

are you using a local copy or something?

#

it's a package from lordfirespeed

#

(which imo you should be relying on nuget packages when possible anyways)

gleaming robin
#

ahhh okay

#

yea no one ever told me about nuget lol

copper yew
#

i guess thats something the wiki should ideally mention

gleaming robin
#

it probably does and I just didn't see it

copper yew
#

:D

tulip vault
#

yeee stuff like this is gonna make all the little dev workflow cracks pop up

#

can be overwelming to look into them all at once but their all pretty tame

gleaming robin
#

Seems it broke something else tho @copper yew

copper yew
#

what the, how's that even possible 🤔

#

is your repo open source

#

i wanna take a look

gleaming robin
#

not yet lol, I haven't gotten it to a state worth publishing

copper yew
#

ah

#

im genuinely not even sure how that could break

gleaming robin
#

idk, it threw some little warning icons on some of my manual refs which seemed related to the packages I installed so I thought they were duplicates, but I can't see how it'd break a System thing

tulip vault
#

do you have a namespace the same name as your class?

#

only thing i could think of

gleaming robin
#

I checked and I did, but changing it didn't fix the error

tulip vault
#

it might still be lurking in your usings up the top?

gleaming robin
#

it was just in my transpiler cs I had created to do transpiling things

#

even if I comment out everything in my other cs's the issue persists

#

I am so confused

gleaming robin
#

I love wikipedia, I love knowing why something is called what it is

#

st = store makes a ton of these make immediate sense

#

ld = load

#

conv = convert (a bit more obvious, but still)

copper yew
#

IL shenanigans 😭

gleaming robin
#

me using the cmd prompt to open a second instance of ILSpy:

gleaming robin
#

I'm heading to bed, but @faint copper I guess I managed to get the code transpiled in the right place. It didn't really do what I needed it to, but it didn't throw a bunch of errors at me at least.

copper yew
gleaming robin
#

It's fine, I'm on version control now :P

faint copper
#

if you want me to have a look at the code or generated IL I could let you know if I see anything weird

gleaming robin
faint copper
#

oh, I didn't mean the IL of your IL manipulator

#

I meant the IL that it generates

#

I'm not sure what that pop is for, you probably are calling a function above that that returns something that you're ignoring

#

(probably an ILCursor function that is supposed to allow chaining?)

gleaming robin
#

uh

sterile echo
#

@gleaming robin I let you out of jail

gleaming robin
#

ty

#

what did it not like? xD

sterile echo
#

Your code had an unfortunate run of letters that spelled out a naughty word with a dot in it

gleaming robin
#

ohhhhhhhh

#

I see

sterile echo
#
private static void HawkScrapDestinationChanger(ILContext il)
{
    IL.BaboonBirdAI.DoAIInterval += HawkScrapDestinationChanger;
    ILCursor c = new(il);
    c.GotoNext(
        x => x.MatchLdarg(0),
        x => x.MatchLdcI4(0),
        x => x.MatchCall<EnemyAI>(nameof(EnemyAI.SetDestinationToPosition))
        );
    c.Emit(OpCodes.Ldarg_0);
    c.EmitDelegate<Action<BaboonBirdAI>>((self) =>
    {
        logger.LogWarning("Baboon hawk is trying to carry scrap back to the nest!");

        var pathToTeleport = new NavMeshPath();

        foreach (EntranceTeleport teleport in StarlancerEscapeComponent.entranceTeleports)
        {
            NavMesh.CalculatePath(self.transform.position, teleport.entrancePoint.transform.position, self.agent.areaMask, pathToTeleport); //Check for a valid path to this entrance.

            if (pathToTeleport.status == NavMeshPathStatus.PathComplete)
            {
                self.SetDestinationToPosition(teleport.transform.position);
                break;
            }

        }
    });
}```
#

I'll just send it for you

gleaming robin
#

Thanks! And thank you for freedom :3

faint copper
#

wait, are you supposed to be registering your manipulator inside there?

gleaming robin
#

probably not

#

xD

#

That would make sense as to why nothing really happens I suppose

faint copper
#

yeah that needs to be called somewhere else I would imagine

#

I don't use MonoMod though so I couldn't say for sure

gleaming robin
#

I'm pretty sure you're right

#

I was just rushing to get the tutorial code to not throw an error at me and that worked :P

#

I think I need to register it on enemy start?

faint copper
#

nono

#

it only needs to be registered once

#

when the game starts up

gleaming robin
#

Oh, so I could just run it alongside all my registering of enemies then?

faint copper
#

(I should say, I don't know when it needs to be registered but it definitely only needs to be done once)

#

that would probably work

gleaming robin
#

Fair lol

#

My other thought is on my plugin awake()

faint copper
#

I'm sure the normal way to do it would be during Plugin.Awake() like for Harmony patches

gleaming robin
#

🥷

faint copper
#

I forget if you answered this before, but is there a reason why you're not trying to patch this in SetDestinationToPosition()?

#

just because you don't trust the ways you've used to detect which navmesh a position is on?

#

one other potential option that I don't think was mentioned is to check that there is no direct path, then test a path from the exit point of an EntranceTeleport from wherever the enemy currently resides, and if that path is valid, send the enemy to that EntranceTeleport

#

not the most efficient way probably, since testing paths isn't super fast, but it's at least foolproof I think

gleaming robin
gleaming robin
gleaming robin
#

@faint copper okay, I'm actually glad to get an error bc that means my code is trying to do something at least

#

That's on attempting to register it on GameNetworkManager.Start()

faint copper
#

hmm, are you using .NET Standard 2.1? you should put your pdb in the mod folder so you can actually get line numbers if so

faint copper
gleaming robin
#

is that not what my foreach is doing?

#

oh I see what you mean

#

a valid path to the original destination?

faint copper
#

by direct path I mean a path from the agent's position to the destination that was passed to SetDestinationToPosition

#

from what I can tell from above, it looks like you're just making them drop items at the entrance regardless of whether they can go to the nest

gleaming robin
#

gotcha gotcha

#

well for now I'm just trying to successfully override their behavior

faint copper
#

also, why check all entrances instead of just the ones that you know are in the AI's current area?

gleaming robin
#

once I properly have my hook in, then I can fine tune it

faint copper
#

yeah

#

fair

gleaming robin
faint copper
#

also, the reason I ask about getting line numbers is just because I'm assuming that error occurs when it can't find a match for what you're searching for, but it is suspicious that it's not a custom error

gleaming robin
#

I'll throw the pdb in with the next build

faint copper
#

unless they're not in that hierarchy

#

I'd have to check whether the interior ones spawn through SpawnSyncedObject or something, but I wouldn't expect they would

gleaming robin
#

they do

faint copper
#

oh weird

#

I'm surprised the teleportation isn't a player rpc

#

okay then

gleaming robin
#

`// SetDestinationToPosition(baboonCampPosition);
IL_0483: br.s IL_0492

IL_0485: ldarg.0
IL_0486: ldsfld valuetype [UnityEngine.CoreModule]UnityEngine.Vector3 BaboonBirdAI::baboonCampPosition
IL_048b: ldc.i4.0
IL_048c: call instance bool EnemyAI::SetDestinationToPosition(valuetype [UnityEngine.CoreModule]UnityEngine.Vector3, bool)
IL_0491: pop`
#

okay so that's the IL I'm attempting to access

#

do I need to match that ldsfld?

faint copper
#

yes

golden basin
#

Star you've been messing with the navmesh for a while

#

Is there a way to make an enemy pick a further away node

#

When wandering

faint copper
#
    c.GotoNext(
        x => x.MatchLdarg(0),
        x => x.MatchLdcI4(0),
        x => x.MatchCall<EnemyAI>(nameof(EnemyAI.SetDestinationToPosition))
        );

this piece of code specifically looks for

ldarg.0
ldc.i4.0
call instance bool EnemyAI::SetDestinationToPosition(valuetype [UnityEngine.CoreModule]UnityEngine.Vector3, bool)

if it sees that ldsfld in the middle it won't match

gleaming robin
#

uhhh iirc there's a method for ChooseFurthestNodeFromPosition

golden basin
#

Ehh furthest node isn't that great, I just wanna like increase the range because the Redwood can stay in one spot too much

faint copper
#

with the search coroutine?

golden basin
#

If possible yeah

#

But if I have to I can make my own stuff

gleaming robin
#

yea I'm not sure lol, sorry

gleaming robin
faint copper
#

if that compiles, that seems right

#

oh wait

#

never mind, that type parameter is probably the type that field lives on

#

you didn't specify where the field is

gleaming robin
#

Not sure I understand

faint copper
#

what class defines "baboonCampPosition"? and where is it in that function call?

gleaming robin
#

Well since MatchLdsfld requires a string, would I just use BaboonBirdAI.baboonCampPosition.ToString()?

#

or do I need to use the overloaded method and do nameof(BaboonBirdAI)

faint copper
#

nono

#

x.MatchLdsfld<BaboonBirdAI>("baboonCampPosition")

#

that's what I meant by specifying the type it lives on

gleaming robin
#

ohh

faint copper
#

you gave it the type of the field and the name of the field, but not the type it is on, so it would have to scan all loaded types for that field if it was going to do what you wanted

gleaming robin
#

gotcha gotcha

faint copper
#

if you want to use nameof, though, which you should, you would do x.MatchLdsfld<BaboonBirdAI>(nameof(BaboonBirdAI.baboonCampPosition))

#

it's much better to reference things that way so that you can use IDE tools to find that again if you ever need to

#

which is why using the publicizer is also a very good thing to do

gleaming robin
#

So once I've matched it, the MM examples do some OpCode emitting, what is that really for?
c.Emit(OpCodes.Ldarg_0);
c.Emit(OpCodes.Ldc_I4_0);

faint copper
#

reflection that is asking for a field or method that doesn't exist will fail at compile time instead of runtime when using nameof

gleaming robin
#

fair point

faint copper
#

that will load the first argument and then load a constant value of 0

#

(Ldc = load constant, i4 = 4-byte integer, 0 = constant zero)

gleaming robin
#

So with that, is the 0 being used for false?

faint copper
#

yep

#

0 = false, 1 = true

gleaming robin
#

nice

#

arg.0 then is position? Which uses the ldsfld?

faint copper
#

arg 0 is the position, yes

#

er, whoops

#

no, arg 0 would be this in an instance function

#

for a static method it would be position

gleaming robin
#

okay so this is where the visualization of the stack comes in I guess

faint copper
#

the main thing you have to keep in mind is that things are popped from the stack in the same order they are pushed to it

#

in the case of a method call, it pops in the order you would expect given the parameter ordering

#

last push is last arg etc

gleaming robin
#

so arg.0 is "this" (meaning the hawk in this instance?), the fld is the position, the i4.0 is false, which are then called with SetDestinationToPosition()?

faint copper
#

which are then popped by the call to SetDestinationToPosition()
, yes

faint copper
#
    IL_0485: ldarg.0
    IL_0486: ldsfld valuetype [UnityEngine.CoreModule]UnityEngine.Vector3 BaboonBirdAI::baboonCampPosition
    IL_048b: ldc.i4.0

after these three instructions, the stack is 3 items

#

if it was ldfld, it would pop one item off the stack

gleaming robin
#

would ldfld pop the field that it loads off the stack?

faint copper
#

ldfld pops one value off the stack and then loads a field from it and pushes that onto the stack

gleaming robin
#

ahh

#

how dare you link to a .net8 doc :P

#

so in my case

faint copper
#

erm.... actually....

gleaming robin
#

do I need to emit any opcodes, or do I just EmitDelegate?

faint copper
#

depends on the case

gleaming robin
faint copper
#

Google doesn't know how to remove queries from URLs because it's dumb

#

anyway

#

if you need a value that exists in the function I believe you probably do need to emit opcodes, unless MonoMod does some magic to detect variable names or something

#

if it doesn't, just load the things you need from the place you're injecting in the order you define them in the delegate

gleaming robin
#

it looks like I can use EmitDelegate and then just use regular code

faint copper
#

hm?

#

it doesn't say anything about that there

#

all it does is emit a call or callvirt to your function

gleaming robin
#

the example code was this, so that was my understanding

c.EmitDelegate<Action<PlayerControllerB>>((self) =>
{
    logger.LogInfo("Hello from C# code in IL!");

    if (self.isSprinting)
        self.jumpForce = 30f;
    else
        self.jumpForce = 13f; // this is the default value of jumpForce
})```
faint copper
#

it seems like self is a special case, which makes sense

#

although I'm not exactly sure how that works

#

I guess you would have to make it the last argument in your delegate, which seems a bit silly to me