Jump to content

[LE] How to scan for actors around player?


xyz3lt

Recommended Posts

Naturally since i am looking for a way to get actors from around player any way of scanning for ObjectRefrences around some ObjectReference will do.

Ideally what i'd like is a Scan() function that returns array of Actors or ObjectReferences.

Roughly what i am using right now.

elt_Scanner.psc:

  Reveal hidden contents



elt_ScannerEffect.psc:

  Reveal hidden contents



Script above casts AOE on player and retrives actors this way, but it does take a little while, mostly because i don't know how to safely handle parallelism differently.

I tried to use PapyrusUtils>MiscUtils>ScanCellNPCs but exactly as it says it only seems to scan a single cell, which is a problem in worldspace since cells are divided into squares.
Also thought of getting 4 closest cells to player then GetNthForm for actors and handle distance manually with GetDistance. I didn't try it though.
And also tried PowersOfThree>PO3_SKSEfunctions>FindAllReferencesOfFormType but that function seems to returns references as you would see them in CK render window. It worked very oddly, sometimes returning nothing and sometimes a lot.

Some mod that i checked made use of a scriptCloak that add's keywords, then Actors are retrived trough ReferenceAlias'es. It's a bit too confusing for me to recreate from just looking.

 

Here is PO3 script incase i used it incorrectly.

 

elt_QuestScanner.psc:

 

  Reveal hidden contents

 

Link to comment
Share on other sites

You can use SKSE to do something similar. I wrote a quick and dirty example:

Actor akCenter = player ; player variable containing Game.GetPlayer() isnt visible in this example
Actor[] kActors = new Actor[128]
Cell kCell = akCenter.GetParentCell()
Int cellActors = kCell.GetNumRefs(43)
Int i


while i < cellActors
    Actor akActors = kCell.GetNthRef(i, 43) as actor
    if akActors != akCenter ; exclude the center of the search
        kActors[i] = akActors
    endif
    i += 1
endwhile

Problems: Could be slow since it searches the entire cell checking every type that matches, so highly populated cells might slow it down.

You will need to resize the array if the number of actors is over 128. I think, for example if you're near the edge of a cell and actors are in the next cell, this method will ignore them and catch only the ones in the parentcell. This works great for interiors though.


You can modify this to make your own FindReferenceofXXXXX, like restricting the search to the radius around the player, rather than the full size of the cell if you want as well.

Edit: I believe that FindAllReferencesOfFormType is actually using GetNumRefs underneath because the behavior you described is exactly how GetNumRefs operates. Cells might have 20 actors, and then some cells might have no actors. Now if you use the formtype to find objectreferences, it will return everything in the cell.

Edited by AnishaDawn
Link to comment
Share on other sites

Papyrus Extender has some functions that can help with this: https://www.nexusmods.com/skyrim/mods/95017

ObjectReference[] function FindAllReferencesOfType(ObjectReference akRef, Form formOrList, float radius) global native
ObjectReference[] function FindAllReferencesWithKeyword(ObjectReference akRef, Keyword[] keywordArray, float radius, bool matchAll) global native
Actor[] function GetActorsByProcessingLevel(int Level) global native

Use 0 for the actor function to get all loaded actors in your area.

Link to comment
Share on other sites

Big problem with GetNthRef / GetNumRefs is how cells work, inside a big cell like a ruin you can get a lot of hits, but add some GetDistance processing and you are good, meanwhile actors standing next to you inside worldspace like tamriel or whiterun may not be detected since they are technically in a different cell. For interiors i could just use ScanCellNPCs from MiscUtils as it does have built in distance, but for exteriors i'd have to check roughly 4 cells closest to player to get rid of "standing next to but not detected" issue. If it's faster then spell approach i'll try doing it anyways.

 

As for PO3 it just acts strangely, maybe i misunderstood how it works, using script above, outside of jorrvaskr i can get at most 3 detections (player included) but usually 0 not even player, but inside even though there were only 2 npcs there i got 13 detections, including strange things like bandits and silver hand.

Link to comment
Share on other sites

Test script i am using.

 

elt_QuestScanner.psc:

 

  Reveal hidden contents



Test62 FindAllReferencesOfFormType works erratically detecting invisible things and sometimes nothing.

Test64 using my spell scanner, works fine, but it does take 5 seconds (i could probably cut it down a bit).

Test65 FindAllReferencesOfType doesn't ever return anything, clearly i am using it wrong and after a bit of testing i still don't have any idea how to make it return anything.

Test66 GetActorsByProcessingLevel, it does work, returns 50 actors on average, with a bit of processing it coud easily be cut down to ~15, any idea how does it perform in comparison to spell?

 

As for keywords search i didn't try it yet, i am not sure what keyword to look for, i could make a script cloak that adds/removes keywords but that couldn't possibly be performance friendly.

 

Edit: As for MiscUtils ScanCellNPCs it only scans around you in current cell, works great for interiors but no so much for worldspace (square grid of cells).

Edit2: somewhat more readable script

Edited by xyz3lt
Link to comment
Share on other sites

Here is an explanation of processing level: https://geck.bethsoft.com/index.php?title=GetActorsByProcessingLevel

0 gets all loaded actors in the area.

 

For FindAllReferencesOfType, it only finds object references of a specific form. So if you used:

 

MiscObject Property Lockpick Auto

Event OnInit() 
    Form[] MyFormArray = PO3_SKSEfunctions.FindAllReferencesOfType(Game.GetPlayer(), Lockpick, 1000)
EndEvent

It would only find all of the lockpicks in 1000 units from the player. So if using an actorbase, it would only find that specific actor. Using a formlist instead there for me caused CTD. I would suggest using the keyword function. You can use ActorTypeNPC to get all humanoid actors. There's also a bunch of other ActorType keywords you can check for.

 

Keyword Property ActorTypeNPC Auto 

Event OnInit() 
    ObjectReference[] NPcs = PO3_SKSEfunctions.FindAllReferencesWithKeyword(Game.GetPlayer(), ActorTypeNPC, 1000, false)
EndEvent

Or, if you're using Skyrim SE, you can maybe use SkyPal: https://www.nexusmods.com/skyrimspecialedition/mods/43925?tab=description which has a bunch of functions for getting and filtering object references.

 

Link to comment
Share on other sites

For now i'll try to improve SpellScanner, implement proper FindAllReferencesWithKeyword search keyword being ActorTypeNPC, implement skypal Grid() then filter it for actors then distance, and finally GetActorsByProcessingLevel with a bit of postprocessing, also using skypal filter for distance. Then test for performace impact of those 4 methods and that would be it.

 

Thanks for all the help thats probably all i needed to know.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...