ID:177236
 
This question has probably been asked a million times before, but when should you use usr instead of src, and vice versa? Is there a difference in funtioanality? My games seem to work ok, but I think I use usr when I should be using src. Is there some problems this may cause that I am not noticing?
OneFishDown wrote:
This question has probably been asked a million times before, but when should you use usr instead of src, and vice versa? Is there a difference in funtioanality? My games seem to work ok, but I think I use usr when I should be using src. Is there some problems this may cause that I am not noticing?

It's very insightful that you asked this question; a lot of people don't really give it a second thought, and they should. There are lots of problems the misuse of usr can cause, many of them subtle; many won't show up at all until a multiplayer test.

In a nutshell: usr is set whenever a player performs an action, and it's valid for the duration of the verb (or other action like a login or mouse movement). It's actually a local var that gets passed invisibly to each verb or proc that gets called as a result of a player action. src, on the other hand, is simply the object that owns a particular proc. In a lot of cases src and usr might end up being the same.

One example is movement procs: Most of the time when Move() is called, it's because you moved your character yourself; usr==src in this case. But if some other proc calls Move() for your mob, then usr may be another player or null. In Move(), src is always correct, and usr is sometimes wrong.
In turf/Entered(), which is called by Move(), usr can be wrong too. If you didn't move yourself, usr will be something else. src is the turf, though; the correct thing to use is the first argument to the proc. (Entered() takes two arguments: The thing that moved, and where it was last. Most people don't need the second argument for anything.)

In mob/Logout() or client/Del(), a player might have disconnected on purpose (which would set usr), or an admin might have kicked them out. usr is unreliable here.

There are a few rules of thumb with usr:

  • If src is correct, use src.
  • Never ever put usr in a movement proc like Move(), Entered(), Bump(), etc.
  • Never put usr in a proc unless you're absolutely sure it's correct; verbs are okay. Procs that are only ever called by verbs are okay too.
  • Only a few procs support usr: mob/Stat(), mob/Login(), and a couple others; that's because they're called as a result of client actions. Click() is a verb, as are some similar mouse routines. (Just for clarification: In Stat(), usr is always the person looking at the statpanel. src is client.statobj and can be set to something else if you want, but by default it's the same as usr.)
  • If you're not sure if usr is right, but you know src is something else, see if you can provide more information to your proc, or if you already have that info available. For example, some people use usr in Entered() when they should be using the first argument instead. If you have usr all over DeathCheck(), make it DeathCheck(M) and use M (if it's a mob).

    My next Dream Tutor article in the pipeline is on exactly this topic. It'll go up probably in a week or two once some more BYONDscape articles have intervened.

    Lummox JR
In response to Lummox JR
Generally, usr is the only way to refer to the player when using a verb that belongs to a seperate atom as well. For example:

<code>obj/verb/Get() set src in usr.loc src.Move(usr) usr << "You get [src]."</code>

Unless you know something I don't, there isn't any way to do that without using the usr variable.
In response to Foomer
Foomer wrote:
Generally, usr is the only way to refer to the player when using a verb that belongs to a seperate atom as well. For example:
<code>obj/verb/Get() set src in usr.loc src.Move(usr) usr << "You get [src]."</code>> Unless you know something I don't, there isn't any way to do that without using the usr variable.

Correct, but I specifically said usr is okay in verbs. That's where it's meant to be used, after all.

Lummox JR
In response to Lummox JR
Those types of verbs specifically are the ones where it is okay, an required to use usr. Since normal verbs, for example, a Say() verb, can be called just like a normal proc, it could cause problems if those verbs used usr. It's still better to use src in verbs that don't require usr.
In response to Foomer
Foomer wrote:
Those types of verbs specifically are the ones where it is okay, an required to use usr. Since normal verbs, for example, a Say() verb, can be called just like a normal proc, it could cause problems if those verbs used usr. It's still better to use src in verbs that don't require usr.

It should be okay in all verbs, actually; src is merely easier when it's known to be the same as usr.

Lummox JR
In response to Lummox JR
How about this. Suppose you make a simple Say() verb like this:

<code>mob/verb/Say(message as text) usr << "You say, \"[message]\"" ohearers() << "[usr] says, \"[message]\""</code>

But now, you go and make yourself an admin verb that allows you to force another player to say something.

<code>mob/verb/ForceSay(mob/M as mob in view(), message as text) usr << "You force [M] to speak." M.Say(message)</code>

Since the admin used in the ForceSay verb, usr is going to be the admin in the Say() verb. That means when it will appear as if the admin said the message, not the targetted mob. If src was used instead, that wouldn't have been a problem.
In response to Foomer
Foomer wrote:
How about this. Suppose you make a simple Say() verb like this:
<code>mob/verb/Say(message as text) usr << "You say, \"[message]\"" ohearers() << "[usr] says, \"[message]\""</code>>
But now, you go and make yourself an admin verb that allows you to force another player to say something.
<code>mob/verb/ForceSay(mob/M as mob in view(), message as text) usr << "You force [M] to speak." M.Say(message)</code>> Since the admin used in the ForceSay verb, usr is going to be the admin in the Say() verb. That means when it will appear as if the admin said the message, not the targetted mob. If src was used instead, that wouldn't have been a problem.

I see what you're getting at, but this is sort of fishing for an exception; what you're doing here is using the verb as a proc, and so essentially you've taken a valid case for usr and forced it into an invalid state. When a verb is being treated like a proc, it loses its validity as a verb for the purposes of usr. Essentially the reason for the rule of thumb that usr should be in verbs but not procs is that verbs are the immediate response to client input, whereas a proc is usually initiated in a way that's several steps removed (and may not be due to client input at all).
Conceivably an admin might want to force someone to do any kind of verb, and the same problem you brought up would apply. There are two ways around this that I'd consider robust (not more so than using src, in this exact case, but as a general solution applying to all verb cases):

  • Make Say() and ForceSay() call a separate proc that handles the actual output, bypassing the problem with usr through the way the call is structured.
  • Use call() to call Say() with a forced usr.

    Lummox JR
In response to Lummox JR
Regardless, it removes all possible problems if src is used instead of usr. So my general rule is to use src for everything, unless the occasion requires the usr be used.