Optimize my IsKeyPressed() Script

Post » Thu Jun 21, 2012 7:37 am

Here's what I'm trying to do. I'm trying to create a GTA:SA-like mod that allows two Players to play on ones screen. I did this with Oblivion and Fallout 3 also. Problem is, Papyrus times scripts and tells them to wait if they call stuff a lot. I'm going to post my script (with comments for you guys). Hope some one can help me, if not, I will wait till the OnKeyDown() event from SKSE.

Spoiler

Scriptname MultiplayerSkyrim extends activemagiceffect  Keyword Property P2KeyWord  AutoActor Property aPlayer2  Auto  Actor Property Dummy  Auto  float anglezfloat offset = 50.0float offset2 = -75.0float offsetxfloat offsetyMiscObject Property Checker1  AutoInt Toggle = 0Int Speed = 0Event OnEffectStart(Actor akTarget, Actor akCaster)While Speed == 0 ;Used to make the script faster.If Input.IsKeyPressed(200) == True ;Up Arrow key. For moving forward. This is the only way I've found to get an actor to move forward :(	anglez = aPlayer2.GetAngleZ()	offsetx = offset * math.sin(anglez)	 ;i think sin is for x axis, if not, try cos	offsety = offset * math.cos(anglez)	 ;i think cos is for y axis, if not, try sin	aPlayer2.SetAnimationVariableBool("bHeadTracking", false)		  aPlayer2.MoveTo(aPlayer2, offsetx, offsety, 0)EndifIf Input.IsKeyPressed(208) == True ;Down Arrow key;Empty for now. Going to use Offset2 with a copy of the Up-Arrow block.EndifIf Input.IsKeyPressed(203) ;Left Arrow key. Rotation. This is slow too.	  aPlayer2.SetAngle(aPlayer2.GetAngleX(), aPlayer2.GetAngleY(), aPlayer2.GetAngleZ() - 30)EndifIf Input.IsKeyPressed(205) ;Right Arrow key. Rotation. Slow :(	  aPlayer2.SetAngle(aPlayer2.GetAngleX(), aPlayer2.GetAngleY(), aPlayer2.GetAngleZ() + 30)EndifIf Input.IsKeyPressed(46) ; C key. Attack. Simple. Still slow.	 aPlayer2.SetAlert(True)  If aPlayer2.GetEquippedItemType(0) == 7	 Debug.SendAnimationEvent(aPlayer2, "BowAttackStart")  EndIfDebug.SendAnimationEvent(aPlayer2, "AttackStart")EndifIf Input.IsKeyPressed(47) ; V key. Power Attack.	 aPlayer2.SetAlert(True)	 Debug.SendAnimationEvent(aPlayer2, "AttackPowerStartInPlace")EndifIf Input.IsKeyPressed(48) ; B key. Used for opening Inventory. A simple function like this doesn't even work fast :(	 aPlayer2.SetPlayerTeammate(True, False)	 aPlayer2.OpenInventory(true)EndifIf Input.IsKeyPressed(49) ; N key. Used for getting stats of Player 2.	 Debug.MessageBox(" Health: " +aPlayer2.GetAV("Health") as Int +" Magicka: " +aPlayer2.GetAV("Magicka") as Int \	 +" Stamina: " +aPlayer2.GetAV("Stamina") as Int +" Alchemy: " +aPlayer2.GetAV("Alchemy") as Int \	 +" Alteration: " +aPlayer2.GetAV("Alteration") as Int +" Block: " +aPlayer2.GetAV("Block") as Int \	 +" Conjuration: " +aPlayer2.GetAV("Conjuration") as Int +" Destruction: " +aPlayer2.GetAV("Destruction") as Int \	 +" Enchanting: " +aPlayer2.GetAV("Enchanting") as Int +" HeavyArmor: " +aPlayer2.GetAV("HeavyArmor") as Int \	 +" LightArmor: " +aPlayer2.GetAV("LightArmor") as Int +" LockPicking: " +aPlayer2.GetAV("LockPicking") as Int \	 +" Archery: " +aPlayer2.GetAV("MarksMan") as Int +" Illusion: " +aPlayer2.GetAV("Illusion") as Int \	 +" OneHanded: " +aPlayer2.GetAV("OneHanded") as Int +" PickPocket: " +aPlayer2.GetAV("PickPocket") as Int \	 +" Restoration: " +aPlayer2.GetAV("Restoration") as Int +" Sneak: " +aPlayer2.GetAV("Sneak") as Int \	 +" TwoHanded: " +aPlayer2.GetAV("TwoHanded") as Int)EndIfIf Input.IsKeyPressed(157) && Toggle == 0 ;Right Control	 Debug.SendAnimationEvent(aPlayer2, "SneakStart")	 Toggle = 1EndIfIf Input.IsKeyPressed(157) && Toggle == 1	 Debug.SendAnimationEvent(aPlayer2, "SneakStop")	 Toggle = 0EndifEndwhileEndEvent;NOTES; Like I said, none of these work fast. It's in a while loop, so shouldn't it work fast? Also, it would help if someone could tell me a way to get an; actor to walk forward? Almost like when using "Reference.PlayGroup Forward 1" from Obscript.;;Thanks, Moop <3
User avatar
courtnay
 
Posts: 3412
Joined: Sun Nov 05, 2006 8:49 pm

Post » Thu Jun 21, 2012 9:29 am

Try it as a quest with something like:
Spoiler
ScriptName InputQuestScript extends QuestImport InputBool bIsAttackHotkeyPressedBool bIsSneakHotkeyPressedBool bIsPowerAttackHotkeyPressedBool bIsInventoryHotkeyPressedBool bIsRotateRightHotkeyPressedBool bIsRotateLeftHotkeyPressedBool bSneakFloat fAngleZFloat fOffset = 50.0Float fOffset2 = -75.0Float fOffsetXFloat fOffsetYInt iAttackHotkey = 46 ; 'C'Int iBackwardHotkey =  208; Down ArrowInt iForwardHotkey = 200 ; Up ArrowInt iRotateLeftHotkey = 203 ; Left ArrowInt iRotateRightHotkey = 205 ; Right ArrowInt iInventoryHotkey = 48 ; 'B'Int iPowerAttackHotkey = 47 ; 'V'Int iSneakHotkey = 157 ; R-CtrlInt iStatsHotkey = 49 ; 'N'Actor Property aPlayer2 AutoActor Property Dummy AutoKeyword Property P2KeyWord AutoMiscObject Property Checker1 AutoEvent OnInit()	RegisterForSingleUpdate(0.1)EndEventEvent OnUpdate() 	If IsKeyPressed(iForwardHotkey)		fAngleZ = aPlayer2.GetAngleZ()		fOffsetX = fOffset * Math.sin(fAngleZ)		fOffsetY = fOffset * Math.cos(fAngleZ)		aPlayer2.SetAnimationVariableBool("bHeadTracking", False)		aPlayer2.MoveTo(aPlayer2, fOffsetX, fOffsetY, 0);	ElseIf IsKeyPressed(iBackwardHotkey)	EndIf	If IsKeyPressed(iRotateLeftHotkey)		aPlayer2.SetAngle(aPlayer2.GetAngleX(), aPlayer2.GetAngleY(), aPlayer2.GetAngleZ() - 30)	ElseIf IsKeyPressed(iRotateRightHotkey)		aPlayer2.SetAngle(aPlayer2.GetAngleX(), aPlayer2.GetAngleY(), aPlayer2.GetAngleZ() + 30)	EndIf	If bIsAttackHotkeyPressed != IsKeyPressed(iAttackHotkey)		bIsAttackHotkeyPressed != bIsAttackHotkeyPressed		If abIsAttackHotkeyPressed			akPuppet.SetAlert(True)			  If akPuppet.GetEquippedItemType(0) == 7				Debug.SendAnimationEvent(akPuppet, "BowAttackStart")			  EndIf			Debug.SendAnimationEvent(akPuppet, "AttackStart")		EndIf	ElseIf bIsPowerAttackHotkeyPressed != IsKeyPressed(iPowerAttackHotkey)		bIsPowerAttackHotkeyPressed != bIsPowerAttackHotkeyPressed		If bIsPowerAttackHotkeyPressed			aPlayer2.SetAlert(True)			Debug.SendAnimationEvent(aPlayer2, "AttackPowerStartInPlace")		EndIf	ElseIf bIsSneakHotkeyPressed != IsKeyPressed(iSneakHotkey)		bIsSneakHotkeyPressed = !bIsSneakHotkeyPressed		If bIsSneakHotkeyPressed			bSneak = !bSneak			If bSneak				Debug.SendAnimationEvent(akPuppet, "SneakStart")			Else				 Debug.SendAnimationEvent(akPuppet, "SneakStop")			EndIf		EndIf	ElseIf IsKeyPressed(iInventoryHotkey)		aPlayer2.SetPlayerTeammate(True, False)		aPlayer2.OpenInventory(True)	ElseIf IsKeyPressed(iStatsHotkey)		Debug.MessageBox(" Health: " +aPlayer2.GetAV("Health") as Int +" Magicka: " +aPlayer2.GetAV("Magicka") as Int \		+" Stamina: " +aPlayer2.GetAV("Stamina") as Int +" Alchemy: " +aPlayer2.GetAV("Alchemy") as Int \		+" Alteration: " +aPlayer2.GetAV("Alteration") as Int +" Block: " +aPlayer2.GetAV("Block") as Int \		+" Conjuration: " +aPlayer2.GetAV("Conjuration") as Int +" Destruction: " +aPlayer2.GetAV("Destruction") as Int \		+" Enchanting: " +aPlayer2.GetAV("Enchanting") as Int +" HeavyArmor: " +aPlayer2.GetAV("HeavyArmor") as Int \		+" LightArmor: " +aPlayer2.GetAV("LightArmor") as Int +" LockPicking: " +aPlayer2.GetAV("LockPicking") as Int \		+" Archery: " +aPlayer2.GetAV("MarksMan") as Int +" Illusion: " +aPlayer2.GetAV("Illusion") as Int \		+" OneHanded: " +aPlayer2.GetAV("OneHanded") as Int +" PickPocket: " +aPlayer2.GetAV("PickPocket") as Int \		+" Restoration: " +aPlayer2.GetAV("Restoration") as Int +" Sneak: " +aPlayer2.GetAV("Sneak") as Int \		+" TwoHanded: " +aPlayer2.GetAV("TwoHanded") as Int)	EndIf	RegisterForSingleUpdate(0.1)EndEvent
Sneak works for sure, but I didn't test the others.

As a MagicEffectScript:
Spoiler
ScriptName InputEffectScript extends ActiveMagicEffectInt iAttackHotkey = 46 ; 'C'Int iBackwardHotkey =  208; Down ArrowInt iForwardHotkey = 200 ; Up ArrowInt iRotateLeftHotkey = 203 ; Left ArrowInt iRotateRightHotkey = 205 ; Right ArrowInt iInventoryHotkey = 48 ; 'B'Int iPowerAttackHotkey = 47 ; 'V'Int iSneakHotkey = 24; 157 ; R-CtrlInt iStatsHotkey = 49 ; 'N'Event OnEffectStart(Actor akTarget, Actor akCaster)	ControlActor(akTarget) ; <-- Or whoever is to be akPuppetEndEventFunction ControlActor(Actor akPuppet, Bool abControl = True, Bool abSneak = False, Bool abIsAttackHotkeyPressed = False, Bool abIsSneakHotkeyPressed = False, Bool abIsPowerAttackHotkeyPressed = False, Float fAngleZ = 0.0, Float fOffset = 50.0, Float fOffset2 = -75.0, Float fOffsetX = 0.0, Float fOffsetY = 0.0)	While abControl	 	If Input.IsKeyPressed(iForwardHotkey)			fAngleZ = akPuppet.GetAngleZ()			fOffsetX = fOffset * Math.sin(fAngleZ)			fOffsetY = fOffset * Math.cos(fAngleZ)			akPuppet.SetAnimationVariableBool("bHeadTracking", False)			akPuppet.MoveTo(akPuppet, fOffsetX, fOffsetY, 0)	;	ElseIf Input.IsKeyPressed(iBackwardHotkey)		EndIf		If Input.IsKeyPressed(iRotateLeftHotkey)			akPuppet.SetAngle(akPuppet.GetAngleX(), akPuppet.GetAngleY(), akPuppet.GetAngleZ() - 30)		ElseIf Input.IsKeyPressed(iRotateRightHotkey)			akPuppet.SetAngle(akPuppet.GetAngleX(), akPuppet.GetAngleY(), akPuppet.GetAngleZ() + 30)		EndIf		If abIsAttackHotkeyPressed != Input.IsKeyPressed(iAttackHotkey)			abIsAttackHotkeyPressed != abIsAttackHotkeyPressed			If abIsAttackHotkeyPressed				akPuppet.SetAlert(True)			  	If akPuppet.GetEquippedItemType(0) == 7					Debug.SendAnimationEvent(akPuppet, "BowAttackStart")			  	EndIf				Debug.SendAnimationEvent(akPuppet, "AttackStart")			EndIf		ElseIf abIsPowerAttackHotkeyPressed != Input.IsKeyPressed(iPowerAttackHotkey)			abIsPowerAttackHotkeyPressed != abIsPowerAttackHotkeyPressed			If abIsPowerAttackHotkeyPressed				akPuppet.SetAlert(True)				Debug.SendAnimationEvent(akPuppet, "AttackPowerStartInPlace")			EndIf		ElseIf abIsSneakHotkeyPressed != Input.IsKeyPressed(iSneakHotkey)			abIsSneakHotkeyPressed = !abIsSneakHotkeyPressed			If abIsSneakHotkeyPressed				abSneak = !abSneak				If abSneak					Debug.SendAnimationEvent(akPuppet, "SneakStart")				Else					Debug.SendAnimationEvent(akPuppet, "SneakStop")				EndIf			EndIf		ElseIf Input.IsKeyPressed(iInventoryHotkey)			akPuppet.SetPlayerTeammate(True, False)			akPuppet.OpenInventory(True)		ElseIf Input.IsKeyPressed(iStatsHotkey)			Debug.MessageBox(" Health: " +akPuppet.GetAV("Health") as Int +" Magicka: " +akPuppet.GetAV("Magicka") as Int \			+" Stamina: " +akPuppet.GetAV("Stamina") as Int +" Alchemy: " +akPuppet.GetAV("Alchemy") as Int \			+" Alteration: " +akPuppet.GetAV("Alteration") as Int +" Block: " +akPuppet.GetAV("Block") as Int \			+" Conjuration: " +akPuppet.GetAV("Conjuration") as Int +" Destruction: " +akPuppet.GetAV("Destruction") as Int \			+" Enchanting: " +akPuppet.GetAV("Enchanting") as Int +" HeavyArmor: " +akPuppet.GetAV("HeavyArmor") as Int \			+" LightArmor: " +akPuppet.GetAV("LightArmor") as Int +" LockPicking: " +akPuppet.GetAV("LockPicking") as Int \			+" Archery: " +akPuppet.GetAV("MarksMan") as Int +" Illusion: " +akPuppet.GetAV("Illusion") as Int \			+" OneHanded: " +akPuppet.GetAV("OneHanded") as Int +" PickPocket: " +akPuppet.GetAV("PickPocket") as Int \			+" Restoration: " +akPuppet.GetAV("Restoration") as Int +" Sneak: " +akPuppet.GetAV("Sneak") as Int \			+" TwoHanded: " +akPuppet.GetAV("TwoHanded") as Int)		EndIf	EndWhileEndFunction
User avatar
Julie Serebrekoff
 
Posts: 3359
Joined: Sun Dec 24, 2006 4:41 am

Post » Thu Jun 21, 2012 10:36 am

Thanks Justin,

I'm trying it now. I'll see how it works.

Also, I'm going to replace the OnInit() with OnEffectStart(). To add, I'm going to attach an If condition to check if the Target NPC has the P2Keyword, singling this effect to an exact NPC.


Scratch that. I don't really work with Quests. Can you tell me a barebones way to get this method tested?

Whelp, I made a quest checked "begin on game start", added the script, hit OK, and the CK froze. Hmm...

Haha well I just made a quest (finally), and none of the keys work... My brain hurts...

Moop.
User avatar
Teghan Harris
 
Posts: 3370
Joined: Mon Mar 05, 2007 1:31 pm

Post » Thu Jun 21, 2012 2:29 pm

Well, try the ActiveMagicEffect version I added? The While loop is actually more responsive than 0.1 updates it seems. The quest script works (tested it and the sneak hotkey was responfding appropriately at least).
User avatar
Lizbeth Ruiz
 
Posts: 3358
Joined: Fri Aug 24, 2007 1:35 pm

Post » Thu Jun 21, 2012 9:21 am

Yeah I got the script to work. Turns out I forgot to use SKSE Loader. Simple mistake. Anyways, the script seems to be a little more responsive than a While Loop. I think I'm just going to wait till the OnKeyDown() event because It would still miss some Key Presses. Thanks for the script though.

Moopus.
User avatar
Enny Labinjo
 
Posts: 3480
Joined: Tue Aug 01, 2006 3:04 pm

Post » Thu Jun 21, 2012 8:21 pm

If you are experiencing slow response times when using a simple while-loop like the above, your problem is most likely NOT your script. In fact, while-loops tend to run TOO fast, causing CTD sometimes on high-end systems. I would suggest placing a wait(0.03) just before the endWhile... this way it'll run as fast as you want, but never TOO fast. (experiment with the actual wait number... you may be able to get away with something even slower, given you find what's currently slowing it down)

It sounds like the problem may be with other mods you are running... check your Papyrus log. If it's a mile long, that's your answer... fix the other mods' errors (or disable those erroneous mods) and the above script should run fast as lightning. I suppose it's also possible that a low fps rate is the problem... anything below 30fps will cause intense Papyrus scripting to lag horribly. So if THAT'S your problem, try setting your detail levels lower... just to try it out.

http://www.gamesas.com/topic/1370110-impact-of-system-stress-scripting-errors-on-game-performance/
User avatar
Veronica Martinez
 
Posts: 3498
Joined: Tue Jun 20, 2006 9:43 am

Post » Thu Jun 21, 2012 3:28 pm

If you are experiencing slow response times when using a simple while-loop like the above, your problem is most likely NOT your script. In fact, while-loops tend to run TOO fast, causing CTD sometimes on high-end systems. I would suggest placing a wait(0.03) just before the endWhile... this way it'll run as fast as you want, but never TOO fast. (experiment with the actual wait number... you may be able to get away with something even slower, given you find what's currently slowing it down)

It sounds like the problem may be with other mods you are running... check your Papyrus log. If it's a mile long, that's your answer... fix the other mods' errors (or disable those erroneous mods) and the above script should run fast as lightning. I suppose it's also possible that a low fps rate is the problem... anything below 30fps will cause intense Papyrus scripting to lag horribly. So if THAT'S your problem, try setting your detail levels lower... just to try it out.

http://www.gamesas.com/topic/1370110-impact-of-system-stress-scripting-errors-on-game-performance/

Haha oh my god I love you! Thanks a ton! Sped up the responsive-ness considerably.
User avatar
Taylrea Teodor
 
Posts: 3378
Joined: Sat Nov 18, 2006 12:20 am

Post » Thu Jun 21, 2012 6:48 pm

Cool. Still be aware that it may be firing TOO fast now, as explained above. If that's the case, it would interfere with other scripts; or possibly cause drama on systems that are able to run it a million times per nanosecond (give or take.. heheh). The wait(0.03) I suggested is fast enough to do it once per humanly visible frame... anything faster, I'm not sure what the purpose would be.
User avatar
Gaelle Courant
 
Posts: 3465
Joined: Fri Apr 06, 2007 11:06 pm


Return to V - Skyrim