ID:253359
 
Keywords: lag
(See the best response by Flame Sage.)
I have a dungeon generator that does just that generates a dungeon. The problem I'm having with it is lag. It takes anywhere from .2 to 12 seconds to actually generate its map. I also used swap maps to create a new map just so it creates a new map just for the custom dungeon but that process finishes almost immediately. In a multi-player situation the lag is processed by EVERYONE or atleast in the tests I've run I have yet to run dream daemon only hosted it through Dream Seeker but the lag is server-sided. Is there a way I can make the lag effect the client alone then well, EVERYONE.
There really is no way to do client-side processing in BYOND right now. There are DLL files which run on the server that potentially could speed up map creation due to having them written in another language, but all of your players are going to experience lag because the SERVER is doing all of the calculations, it handles all that.
Crapsicle. That's my only response. I need SOMETHING that will speed this up. I'll give this a shot on a server and host it and get process times off debug. I'm going to give it a few other attempts I don't want this to generate massive dungeons and make EVERYONE in the world process this lag. I've heard falacy had a dungeon game with a generator and I'm curious to see if he has any information for me on lag reduction.
Proc Name      Self CPU    Total CPU    Real Time        Calls

------------------------------------ --------- --------- --------- ---------

/turf/wall/Enter 0.041 18.540 18.676 1

/dungeon/proc/generate 0.344 18.487 18.623 1

/dungeon/proc/path 17.302 17.827 17.827 14
Best response
Well, without posting the code there's really no way to help you...
In response to Flame Sage
This is based off a library I found (Nearly exactly...) JP.Dungeon_Generator (Or something I believe.) I just edited dantum object names for typing simplicity and things. & There's a little bit of Lummox JR's swap maps hidden in my entered procs so I can create a new z level. If I generate the map this way it takes ~19 seconds of no movement on the clients end to finish complete generation.

turf/wall
icon = 'wall.dmi'
icon_state = "wall"
Enter(mob/M)
if(ismob(M)&&M.client)
var/map="[usr.key][usr.name]-Map"
var/_x=70
var/_y=70
var/_z=1
var/swapmap/Map=new(map,_x,_y,_z)
world<<"[Map.z1]-[Map.z2]"
for(var/turf/T in block(locate(Map.x1,Map.y1,Map.z1),locate(Map.x2,Map.y2,Map.z2)))
for(var/atom/movable/O in T) del(O)
usr << "Map [map] created: ([Map.x1]-[Map.x2],[Map.y1]-[Map.y2],[Map.z1]-[Map.z2])"
for(var/turf/t in block(locate(Map.x1,Map.y1,Map.z1),locate(Map.x2,Map.y2,Map.z2))) new /turf/wall(t)
generate.setArea(locate(Map.x1,Map.y1,Map.z1),locate(Map.x2,Map.y2,Map.z2))
generate.setWallType(/turf/wall)
generate.setFloorType(/turf/ground)
generate.setAllowedRooms(list(/Room/furnished, /Room/fountain, /Room/hall, /Room/deadend))
generate.setNumRooms(5)
generate.setExtraPaths(5)
generate.setMinPathLength(20)
generate.setMaxPathLength(45)
generate.setMinLongPathLength(30)
generate.setLongPathChance(30)
generate.setPathEndChance(30)
generate.setRoomMinSize(3)
generate.setRoomMaxSize(6)
generate.generate()


dungeon
proc
generate(seed=null)
set background = 1
if(!check_params()) return
out_numPaths = 0
out_numLongPaths = 0
var
tempseed = rand(-65535, 65535)
numits
paths
RoomEntry/nextentry
Room/nextroom
list/Room/rooms = list()
list/Region/regions = list()
list/RoomEntry/required = list()
turf/nextloc
minx
maxx
miny
maxy
z
Region/region1
Region/region2
if(seed==null)
out_seed = rand(-65535, 65535)
rand_seed(out_seed)
else
out_seed = seed
rand_seed(seed)
z = corner1.z
minx = min(corner1.x, corner2.x) + roomMaxSize + 1
maxx = max(corner1.x, corner2.x) - roomMaxSize - 1
miny = min(corner1.y, corner2.y) + roomMaxSize + 1
maxy = max(corner1.y, corner2.y) - roomMaxSize - 1
if(minx>maxx || miny>maxy)
out_error = ERROR_BAD_AREA
return
if(usePreexistingRegions)
examined = list()
for(var/turf/t in block(locate(getMinX(), getMinY(), getZ()), locate(getMaxX(), getMaxY(), getZ())))
if(!isWall(t)) if(!(t in examined)) rooms+=regionCreate(t)
for(var/k in allowedRooms)
nextentry = allowedRooms[k]
if(nextentry.required>0) required+=nextentry
var/rooms_placed = 0
while(rooms_placed<numRooms)
if(numits>maximumIterations)
out_error=ERROR_MAX_ITERATIONS_ROOMS
break
nextloc = locate(rand(minx, maxx), rand(miny, maxy), z)
if(!required.len) nextentry = allowedRooms[pick(allowedRooms)]
else
nextentry = required[1]
if(nextentry.count>=nextentry.required)
required-=nextentry
continue
if(nextentry.maxnum>-1 && nextentry.count>=nextentry.maxnum) continue
nextroom = new nextentry.roomtype(rand((nextentry.minsize<0)?(roomMinSize):(nextentry.minsize), (nextentry.maxsize<0)?(roomMaxSize):(nextentry.maxsize)), nextloc, src)
numits++
if(!nextroom.ok()) continue
if(!rooms || !intersects(nextroom, rooms))
nextroom.place()
numits=0
rooms+=nextroom
rooms_placed++
nextentry.count++
border_turfs = list()
for(var/Room/r in rooms)
if(!r.doesMultiborder())
var/Region/reg = new /Region(src)
reg.addTurfs(r.getTurfs(), 1)
reg.addBorder(r.getBorder())
regions+=reg
border_turfs+=reg.getBorder()
else
for(var/l in r.getMultiborder())
var/Region/reg = new /Region(src)
reg.addTurfs(r.getTurfs(), 1)
reg.addBorder(l)
regions+=reg
border_turfs+=l
for(var/turf/t in border_turfs)
for(var/turf/t2 in range(t, 1))
if(isWall(t2)&&!(t2 in border_turfs))
for(var/turf/t3 in range(t2, 1))
if(!isWall(t3))
border_turfs+=t2
break
numits = 0
paths = numExtraPaths
while(regions.len>1 || paths>0)
if(numits>maximumIterations)
if(regions.len>1) out_error = ERROR_MAX_ITERATIONS_CONNECTIVITY
else out_error = ERROR_MAX_ITERATIONS_EXTRAPATHS
break
numits++
region1 = pick(regions)
region2 = pick(regions)
if(region1==region2) if(regions.len>1) continue
var/list/turf/path = getPath(region1, region2, regions)
if(!path || !path.len) continue
numits = 0
if(region1==region2) if(regions.len<=1) paths--
for(var/turf/t in path)
path-=t
path+=new floortype(t)
region1.addTurfs(path)
if(region1!=region2)
region1.addTurfs(region2.getTurfs(), 1)
region1.addBorder(region2.getBorder())
regions-=region2
for(var/turf/t in region1.getBorder()) if(!(t in border_turfs)) border_turfs+=t
for(var/turf/t in path) for(var/turf/t2 in range(t, 1)) if(!(t2 in border_turfs)) border_turfs+=t2
for(var/Room/r in rooms) r.finalise()
out_rooms = rooms
out_region = region1
out_numRooms = out_rooms.len
rand_seed(tempseed)


dungeon
proc
path(Region/region1, Region/region2)
var/turf/start = pick(region1.getBorder())
var/turf/end
var/long = FALSE
var/minlength = minPathLength
if(prob(longPathChance))
minlength=minLongPathLength
long = TRUE
var/list/borders=list()
borders.Add(border_turfs)
borders.Remove(region2.getBorder())
borders-=start
var/list/turf/previous = list()
var/list/turf/done = list(start)
var/list/turf/next = getAdjacent(start)
var/list/turf/cost = list("\ref[start]"=0)
if(minlength<=0)
if(start in region2.getBorder())
out_numPaths++
if(long) out_numLongPaths++
end = start
goto endloop
next-=borders
for(var/turf/t in next)
if(!isWall(t)) next-=t
previous["\ref[t]"] = start
cost["\ref[t]"]=1
if(!next.len) return list()
while(1)
var/turf/min
var/mincost = maxPathLength
for(var/turf/t in next)
if((cost["\ref[t]"]<mincost) || (cost["\ref[t]"]==mincost && prob(50)))
min = t
mincost=cost["\ref[t]"]
if(!min) return list()
done += min
next -= min
if(min in region2.getBorder())
if(mincost>minlength && prob(pathEndChance))
out_numPaths++
if(long) out_numLongPaths++
end = min
break
else
continue
for(var/turf/t in getAdjacent(min))
if(isWall(t) && !(t in borders))
if(!(t in done) && !(t in next))
next+=t
previous["\ref[t]"] = min
cost["\ref[t]"] = mincost+1
endloop:
var/list/ret = list(end)
var/turf/last = end
while(1)
if(last==start) break
ret+=previous["\ref[last]"]
last=previous["\ref[last]"]
return ret
In response to Flame Sage
After all that, clearly my paths code is where the longest client wait time lies but honestly, how the heck else am I supposed to do that? I mean I need paths from point a to point b so following the code here I'm unable to find a shorter way to write it, or even...change it.

[edit]
I've proceeded to test, if I get rid of my paths generation is instant and without problem. Sooo... Any way to consolidate this code? I can't think of any at all.
Would it be smartest to rewrite a path-finding code from scratch using one part of the border of each room and not caring about the length and whether or not there is a dead end possibility?
[/edit]
If your concern is the entire server freezing while the map is generated, just add some sleep()s to the process to spread it out. You can also use the set background=1 setting, although I'm not sure how well it works. It will take longer to generate the actual map, but the rest of the players on the server won't "feel" it.
Uhm if its as simplistic as setting it to the background, then I think I might just have to shoot myself in the foot.

Well some bandages and a little testing later if I set it to background (Why the HELL didn't I think of this.) I have near full movement, with still a good deal of lag but atleast I'm able to move around during generation so I'm going to work in some sleeps during my loops.

Working sleep in broke everything. The hell? Hahaha. Time to keep trying at this.