Talk:GetSelf

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search

Copied the sections from modding terminology as the info on dynamic items is quite counter intuitive - not sure what "getSelf applied to a mod based item will always return the original formid of the item" means though - does it mean that a non dynamic reference will always return its formID even if in inventory ? please someone clarify this one. UDUN 18:51, 7 June 2010 (EDT)

It means that, as opposed to a dynamic item that gets a new FormID, a mod based (or non-dynamic) item always gets the same, original FormID each and every time it is picked up and dropped. While in inventories both as equally FormID-less (?!)
While a non-dynamic item is in an inventory, not only GetSelf returns 0, but any Ref variable containing its FormID will artificially (and temporarily) be set to 0 as well.
I added a couple of notes to the article QQuix 18:37, 8 June 2010 (EDT)
Thanks QQuix  :)- While a non-dynamic item is in an inventory GetSelf returns 0, good to know - thanks ! UDUN 09:58, 10 June 2010 (EDT)


Unreliability with Player[edit source]

Scruggs: To clarify the issue with using getSelf on the player, in the following piece of code:

if ( getSelf != player && getSelf != playerRef )
  message "I am not the player!"
endif

...occassionally the message will be displayed even when the script is run on the player. A workaround for this is to use the code:

if ( getDistance player > 0 )


Any examples when this actually happens? "Occassionally" is a bit vague. Perhaps instead of that generic code above show us the script that actually had that bug?--JOG 13:50, 14 July 2006 (EDT)
Scruggs: "Occassionally" is a bit vague, but the issue is a bit vague, too. I'm speaking in terms of magic effect scripts. The generic code above is used as written in several of my scripts (with various text for the debug message), and all of them at some point have affected my character regardless. When using the getDistance workaround, with no other changes to the script, I have never had the problem occur. I apologize for not being able to explain why the issue occurs, but I can verify that it does.
To find out why is Bethesda's problem the when is the point, without the when, Bethesda will never fix this problem, because they can't reporduce it; I can't either. Magic effects is already one step closer, though it still could be an issue with the area of effect not being 0 or something similar. --JOG 03:09, 15 July 2006 (EDT)
Scruggs: Okay, I'll try to clarify further. I've made several spells in different mods which are cast by activators, either directly at the player or at a different actor. These spells have a radius effect. In cases where I don't want the spell to affect the player, the scriptEffectStart block uses this code:
begin scriptEffectStart
  set targetRef to getSelf
  if ( targetRef != player && targetRef != playerRef )
    message "Target Acquired / Valid Target / Other debug text"
    set validTarget to 1
  else
    dispel spellID
  endif
 end

 begin scriptEffectUpdate
   if ( validTarget )
     ; do stuff that will only affect valid targets
     message "I'm doing stuff."
   endif
 end
The vagueness of the above script is necessary because it illustrates a general issue with various scripts that follow the same form. The issue is, with the use of getSelf and the variable validTarget, there should be no possibility of the player being affected by the spell. As an example, in one script the "do stuff" section adds a potion to the target and then equips it. Given the conditions used, can you think of any reason why the script will sometimes cause my character to equip the potion, other than an issue with the getSelf function or the definition of the player reference?
I'm not the first to notice this issue, either. One discussion on the forums is here: [1]
ShadowDancer 10:31, 15 July 2006 (EDT): Why not just do what Bethesda does? Which is to make the player immune to that magic for the duration of the spell.
You can see this solution in the enchantments UniqueScrollEnStorms, UniqueScrollEnFireNexus, and probably a couple of the others where the area effect would include the player.
Additionally, wouldn't it just be easier to check the TargetRef against Player.GetSelf?
It seems to me that this code is broken. To me it reads that when the script is started, it checks for validation and validation always occurs during the ScriptEffectUpdate block, even if the TargetRef becomes changed. I would honestly have to see the whole coding of the script to say whether or not that happens.
Scruggs: Bethesda's solution is fine for ordinary spell effects, but not for scripted effects. Checking against player.getSelf may well work, but since I'm specifically having issues with using getSelf on the player, I don't trust it to work reliably. It seems more likely that it's not an issue with getSelf per se, as with the reference for the player, which doesn't seem to be defined in the way other references are. See the last post in this topic.
The code is fairly straightforward: When the script first runs, it sets validTarget to 1 only if the target is not the player. Subsequently, the rest of the script only runs if validTarget == 1. The targetRef variable is only used in the scriptEffectStartBlock, which only runs once. The script can be used as written, and will demonstrate this issue, at least in my copy of Oblivion.
ShadowDancer 11:53, 15 July 2006 (EDT): I would think that a 100% magic resistance on self would work nicely to keep the effect from operating on the character (unless you have Script Effect Always Applies checked on the spell). As for the GetSelf being buggy, I honestly haven't run into a problem with it. Then again, I haven't used a if ( targetRef != player && targetRef != playerRef ) either. To me that is the part that seems the most likely to be buggy, especially with the && in there. If either of those variables is false, the player is considered a valid target. What exactly is playerRef. I don't see it defined anywhere and I can't find it on the Wiki. The other thing is that the way that the parenthesis are used could possibly be causing problems (its happened before) and they aren't necessary for this script. My personal opinion is that If TargetRef != Player.GetSelf should be used instead of if ( targetRef != player && targetRef != playerRef ). To me this script looks like it is overly complicated and that is usually where the issues crop up.
Out of curiousity, why are you running the rest of the script in the ScriptEffectUpdate anyway?
OK, I just followed the last link to the topic. PlayerRef is a runtime variable that may or may not be set according to what is stated in that topic. That is most likely your issue in my opinion and if it were me, I would remove that from your if statement so that it just reads as If TargetRef != Player. I bet that will solve the issues you are having. Put a ; in front of the if statement and use the line above right below it. Worst case, you have to go back and take it out of one spell.
Scruggs: You're probably right that the && could easily throw it off. The thing is, I've used various versions of this code - checking for playerRef or player only, or checking for a positive match rather than a negative. PlayerRef is used interchangeably with Player by Bethesda, although player is used more frequently.
The script in this link seems to confirm the issue I'm having - in that case, the only other possibility would be your suggestion that the parentheses are interfering somehow. I'll have to look through the scripts I'm using. If it turns out to be an issue with the code and not the function, I'll remove the note from the page.
If your test-scripts are radius effect cast by an activator then they will run on the activator as well, and a debug-message might fool you.--JOG 12:47, 15 July 2006 (EDT)
Scruggs: Possibly, but having other effects (like drinking a potion) run on the player is a clear indication that something else has gone wrong. For the sake of preventing this discussion from becoming a column of single characters on the right-hand side of the page, I'm going to run some test scripts. I'll post the results here. (Thanks for the input, by the way).
ShadowDancer 13:14, 15 July 2006 (EDT): No prob. I created an area effect spell to add potions to everyone in the area and I could not duplicate the issue so something else must be going on. I even had a bunch of actors around and couldn't duplicate it using my version of the script. It might be something that only happens in certain situations, or it might be that the TargetRef gets messed up someplace in the middle of running. It adds some 130 or so potions though when I do it in the ScriptEffectUpdate block. Maybe it has something to do with the number of items added? The other possibility is that you should just use GetSelf in the if statement along the lines of If GetSelf != Player to bypass the issue. Thats what the other guy did rather than setting a variable to it.

Dragoon Wraith TALK 13:34, 16 July 2006 (EDT): (return to left) (Scruggs, please sign your posts, use ~~~~) I have a script like this:

ref self

[...]

Begin ScriptEffectStart

  set self to GetSelf
  if ( self == player )
    Dispel, "spell's ID"
  endif

[...]

End

And I have never had any problems with it. The upper right-hand corner will flash the "Burden" icon briefly, before the spell is dispelled, but other than that, it works perfectly.

Regarding this piece of code:

if ( targetRef != player && targetRef != playerRef )

That's exactly how that should be written. ( targetRef != player || targetRef != playerRef ) would always be true, because if it was one of those, it would not be the other. My personal preference for parentheses (Oblivion doesn't care as far as I know) for it would be this:

if ( targetRef != player ) && ( targetRef != playerRef )

By the way, does anyone know how the order of operations works with logical operators?

Finally, as for immunizing the player to the spell, I really don't think that's a very clean solution. It is entirely possible for the player to be hit with another spell during the duration of the immunity, which causes an unwanted side-effect.

ShadowDancer 13:47, 16 July 2006 (EDT): I agree about the unwanted side effect. It wouldn't be my first choice on how to handle the situation either. It is how Bethesda chose to deal with area effect damage with the player in that area however. They didn't give 100% magic resistance, but they did make the player immune to the particular type of magic being used (fire, shock, etc) for 2 seconds longer than the spell's damage component duration. I agree that the scripting is correct, however that doesn't explain the reason for the glitch. I am not sure we will ever be able to fully define why the glitch happens from outside of the game's coding. I was trying to offer what seemed like the most probable place for the glitch to occur in the scripting and possible ways to bypass it. My personal preference for parenthesis, if I use them, is the same as yours too.
JOG: The order of operations is described in the If-Page: same as everywhere: first "OR" then "AND". As for the GetisID problem, I still think it's caused by either the spell affecting something else than the player or some strange issue with playerRef
Dragoon Wraith TALK 19:30, 16 July 2006 (EDT): Thank you, JOG, I'd missed that.

Using GetIsReference player solves the above problem. Scruggs 16:52, 12 February 2007 (EST)


Quest Scripts[edit source]

Quick question, does this function return quest id's if called in a quest script? Seems a bit abstract so I wanted to make sure. --Moses 01:13, 14 July 2010 (EDT)

No. Quests do not have references, therefore there would be nothing for GetSelf to return, because GetSelf only returns references. I cannot imagine any situation where you would need to do that, though. What are you trying to do?
PS. The distinction between references and base objects is really important in modding. That's one you want to clarify on if you're confused.
Dragoon Wraith TALK 09:57, 14 July 2010 (EDT)
Didn't know quests don't have references. The reason I was asking is because I've got a quest script that's copied multiple times with different settings on each copy. After it runs through it stops the quest and I was wondering if I could return the quest with a getself that way I wouldn't have to go to the end of the script and change which one it disables every time I make a new copy of the script. Also, I know the difference between the two. I just thought they might be able to return a reference. --Moses 15:49, 14 July 2010 (EDT)
I feel like there simply must be an easier way to do what you want. And I have to admit that I'm rather skeptical about you understanding the differences between references and base objects if you thought Quests might have them - references are always actual, 3d instances of an object that you can see and interact with in-game. Anything abstract (like a quest or a magic effect or a faction) does not have any references.
Dragoon Wraith TALK 19:25, 14 July 2010 (EDT)
Base objects are, well just that, the object you edit in the construction set to set it's base variables. They define the traits and variables of all references of them placed in the game. When you change a weapons model it changes it for all references of that weapon because they draw their model path from it. References aren't instances of their base object because they can contain variables such as health and attack damage unique to that reference, but they still share traits with their base object. References are used for any object that can appear more than once in the game world. This part I didn't think about when I posted so that was bad on my part.
--Moses 21:38, 14 July 2010 (EDT)
Barring some technical meaning of "instance" here, I disagree with your assessment. A reference is an instance of a base object - though it does add on additional information that is unique to that reference. In object oriented programming (which is basically what the entire game is), I suppose you could state that each reference is an instance of a subclass of the base object, but that seems pedantic, and in reality it's more likely that they're the same class and the base object merely sets the static members of the class while the reference handles the others.
Dragoon Wraith TALK 01:22, 15 July 2010 (EDT)
The only reason I put that an instance is different from a reference is because the usage of those terms I'm familiar with is in 3ds Max. In it an instance is a complete copy of an object and whatever you do to it will be done to the original and vice versa. A reference is different though. Once a reference is created the reference can have things done to it and not affect the original as long as they're placed higher on the modifier stack. --Moses 04:43, 15 July 2010 (EDT)
Different systems have different terminology. I was using Oblivion's.
Dragoon Wraith TALK 11:44, 15 July 2010 (EDT)
But I am telling you, and trust me, I know, every reference is always a 3d object visible in the actual game. Or, not visible, if it doesn't have a mesh, but by definition, the extra data of a reference is related to its current position, rotation, and in-game status. Being something that is actually placed into the Render Window is what makes something a reference.
Dragoon Wraith TALK 01:22, 15 July 2010 (EDT)
Can you not simply store the appropriate settings in variables, and then have a script that checks whatever conditions are appropriate and sets the variables as you need them set so that the same script can be used for all of them?
Dragoon Wraith TALK 19:25, 14 July 2010 (EDT)
Long story short. No, I can't. It's meant to be used an unknown amount of times by an unknown amount of mods so it has to be something that is user friendly and self contained. It sets about 29 variables (strings, arrays, refs, real numbers) to specific slots in another array.
The closest thing I can do is change it to an object script, attach it to something, add it to the players inventory, and have it do a RemoveMe. But even then I'd need a quest script to add it to the players inventory to begin with since the player isn't supposed to even know it's there. My mod is a gun system so it's more of a resource then an actual mod. Modders take the ammo generation script (the script we're talking about), copy and modify the settings for a new ammo type, and save it into a different plugin linked to the "master" gun system. They load both up and it supplies the master system with the needed data. The ammo script needs to be something that initializes once the gun it's used in becomes initialized. This is also true for the guns, but the guns initialize once an actor acquires one so it's nothing to worry about.
--Moses 21:38, 14 July 2010 (EDT)
Hmm, OK, I can see that. An object added to the player wouldn't help, by the way - those don't have references, either (note: an object in an inventory is not out in the game world - hence, no reference, only a list of base objects with a parallel list of "extra data" for things like health and script state) - though if you use OBSE, GetBaseObject could work (and now that I think about it, might work with quests, too - worth trying, anyway).
I'll have to try that. Going to set up a small test right now to see if it returns anything.Also, I wasn't saying that objects in inventories have references. I said I could remove them with RemoveMe which would stop the script as well. Also, this mod heavily relies on OBSE functions and Pluggy for arrays to store data in. I mean H E A V I L Y --Moses 04:43, 15 July 2010 (EDT)
Just tried it and apparently trying to return the base object of something that is already a base object crashes the script. I might as well leave it as it is or take the stopquest command out because now that I think about it, if a mod installed were to call DestroyAllArrays it would COMPLETELY eradicate all the saved data in the arrays and they'd need to be rebuilt. It could all be done within a frame or 2 but any custom ammo that a player might make would be erased and the actual ammo objects would become expensive clutter. As of right now though that's the only mod conflict I can think of.
Yeah, the notes on the page suggested as much, but couldn't be sure til you tried. *shrug* Anyway, as far as I can tell, DestroyAllArrays does not exist, nor should it...
Dragoon Wraith TALK 11:44, 15 July 2010 (EDT)
DestroyAllArrays The espID still has to be specified but in the worst case scenario this could be like running a semi through a just built house. I had code in place to clean it all up and rebuild them but there were a lot of new features I added and had to remove the cleanup code because it no longer worked right. I'll add them back when my code stops adjusting so much. The only problem I have though is that every ammo type creates a new object to be saved to the save file for each bullet that could be in the ammo clip. An 8 round pistol clip creates 8 new objects and each one represents a partially filled clip if you take it out of the gun and put a fresh one in. They don't pool together into full clips like in every fricken shooter I've ever played in my life. You can auto combine them into the best possible combination by resting though. But yeah, got any idea for how I can retrieve/delete those lost references if the arrays were ever destroyed? It'd cause savegame bloat in no time if it were to continue for too long.
I didn't realize you were using Pluggy arrays. Why not use OBSE arrays? That function doesn't exist for them and it automatically handles destructing arrays as they're no longer needed.
Dragoon Wraith TALK 13:00, 15 July 2010 (EDT)
Because I read up on OBSE arrays a bit and it seemed fine until I saw how it handles them inside usermade functions. Since I have a LOT of code that's duped I've stored a lot of it in external functions. As it says in the documentation "A note about local variables within functions: when the function terminates, all local variables are reset to zero. Local array variables are automatically cleaned up so there is no need to use ar_Null to reset them". It ALSO says Local string variables AREN'T cleaned up automatically but it says NOTHING about Local array variables. Correct me if I'm wrong but that sounds like no arrays will survive after the function call returns :/ --Moses 14:14, 15 July 2010 (EDT)
Not sure on the details there, but it'd be worth asking about. But if all-else fails, you could always either return the array itself - I'm sure that means OBSE will pass it to where you want it - or take the array as an argument, modify it, and then it won't have been declared inside the function, it will have been declared outside the function and modified by it, so it will persist. This is similar to the C++ concept of pointer/passed-by-reference arguments, and is a pretty tried-and-true scheme for dealing with scope issues. OBSE itself uses this quite often (as in, every single function call ever uses it, since the functions in OBSE actually just return true; when they're done - a pointer to a double is instead passed as a function, and the return value of the function is stored in that double.
Overall, I'd ask in the thread about this - Scruggs has no doubt considered this issue and provided a response to it.
Dragoon Wraith TALK 14:27, 15 July 2010 (EDT)
Anyway, couldn't you just pass those records to your Plugin as you create them? I mean, I assume you're using CloneForm - it returns a FormID that you can put into your array, and then delete it as necessary. No need to get involved in the actual script that's calling it as long as that script gives you everything you need.
Dragoon Wraith TALK 13:00, 15 July 2010 (EDT)
Actually I think I know what I'll do is set the Protected boolean on the array containing all the references to true so that even if the array containing the pointer to it is destroyed IT won't be. As long as the quest script is running it can check to see if the refs array already exists or if it needs to be created for the first time. This way I can avoid savegame bloat and ammo becoming useless. What do you think? --Moses 14:14, 15 July 2010 (EDT)
Not familiar enough with Pluggy arrays to say, honestly. I much prefer the OBSE arrays, they work much more simply.
Dragoon Wraith TALK 14:27, 15 July 2010 (EDT)
Out of curiosity, why do you need to be able to get the quest itself, then? Couldn't the code just report all relevant values without you knowing which quest they were coming from?
Dragoon Wraith TALK 01:22, 15 July 2010 (EDT)
Ok, the only reason I wanted to return the quest is to have the little command at the end of the script stop the quest without users of my mod having to remember to go down to the bottom and change it to the right name. That way there isn't a bunch of people's ammo scripts running in the background even if they return early due to having already completed their purpose. --Moses 04:43, 15 July 2010 (EDT)
I applaud your dedication to clean programming here, but honestly you could have thousands of scripts like that, and it wouldn't affect Oblivion's performance. I wouldn't worry about it.
Dragoon Wraith TALK 11:44, 15 July 2010 (EDT)
PPS. Please use ~~~~ to sign comments. I've done that for you here.
Dragoon Wraith TALK 09:57, 14 July 2010 (EDT)
Sorry about that, It was about 5am here when I wrote that and I dont work well when I'm tired.
--Moses 15:49, 14 July 2010 (EDT)

GetSelf glitch[edit source]

If used (1) in an item script and (2) the item is in a container in an exterior cell and (3) the container cell is loaded as the player approaches on foot and (4) GetSelf is used in the very first frame >> the game CTDs.

Notice that those are AND conditions. The game does not CTD if

  • the item is in the world, or
  • the player teleports to the area, or
  • There is a frame delay and GetSelf is used in the second frame after cell load.

All I can guess is that the cell load process is different for teleporting into it (cell load screen and all) and the cells loaded as the player walks around in exterior areas. I guess that when GetSelf is used in the very first frame, somehow, the load process has not finished, causing the CTD.

This is confirmed and reproducible: I created a brand new mod with those conditions. The item script has only one line: "let MyRef := GetSelf (plus a few debugging code, of course) and the CTD happens 100% of the tries.

Bottom line: If you use GetSelf in an item script, make sure you don't use it in the first frame when the cell is loaded. Wrapping the code to run only when the player is within a certain distance should do the work.

QQuix 07:31, 15 May 2011 (EDT)

I think general "best practice" suggestions say to always wrap an item's calls to GetSelf with a if ( GetContainer == 0) call, to make sure it's out in the world. GetSelf cannot return anything meaningful if the item is in a container.
Dragoon Wraith TALK 11:29, 15 May 2011 (EDT)
Yes, and, I am counting on it.
GetSelf returns 0 for items in containers and dynamic items in the world.
In this case, that 0 is meaningful: it is an item script. In the CS, I deployed a few of this item in the world and some in a container. They must behave somewhat different and I use GetSelf to, with a single check, rule out the dynamic ones, whether they are in containers or in the world (in both cases GetSelf returns 0).
The problem was easily fixed with a "GetDistance PlayerRef", which delays the GetSelf execution long enough to avoid the CTD, but GetSelf should not CTD, in the first place.
You are right about the Best Practice, anyway. And, considering how rare this scenario occurs, do you think the note should be removed from the article? (I am not sure, myself) QQuix 18:37, 15 May 2011 (EDT)
Frankly, I'm surprised it's so rare; I thought that was the expected result for GetSelf in a container. Pretty sure Bethesda avoids using it...
I vote the warning can stay.
Dragoon Wraith TALK 19:45, 15 May 2011 (EDT)