Jump to content
ChaosWarrior

Skyrim modding help: Cant make Actor to run package and PlaceActorAtMe behavior

Recommended Posts

So I ran into another issues which are undocumented:

First one is that when actors spawn by quest somewhere like 50000-100000 units from player (and even right outside the cave I just entered, doesnt matter as long as cell is unloaded from begining) they just stay, despite having package to run to some activator.

Package itself works flawlessly as long as quest starts in a loaded cell (from onload() event like random encouners).
I tried EvaluatePackage(), StartCombat(Player), MoveToPackageLocation() on different package and switching and for now the only satisfying way is MoveTo to loaded area with alpha 0.1 aggression 0 etc and back.

Is there any conventional way to make them move on their own before player hit "wait" ?

 

Second problem is with PlaceActorAtMe. I reworked entire system so now aliases do not spawn at filling, but they instead optional and spawn when calling function(it happens onupdate every 4 seconds as long as deployed == false). Kinda thought that may help with first part, as placeactoratme make them special in terms of persistance, as well as forcerefto() and it can help with package starting. Here is version of function with return after one spawn, first version threw all of them into world at one loop, however this makes no difference. It gets same result: they dont spawn at obj1, instead they spawn somewhere between obj1 and player, on a distance varying from 8000 (like 2 cells) to 17000. And if if happens to be uloaded they get stuck.

 

Obj1 is a barrel 100000 units away from player position on save, which I use for testing. It is okay for sure as I made function within same script that teleports player there and it is still that obj1.

function DeployAllByOne(objectreference drop) ;;;((ccccBanditTypes.GetAt(0) as ActorBase), 1)
if drop == none
return
endif

actor spawn
int ida = 0
while ida < refaliasarray.length
	if refaliasarray[ida] != none
		if (refaliasarray[ida] as ccccwealiasscript) != none && (refaliasarray[ida] as ccccwealiasscript).reinforcement == false
			if refaliasarray[ida].GetReference() == none
				spawn = drop.PlaceActorAtMe((ccccBanditTypes.GetAt((refaliasarray[ida] as ccccwealiasscript).flistID) as ActorBase),1)
				refaliasarray[ida].ForceRefTo(spawn)
				(refaliasarray[ida] as ccccwealiasscript).SpecialInit()
				debug.Notification("Deployed: " + ida)
				return
			endif		
		endif
	endif
	ida +=1
	if ida > 12
		deployed = true
	endif
endwhile

endfunction

Has anyone dealt with these?

Share this post


Link to post
Share on other sites

Sounds not unlike the Patrols Addon for OBIS SE. Please do go look at it and see if it fits your needs.

For the first part I used Patrol markers. The group (leader and 0 to 3 followers) will spawn at the first marker then patrol along the linked markers and back. No need for player to be there. In fact the spawning occurs while player is indoors to avoid the pop-ins altogether.
You can set up any type of patrol really. Like one to spawn and start when player enters LocTypeDungeon then ends at the entrance. Waiting for them to exit.

Second part - I setup each reference in the quest to hold the possible max patrols. So, each patrol route is covered. Aliased would be as follows. Patrol Start Marker, Leader is created at Start Marker, then each of the 3 possible followers is created at the start marker with conditions including the Global variable which is set in menu for how many followers to deploy.
Leveled lists are used for them to spawn from. And those lists can be adjusted from menu settings as well - in terms of difficulty/toughness. Oh... one of the conditions is to not be the Minotaur race that is in OBIS - they are too slow for patrols. :)

Since the spawning occurs not with script in while loop - instead it is part of the quest starting up and filling... That is how the patrols will reset. The control script will just restart the quest when it is time or when changes in settings are made.

Also, spawning from the while loop - I have found from working on OBIS and Sands of Time mods that using PlaceAtMe() As Actor works well - and using this you can set abInitiallyDisabled = True. We do that in the regular OBIS SE scripts and can add potions add to factions and give them a special item (glowing pearl) that tells us they are script added. All that before then EnableNoWait() then the while loop can move to the next one. PlaceActorAtme() just seems to work better for one off or individual spawns not for quick while loops. Also..... the enable will restart the npc's packages. So, StartCombat(player) should not be needed.

Any questions - please ask!

Edited by Jebbalon
added stuff

Share this post


Link to post
Share on other sites

I'll write more extended post later, but the first problem is that package seems not working until they are loaded or player wait, I mean: I load save, type in console "bat dev" which enables tgm, sets speedmult, adds debug dagger, which on equip starts quest.

And debug notification says they stand still.

If I wait they teleport and then work, but that is not as I want them to. They also work just fine if I move them into loaded area and back.

 

PS I will look onto OBIS, seems like very cool mod from what I saw.

Share this post


Link to post
Share on other sites

My last sentence is sort of a clue I think...

6 hours ago, Jebbalon said:

Also..... the enable will restart the npc's packages. So, StartCombat(player) should not be needed.

So, try that with what you have - just put in Actor.Disable() followed by Actor.Enable()

We found that was effective to get them working. (by them I mean the PlaceActorAtMe() spawns) BUT, what happened with us was the player would often see that brief blink out and back in. So, then we went down the road of Line of Sight checks and the SetAlpha(0.1) etc. It got even more complicated. 
We tried the PlaceAtMe() as Actor and initially disabled then later Enable. This seems to work really well. The packages evaluate and they act normal.

That is for spawns that are loaded. The player can see them. (that's in the OBIS main file) For yours try the disable/enable and also the Patrol package where if you have the markers set up they kinda have to start following the route.(OBIS Patrols Addon)

That might be an idea as well.... Leave them disabled until the player loads in the area - then Enable with fade in and see if that works. 

Share this post


Link to post
Share on other sites

Thanks for the Enable/Disable hint - it really works (problem #1)!)

Sorry for long delay - I was busy.


Its not that I was ignorant or something, I've got your clue, but the problem is whenever I use PlaceActorAtMe() or PlaceAtMe() (they proved similiar in this matter) the package is running already... well because it places actors not on a reference upon which it was called, but into loaded area instead.

It really strange thing and am I the only one getting such or it just some lucky mix of conditions? It is not just any place in loaded area thou - it seems to prefer place where calculated NPC path enters loaded area. Tested this also with interior and bandit swarm got spawned right near main entrance, instead of reference which was near Riverside Shack like 140k units from oustide entrance.

So in order to test Enable/Disable thing I had to revert from placeatme() to previous system where quest makes placement of npc. If this behavior of PlaceAtMe() is reliable it could be used for sending reinforcements.

However this works, thanks again:

Spoiler

function DeployAll(objectreference drop) 
if drop == none
return
endif

actor spawn
int ida = 0
while ida < refaliasarray.length
	if refaliasarray[ida] != none
		if (refaliasarray[ida] as ccccwealiasscript) != none && (refaliasarray[ida] as ccccwealiasscript).reinforcement == false
			if refaliasarray[ida].GetReference() == none
				spawn = PlayerRef.PlaceAtMe((ccccBanditTypes.GetAt((refaliasarray[ida] as ccccwealiasscript).flistID) as ActorBase),1, false, true) as actor
				spawn.moveto(drop)
				spawn.EnableNoWait()
				refaliasarray[ida].ForceRefTo(spawn)
				(refaliasarray[ida] as ccccwealiasscript).SpecialInit()
				;debug.Notification("Deployed: " + ida)
				;return
			endif		
		endif
	endif
	ida +=1
	if ida > 12
		deployed = true
	endif
endwhile



endfunction

 


About patrol thing - in my case it is follow package as it works well for dynamically moving destination, also if set large radius (distance between "close enough" destination and target reference) it helps against being stuck due to target use jumping to traverse imposible terrain, outplacing my old backtracking system. Target of package is activator type marker which gets moved towards player or something else on some conditions. There are few types of such markers and conditions for different worldspaces, for interiors etc, and getdistance() used to check where two are in the same WS and some calculations.

Also I wonder if this part of PlaceAtMe() has been reversed by SKSE team. Probably a function that finds and returns pathnode or something that matches conditions would be one good to have.

Share this post


Link to post
Share on other sites
10 hours ago, ChaosWarrior said:

Its not that I was ignorant or something, I've got your clue,

No, no, my thought process was more like " Oh, I know what might be going on! ... it's in my last line of that paragraph! " the disable/enable thing.

Anyway, that might just be the difference between PlaceActorAtMe() and PlaceAtMe() As Actor - is in the way you can use disable then enable. With PlaceActor they are spawned then you can disable and enable them to kickstart AI. Where as with PlaceAtMe you can use initially disabled and then enable. Both work but you avoid the blinking in and out if the player happens to be in line of sight. That is how we learned this with OBIS anyway. But that is all in loaded areas ....

So, with OBIS patrols it happens in unloaded areas but with the pre-placed xMarkers/patrol points. You want to use dynamic points to spawn at.... ? Which are in unloaded areas. ............. Hmmm

ok, what if... Your activator - Can it have a linked reference? a second activator or marker. When the player changes location the activator moves to player and the linked marker is left in previous location. Or rather the sequence would be Player changes loc, then linked marker moves to activator then the activator moves to player. Then you can spawn at player disabled, Use skse function to GetNthLinkedRef() (would have to look that up but it is something like that) Move to that marker and enable. You might even have more than one linked markers. ... And onCellChange might work as well.

Does that sounds like something useful?

Edited by Jebbalon
stream of consciousness edit

Share this post


Link to post
Share on other sites

Short answer - problem solved as I can spawn disabled npc even on the player head and then moveto them anywhere.

But I still wonder: do placeatme or placeactoratme always spawn actors in loaded area? Because I was near Whiterun and reference was a barrel near Riverside Shack, getdistance attached to debug.notification showed like 110k units between squad leader and destination (that activator which stalking player) when I wasnt using PlaceAtMe, well it shows the same after moveto. And now I chose playerref instead of barrel to observe is there any blinking. But the question is in the first sentence of this block of text, because without "initialy disabled" and without moveto "barrel.placeatme()" places them in distance 8-17k from player. It even does not matter where player is! Barrel is 110k from whiterun.

 

If you interested in things what I am doing: it is not about bandits, but I use them for testing. It is kinda horror/survival/sneak/escape thing.

There are few things that stalk player but shortly: a grid of start points, worldspace anchors - used to run getdistance upon and see if it is less then few millions, stalking markers which do not leave corresponding worldspace, stalking markers that follow player anywhere, the system of intercepting running player and of calling reinforcements, and the most complicated one - system of bypassing any kind of stuckness xD

Also there is parent quest that manages starting of this based on conditions and holding data, so it is most likely that reference upon which the things spawn will not be in loaded area, once conditions are met its choice based upon on coordinates in worldspace. I am avoiding SM for now, want to do it hardcore.

It heavily relies on coding and I am unsure if I finish it, but I trying to make it before my 30 birthday.

Share this post


Link to post
Share on other sites

That sounds cool - can't wait to try it out!

That 8-17k distance is within the uGrids 5x5 grid radius - so yeah, loaded area. The MoveTo should work though no matter the distance. That is interesting.

Happy Holidays and Happy early Birthday!

-Jebbalon

Share this post


Link to post
Share on other sites

Some things to keep in mind:

  • When an actor is placed, the game will try to move it onto the nearest navmesh without saying. If a cell is not loaded, there will be no navmesh either, so placement is expected to be pretty inaccurate.
  • Placing an actor in an unloaded cell via PlaceAtMe won't work if the ref to place the actor at is not peristent. While you can force any ref to be persistent by ticking the respective flag in the CK, having too many peristent refs is not a good idea (they permanently consume memory).
  • Likewise, actors cannot interact with refs in unloaded cells unless they are persistent.
  • Actors that run packages to move from one place to another do still move while they are in unloaded area, but this "movement" is a simulation and no real movement. The game updates them at pretty long time intervals and then moves them some distance forward, so they actually move discontinuously.. Update intervals for actors in loaded cells are much shorter.. Thus, if a package starts running on an actor in an unloaded cell, it has to be expected that there will be some time passing before he actually starts moving (plus, he will not really move until he is on a working navmesh; it's likely therefore that the game will teleport him onto the edge of the loaded area, and only then the package runs normally). It's also worth mentioning that movement through unloaded cells is poorly repeatable. Some years ago, I made a mod for measuring the time needed by an actor to move from one location to another (with a long list of locations covered) in order to find out whether they were repeatable (see https://www.nexusmods.com/skyrim/mods/31241). Unfortunately though, they varied by a very large margin. Of course, reproducibility (which takes hardware and game setup variations on other peoples' PCs into account) is even much worse.
  • Placing an actor may take a considerable real time since the game may need to load his face preset and outfit items. If the actors in question only use vanilla items, this is almost negligible. With mods installed that add more faces (and some mods hold them in very long leveled lists) and/or custom outfit items (with texture resolutions notoriously over the top), the situation can be significantly worse. It's a good idea therefore to spawn actors (even disabled ones) at a far enough distance. Otherwise, they may pop in in plain sight. The more actors are spawned at the same time, the worse this gets. There's a reason why most random encounters start running when the trigger loads, i.e. when the cell with the trigger attaches at the edge of the loaded cell grid.

 

 

Share this post


Link to post
Share on other sites
19 hours ago, Jebbalon said:

That sounds cool - can't wait to try it out!

Happy Holidays and Happy early Birthday!

-Jebbalon

Thanks I guess)

 

7 hours ago, Sclerocephalus said:

Some things to keep in mind:

That is interesting, as I found that they move much slower when in unloaded area, in loaded are they cover like 1000-1500 units in one quest onupdate() interval, while in unloaded after enablenowait() it is more like 250-500 units per interval, so long distance placement is probably poor thing to do and unfortunately I have to place more spawnpoints. That unloaded movement is also can be influenced by StartCombat() StopCombat() thing, as I attached them to a *Debug Dagger* I could call those on demand, and see red things on compas plus notifications form script.. so when I do this the squad making leaps that sometimes 10-50k units per click, highly unpredictable yes, and squad can spread thin during this (that is not a big problem thou as "unstuck part" have special approach to those who got stuck in uloaded area while their squadmates are not - they send like reinforcements, not implemented yet, but the reinforcements already are)

About persistance thing: if moveto works on it then it is persistent? It is also referenced by property and touched(moved) in a non-esm plugin, I heard all those things are making things persistant, but there are many levels of persistance and may be there is "not enough persistance" thing. And by the way the later is a good reason to worry less about persistance consuming memory  as most of mods are not master files and still users can load pretty many of those. Actually I tested it with said barrel - set its coordnates to 0,0 in TESEdit and when mod is not master it can be seen at all times near Bleakwind Basin or something, and while plugin is a master - it cant.

 

PS IMPORTANT UPD

Did some research: it seems that after doing moveto() Enablenowait() thing they move for 218 or 436 units per onupdate(), which happens every 4 seconds, those are fancy numbers as 436 is double 218 and it is obvious that "movement simulation" occurs 1 times per one interval and two per another, like once every 3s or something, so speed is 654 units per 8s or rougly 82 units/per second, rather slow.

But that is not the only thing I did. I added another debug dagger that teleports squad to loaded area and back and numbers had changed alot: 1000 to 2000 per onupdate! Also for some reason that notification begin to pop more frequently, not yet understood why as I use RegisterForSingleUpdate(4.0) and cant think of reason why I can see 4 lines of text in notification area at the same time.

So I kinda go back to the beginning with this - I still would prefer to move them in enabled state to loaded area and back as it is the only thing that works satisfying.

PPS was experimenting and got even more wonderful stuff!


To be short I just put up facts:
-Bandit boss in heavy armor sprinting towards player in loaded cell on flat terrain about 2000u per 4s.
-They move pathing while Disabled! That was unexpected! If I disable them for 2seconds(which does one of my experimental functions) and then enable they skip 10k to 14k units in their path, that is while they move at 218 units per tick... it quicly rises to 40k+ when they path at 1000 per tick.
-If they jumped in their path like above they still arrive simultaneously.

PPPS If someone wants to share more intel like this feel free to contact me or invite to some chat. I enjoy scripting for bethesda games and got almost nobody to talk about it.

Edited by ChaosWarrior

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Support us on Patreon!

Patreon
×
×
  • Create New...