ID:1774417
 
(See the best response by 8BitParagon.)
As a good old byond developer I am used to do this alot:
for(var/mob/M in world)//or
for(var/obj/O in world)

And now that I plan to reduce lag on my games I heard that this is a bad way to use for... However I researched in forums and fount other ppl saying the same thing but no solution..

I fount out that this works the same way:
for(var/mob/M)//or
for(var/obj/O)

But I dont know if there are any diffrence...

if both are really the same, should I try to make another way to loop through mob/obj? Like creating a list and adding them at new() would Be better then both options?
Inutaishos wrote:
Like creating a list and adding them at new() would Be better then both options?

Yes. Adding only the objects that you need to a list, assuming that list will be smaller than all objects in the world, will always be more efficient than cycling through every single object in the world. If you'll end up needing every object in the world anyway, though, you'd probably be better off just looping through all of them with for(). Although, I hope that's not the case and that you can narrow down which ones you need in a list.
Neither is more efficient than the other. From the reference:
for list proc

Format:
for (Var [as Type] [in List]) Statement

Args:
Var: A variable to sequentially contain each member of the list.
List: The list to loop through. This defaults to the whole world.
Type: One or more of area, turf, mob, or obj, ORed together. If no type is specified, the declared type of Var will be used to skip over inappropriate elements in the list.

Specifying in world is optional, though including it does help clarify what exactly the loop is doing and what it's iterating through.
Best response
if both are really the same, should I try to make another way to loop through mob/obj?

Like creating a list and adding them at new() would Be better then both options?

Yes. Looping through all objects in the world should be avoided at all costs. If there's a way to avoid it, you should do it.

There's no one-size-fits-all solution to your questions because your question isn't specific enough. Right now, you are asking: "Is there a way to loop through all mobs/objs in the world without looping through all mobs/objs in the world"?" For which the obvious answer is no.

You are going to have to come up with a use-case for me to be able to show you better ways of going about things.


Here's one example of something I see a lot:

for(var/mob/m in world)
if(m.client)
m.loc = locate(1,1,1)


A brief analysis of how this can be improved:

for(var/mob/m in world) //we should be avoiding looping through all mobs in world at all costs
if(m.client) //if we know we are going to need to look up all mobs with clients, we should store them all in a list ahead of time.
m.loc = locate(1,1,1) //if the x, y, and z coordinates are constant for all mobs in the loop, you should store the location in a variable outside of the loop.


Storing the location outside of the loop:
var/loc = locate(1,1,1)
for(var/mob/m in world)
if(m.client)
m.loc = loc


When you initialize objects or grab references to objects via an external proc make sure you do it only as many times as is absolutely necessary. If the reference is going to be reused, but be the same over and over again, keep it in a variable in your code. Don't reinitialize it every time you iterate through the loop.

Now, I also talked about storing the mobs with clients in a list because we needed to access them later. This would be one way of going about that:

var/list/player_mobs = list()

mob
//add any mob with a connected client to a global list
Login()
player_mobs += src
. = ..()

//make sure to remove this from the global list on logout
Logout()
player_mobs -= src
. = ..()

//make sure to check if we're a player when deleting
Del()
if(client)
player_mobs -= src
..()


This would be how I'd go about using it to teleport all players to a specific location:

atom/movable/proc
ForceMove(atom/newloc,dir=0,step_x=null,step_y=null)
/* @ ForceMove(atom|null newloc,[num dir=0,num|null step_x=null,num|null step_y=null])
@ Arguments:
newloc: Set to an atom or null to determine where to move the movable
dir: [optional] set to the new direction the movable will face after moving them
step_x: [optional] omit to leave step_x unchanged, set to a number to change step_x
step_y: [optional] omit to leave step_y unchanged, set to a number to change step_y
@ Returns:
nothing
@ Description:
Forces the movable to move to a new location and calls Exited(), Uncrossed(), Entered(), and Crossed()
as a normal call to Move() would. This function does not call Exit(), Cross(), Enter(), Uncross(),
or Bump() like a call to Move().*/

//store all the atoms this object is currently standing on
var/oturf = src.loc
var/list/oldloc = obounds(src)

//update our location
src.loc = newloc
if(dir)
src.dir = dir
if(step_x!=null)
src.step_x = step_x
if(step_y!=null)
src.step_y = step_y

//get a list of all objects we just started standing on at our new location
var/list/newloc = obounds(src)

//AND the two lists together to get the objects that we were standing on before and after the move
var/list/removed = oldloc&newloc
//remove them from both lists
oldloc -= removed
newloc -= removed

var/turf/t
var/atom/movable/o
//iterate through the old turfs, calling Exited and movables calling Uncrossed
for(t in oldloc)
t.Exited(src,newloc)
for(o in oldloc)
t.Uncrossed(src)
//iterate through the new turfs calling Entered and movables calling Crossed
for(t in newloc)
t.Entered(src,oturf)
for(o in newloc)
t.Crossed(src)
proc
MoveAllPlayers(turf/location,dir=0,step_x=null,step_y=null)
var/list/oldloc
var/list/newloc
//iterate through the player_mobs list calling the ForceMove function
for(var/mob/m in player_mobs)
m.ForceMove(location,dir,step_x,step_y)



Ask more specific questions with code examples and I might be able to give more specific examples of how to improve specific patterns.