Jump to content

[LE] Optimizing a monster script


Recommended Posts

Ok, so I am going to give you the compiler error because you seem to think I'm doing it all wrong here, but your GetBaseObject() useage is wrong

 

looks like the line 152 simply doesn't need GetBaseObject(). I'll see if it functions in game this way.

 


Starting 1 compile threads for 1 files...
Compiling "DBM_PrepstationScript2Extender"...
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(153,11): GetBaseObject is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(153,27): cannot cast a none to a armor, types are incompatible
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(182,15): GetBaseObject is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(182,31): cannot cast a none to a armor, types are incompatible
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(220,15): GetBaseObject is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(220,31): cannot cast a none to a armor, types are incompatible
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(258,15): GetBaseObject is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(258,31): cannot cast a none to a armor, types are incompatible
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(259,77): variable jcRef is undefined
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(259,83): none is not a known user-defined type
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(259,100): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepstationScript2Extender.psc(259,100): cannot relatively compare variables to None\

Link to comment
Share on other sites

Ok, so scratch any issues on the extender script, just a few oversights on your original like jcRef was supposed to be Jc2Ref instead and the getbaseobject calls were not needed in those instances (or the as armor has to be called on the formlist getat() call, not sure, we'll see if it works properly)

 

So then trying to compile your reworked child script, it still has issues with failing to cast ActionRef

 

The issue seems to be (at least if I am understand it properly), The OnActivate event it filling ActionRef as an objectreference but your functions need to call it as an actor. Either that or like I mentioned before, ARef is NOT defined anywhere inside the script other than inside the Armory block which runs separate from the rest and thus does not carry that function property out

 


Starting 1 compile threads for 1 files...
Compiling "DBM_PrepStationScript2"...
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(198,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(201,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(204,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(211,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(214,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(217,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(220,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(227,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(257,4): type mismatch on parameter 1 (did you forget a cast?)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\DBM_PrepStationScript2.psc(260,4): type mismatch on parameter 1 (did you forget a cast?)
No output generated for DBM_PrepStationScript2, compilation failed.

Batch compile of 1 files finished. 0 succeeded, 1 failed.
Failed on DBM_PrepStationScript2

Link to comment
Share on other sites

Oh and lastly, you didn't explain why you prefer using Game.GetPlayer() when several people have attested to me over the last couple years that setting a property for it is 1000 times faster. Incidentally if I do set a PlayerRef property and replace your ActionRef function property in the child script to pass the PlayerRef through to the parent script as the first parameter in each of the sort functions, it compiles just fine. Can to explain clearly why this would not work the best? because as the script looks, there is NOTHING telling the normal state OnActivate event what ActionRef even is because it can't pass an objectreference through as an actor (which is why is causing the type mismatch as best I can tell).

 

I am fascinated by the array method you are eluding to in the script and in your last post. Are Arrays a much faster method to indexing data? faster than formlists or individual properties?

Link to comment
Share on other sites

 

I am fascinated by the array method you are eluding to in the script and in your last post. Are Arrays a much faster method to indexing data? faster than formlists or individual properties?

Arrays are only faster when a formlist contains more than 128 entries. Otherwise an array and a formlist process pretty much the same. The only difference being that arrays can contain INT, FLOAT & STRING whie formlists can only contain forms of one or multiple types.

 

ReDragon2013's array function in the post you indicated simply removes your individual checks for mods into a string array of mod names that then set an index matching bool array with true false values so that you can just check for that stored value rather than calling GetModByName throughout each script run. If called in an OnInit event and then remotely from an OnPlayerLoadGame event, you can reduce the OnActivate processing time a little bit while maintaining valid bool values in the array.

Link to comment
Share on other sites

icecreamassassin wrote: "Oh and lastly, you didn't explain why you prefer using Game.GetPlayer() when several people have attested to me over the last couple years that setting a property for it is 1000 times faster."

 

The fairytale was written in year 2012, Charles Cooley aka CDCooley wrote:
"Game.GetPlayer() function takes approximately 1000 times longer to run than just accessing a property set to PlayerRef."

You'll find his mod "PapyrusSpeedTest" here: http://www.nexusmods.com/skyrim/mods/18825/?

And here you'll find a posting by Perdev, which explained why this is a fairytale. http://forums.bethsoft.com/topic/1383987-performance-characteristics-of-papyrus-functions-and-operations/page-2

 

I made my own speedtest, the while counter "i" is 7. "bLoop" is a scriptVariable, declared like that Bool bLoop

 

playerRef

 

;========================
State Test11
;===========
FUNCTION myF_Test()
  sTest = "fm = playerRef.GetBaseObject()"
  actor playerRef = Game.GetPlayer()
  form fm

int i = ff.Length
WHILE (bLoop)
    i = i - 1
    ff[i] = Utility.GetCurrentRealTime()
    
    fm = playerRef.GetBaseObject()

    bLoop = (i > 0)
ENDWHILE
ENDFUNCTION
;=======
endState
;========================
State Test18
;===========
FUNCTION myF_Test()
    sTest = "playerRef = None"
    actor aRef = Game.GetPlayer()
    actor playerRef = aRef

int i = ff.Length
    WHILE (bLoop)
        i = i - 1
        ff[i] = Utility.GetCurrentRealTime()

;;;     playerRef = aRef
        playerRef = None        

        bLoop = (i > 0)
    ENDWHILE
ENDFUNCTION
;=======
endState

 

 

 

Game.GetPlayer()

 

;========================
State Test8
;===========
FUNCTION myF_Test()
    sTest = "aRef = Game.GetPlayer()"
    actor aRef

int i = ff.Length
    WHILE (bLoop)
        i = i - 1
        ff[i] = Utility.GetCurrentRealTime()

        aRef = Game.GetPlayer()

        bLoop = (i > 0)
    ENDWHILE
ENDFUNCTION
;=======
endState

 

 

 

I used a quest script which runs on intro scene in fresh new game:

 

[03/24/2017 - 05:08:49AM] Test 0: empty loop  1.0 ms = 0.001 sec
[03/24/2017 - 05:08:49AM]  completed in 27.285984 ms,  max = 0.055000, min = 0.000000 sec   average = 0.027200
[03/24/2017 - 05:08:50AM]  
[03/24/2017 - 05:08:50AM] Test 1: s = "sample"
[03/24/2017 - 05:08:50AM]  completed in 30.857086 ms,  max = 0.057999, min = 0.017002 sec   average = 0.028200
[03/24/2017 - 05:08:50AM]  
[03/24/2017 - 05:08:50AM] Test 2: f = GameDaysPassed.value
[03/24/2017 - 05:08:50AM]  completed in 32.143185 ms,  max = 0.070999, min = 0.021000 sec   average = 0.026601
[03/24/2017 - 05:08:50AM]  
[03/24/2017 - 05:08:50AM] Test 3: f = GameDaysPassed.GetValue() = 0.296444
[03/24/2017 - 05:08:50AM]  completed in 36.857059 ms,  max = 0.062000, min = 0.017998 sec   average = 0.035600
[03/24/2017 - 05:08:51AM]  
[03/24/2017 - 05:08:51AM] Test 4: i = GameDaysPassed.GetValueInt()
[03/24/2017 - 05:08:51AM]  completed in 36.143166 ms,  max = 0.060001, min = 0.021000 sec   average = 0.034400
[03/24/2017 - 05:08:51AM]  
[03/24/2017 - 05:08:51AM] Test 5: if GameDaysPassed as GlobalVariable | endif
[03/24/2017 - 05:08:51AM]  completed in 24.285997 ms,  max = 0.063999, min = 0.000000 sec   average = 0.021201
[03/24/2017 - 05:08:52AM]  
[03/24/2017 - 05:08:52AM] Test 6: s = Debug.GetVersionNumber()
[03/24/2017 - 05:08:52AM]  completed in 52.428108 ms,  max = 0.081001, min = 0.000000 sec   average = 0.057199
[03/24/2017 - 05:08:53AM]  
[03/24/2017 - 05:08:53AM] Test 7: f = Utility.GetCurrentGameTime()
[03/24/2017 - 05:08:53AM]  completed in 41.714260 ms,  max = 0.080997, min = 0.000000 sec   average = 0.042200
[03/24/2017 - 05:08:53AM]  
[03/24/2017 - 05:08:53AM] Test 8: aRef = Game.GetPlayer()
[03/24/2017 - 05:08:53AM]  completed in 63.142502 ms,  max = 0.082001, min = 0.040001 sec   average = 0.063999
[03/24/2017 - 05:08:54AM]  
[03/24/2017 - 05:08:54AM] Test 9: oRef = Game.GetForm(0x14) as ObjectReference
[03/24/2017 - 05:08:54AM]  completed in 34.857067 ms,  max = 0.053001, min = 0.017998 sec   average = 0.034600
[03/24/2017 - 05:08:55AM]  
[03/24/2017 - 05:08:55AM] Test 10: oRef = Game.GetPlayer() as ObjectReference
[03/24/2017 - 05:08:55AM]  completed in 67.000252 ms,  max = 0.080002, min = 0.046001 sec   average = 0.068600
[03/24/2017 - 05:08:55AM]  
[03/24/2017 - 05:08:55AM] Test 11: fm = playerRef.GetBaseObject()
[03/24/2017 - 05:08:55AM]  completed in 63.000271 ms,  max = 0.077999, min = 0.046997 sec   average = 0.063201
[03/24/2017 - 05:08:56AM]  
[03/24/2017 - 05:08:56AM] Test 12: AB = playerRef.GetActorBase()
[03/24/2017 - 05:08:56AM]  completed in 59.999737 ms,  max = 0.081001, min = 0.030998 sec   average = 0.061600
[03/24/2017 - 05:08:56AM]  
[03/24/2017 - 05:08:56AM] Test 13: if fm as Actor | endif
[03/24/2017 - 05:08:56AM]  completed in 31.428747 ms,  max = 0.073002, min = 0.013000 sec   average = 0.026800
[03/24/2017 - 05:08:57AM]  
[03/24/2017 - 05:08:57AM] Test 14: fx = Game.GetPlayer().X
[03/24/2017 - 05:08:57AM]  completed in 86.714607 ms,  max = 0.119003, min = 0.044998 sec   average = 0.088600
[03/24/2017 - 05:08:58AM]  
[03/24/2017 - 05:08:58AM] Test 15: fx = playerRef.X
[03/24/2017 - 05:08:58AM]  completed in 54.714203 ms,  max = 0.084999, min = 0.025002 sec   average = 0.054600
[03/24/2017 - 05:08:59AM]  
[03/24/2017 - 05:08:59AM] Test 16: fz = Game.GetPlayer().GetPositionZ()
[03/24/2017 - 05:08:59AM]  completed in 80.428535 ms,  max = 0.097000, min = 0.035999 sec   average = 0.086000
[03/24/2017 - 05:08:59AM]  
[03/24/2017 - 05:08:59AM] Test 17: fz = playerRef.GetPositionZ()
[03/24/2017 - 05:08:59AM]  completed in 53.999763 ms,  max = 0.093998, min = 0.024002 sec   average = 0.052000
[03/24/2017 - 05:09:00AM]  
[03/24/2017 - 05:09:00AM] Test 18: playerRef = None
[03/24/2017 - 05:09:00AM]  completed in 25.571550 ms,  max = 0.066002, min = 0.012001 sec   average = 0.020200
[03/24/2017 - 05:09:01AM]  
[03/24/2017 - 05:09:01AM] Test 19: f = playerRef.GetHeight()
[03/24/2017 - 05:09:01AM]  completed in 57.143074 ms,  max = 0.102001, min = 0.022999 sec   average = 0.055000

 

 

Let us assume playerRef would be 1000 times faster than Game.GetPlayer(), what would be happen?
If PlayerRef would need 1.0 ms, so Game.GetPlayer() may run only every 1.0 s, that is ridiculous.

Game.GetPlayer() is going to slow down your scripts if you call it in a while loop over and over again, but you have to call it more than 6 times before the game engine lower the script priority (in my experience).

In worst case it runs 100 times/percent slower (it consumes the double time), which is the difference from 30.0 ms up to 60.0 ms, which are 0.030 seconds.

Do you think this is much time?

Edited by ReDragon2013
Link to comment
Share on other sites

actionRef, Why can I be sure that is the player?

 

vanilla like events:

EVENT OnActivate(ObjectReference akActionRef)
ENDEVENT
EVENT OnTriggerEnter(ObjectReference akActionRef)
ENDEVENT

I prefer the next, do not ask me why?

EVENT OnActivate(ObjectReference actionRef)
ENDEVENT
EVENT OnTriggerEnter(ObjectReference triggerRef)
ENDEVENT

and now the trick:

EVENT OnActivate(ObjectReference actionRef)
IF (actionRef == Game.GetPlayer() as ObjectReference)
ELSE
     RETURN  ; - STOP - not activated by the player
ENDIF
;-------------- from here the actionRef is always the player as ObjectReference
 actor aRef
    aRef = actionRef as Actor       ; speed up
    aRef = Game.GetPlayer()         ; slower speed while using Game.GetPlayer() a second time
ENDEVENT

I hope it explained the using of actionRef.

Edited by ReDragon2013
Link to comment
Share on other sites

I do not use SKSE, so it is impossible to compile such scripts by me.

 

The next function could be useful, if you check players inventory once only (SKSE is required).

 

  Form[] PROPERTY InventoryList auto Hidden
  Int    counterIL

;---------------------------------------
FUNCTION myF_SKSE_StorePlayerInventory()
;---------------------------------------
; http://www.creationkit.com/index.php?title=GetNthForm_-_ObjectReference

    actor aRef = Game.GetPlayer()
    InventoryList = new Form[128]        ; max. array size
    counterIL = 0

int i = aRef.GetNumItems()               ; SKSE
WHILE (i > 0) && (counterIL < 127)
        i = i - 1
        form fm = aRef.GetNthForm(i)     ; SKSE

        IF (fm as Weapon) || (fm as Armor)
            InventoryList[i] = fm        ; store that form for comparison later
            counterIL += 1               ; update array counter
        ENDIF
ENDWHILE
ENDFUNCTION

 

 

 

The question is: Does it makes sense to store players inventory? Can we really decrease the script runtime?

Edited by ReDragon2013
Link to comment
Share on other sites

Thanks for the time test info, that's very informative.

 

I think you are misunderstanding me about ActionRef usage. I understand HOW it's supposed to work, the issue is that the way you wrote it, it DOESN'T work. The child script will not compile and says that actionref is not the right type and that it's failed to cast. So if you could look again and see where actionref is supposed to be defined for the function blocks that'd be very helpful because as it stands it's not compiling and the only solution I have tried which works is to cast actionref = game.getplayer() right before the sort function groups run

Link to comment
Share on other sites

You wrote: "The child script will not compile and says that actionref is not the right type and that it's failed to cast."

 

That is interesting:

EVENT OnActivate(ObjectReference actionRef)
IF (actionRef == Game.GetPlayer())                       ; this is working without typecast, because actor is always of type objectReference
ELSE
    RETURN ; - STOP -
ENDIF
;--------------------------- I forgot the typecast !!
    myF_Test(actionRef as Actor)                         ; typecast is needed, because not every objectReference can be an actor
ENDEVENT

FUNCTION myF_Test(Actor aRef)
;----------------------------
  ; do nothing
ENDFUNCTION

If you need more advise for your monster script, I think it is a good idea to post your current version of script(s) here again. Did you notice, some functions are redundant?

Edited by ReDragon2013
Link to comment
Share on other sites

Alrighty so I stuck in the myF_Test(actionRef as Actor) into the activation event and stuck the function for it in the parent script and they both compile fine now. I'll set it up again and test to see what's what. If I have any issues I'll post back. I did notice the first time through I was getting a ton of stack errors on your myF_SortByMod function, which I'll have to look into, but I'll post if I can't figure out the cause. I suspect it's just running code without conditioning out that the mod isn't loaded.

 

EDIT: Looks like the errors have resolved, so all should be good. Doing tests now.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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