by Yut Put
Explore epic dungeons and slay epic foes with your friends in a huge, epic fantasy action RPG world.
BYOND Version:494
Operating System:Windows XP Pro
Web Browser:Chrome 18.0.1025.162
Applies to:the game... obviously
Status: Resolved

This issue has been resolved.
Descriptive Problem Summary:

I just got this when I started the game up and clicked "continue game":

loading...this may take up to a minute
Forum_account is online
runtime error: bad index
proc name: RetrievePage (/proc/RetrievePage)
source file: fanning.dm,33
usr: the player (/player)
src: null
call stack:
RetrievePage("http://byond.com/hub/YutPut.ep...", "fans")
Get Fans("YutPut.epic")
isfan(Forum_account (/client))
the player (/player): Login()
FAIL @ http://byond.com/hub/YutPut.epic&command=view_fans
this might be caused by not having internet access... it is the procedure that checks the hub for fans
I was on my home computer which is always online. I don't doubt that BYOND's proc failed when it shouldn't have, so maybe it's worth making the game double check - I am a fan after all (I'm pretty sure I was even before there was a bonus for it)
I'll try that. I could also remove that so it only calls that procedure when it is needed.

Did it make the game inaccessible?
No, everything still loaded up fine and I was able to play.
Here's some more performance-related feedback:

I ran it today through Dream Daemon and connected locally. DD's CPU usage was almost always maxed out when a mob was on the screen. With no mobs on the screen it was around 5-15%. DS's CPU usage was a bit lower. I don't know if it ever got maxed out.

Mouse input was still often unresponsive. I'd click to loot an item and it wouldn't go into my inventory. Yet, if I closed the inventory screen and clicked, I'd attack. I know that sometimes DS just doesn't acknowledge mouse clicks but there appears to be something else happening here (DS and DD both had low CPU usage). I double-checked to make sure my inventory wasn't full but still can't loot anything.

Edit: Pressing T to loot the gold/wires isn't working in these situations either.

Edit #2: I noticed that performance was especially bad in the elven castle. Near the king and jail you can get a lot of mobs on the screen. You have debug enabled so I did some profiling. The average call to mob.movement took 5 milliseconds. If you call that 40 times per second, that's 200 ms. If you have 5 mobs on the screen, that's 100% of your CPU time right there.

The numbers don't exactly add up (it wouldn't be the first time BYOND's profiler was wrong). It looks you like overrode the mob.movement proc and its total CPU time was 53.657, but only 0.220 self CPU time for your movement proc and 0.140 self CPU time for the library's default movement proc. The set_flags proc has 20.938 self CPU time, which is a good part of movement's total time, but I can't account for the rest.

The pixel_move proc has a total CPU time of 16 seconds and a self CPU time of 6 seconds. I can't account for those other 10 seconds - the procs that pixel_move calls don't add up to that. On top of that, set_flags and pixel_move, which are the bulk of movement's CPU time, only add up to 36 seconds (and that includes the unaccounted time in pixel_move). There are some other procs, like action() and move(), that'll take up some time, but I don't see movement's total time being more than 40 seconds. That knocks it down to 3.83 ms per call, meaning it'd take 6.5 mobs to max out the CPU. In the Pixel Movement library's benchmark #1, I'm seeing an average of 0.2 milliseconds per call to mob.movement.

Based on the numbers I'm seeing, there are a few things that might help:

1. I really need to improve the performance of set_flags. It's always been the bottleneck and it used to be optional (you only needed to call it if you planned on using the mob's on_left, on_right, etc. vars). If you don't use these vars (and if I make some changes to the library) this should be a big boost.

2. What does the mob2 proc do? I'm showing it at 1.54 ms per call (but it's not being called every tick).

3. The Enemy/action proc has a total CPU time of 4.835 seconds for 2840 calls, or 1.7 ms per call.

4. You call below() or inside() a lot (in the library's 2D mode they're equivalent) and they take about 0.6 ms per call. I'm guessing you use this for checking if you're standing over a corpse (or other things like that) but it looks like it's getting called for all mobs (not just the player).

The action() proc takes a parameter that's just an increasing integer. You can use it to make certain things happen every other tick, or every third tick, etc. If you can identify some things that mobs do and make them happen a little less frequently, you can really cut the CPU usage. Most actions can be done 20 times per second instead of 40 times per second and the player won't notice - it's an easy way to cut something's CPU usage in half.
the inconsistency might be a result of the icon procs and caching. i use both fcopy_rsc and an icon cache to keep track of the fcopy_rsc entries

1. I didn't use set_flags.

2. mob2 is a procedure that determines overlays and turning stuff for the player. it racks up a lot of CPU probably because it calls the stuff which processes icons. it's only called when something changes in the player's icon, and it isn't consistent with how much cpu it uses because i have an icon cache

3. i applied your method of decreasing the number of times certain things happen in a second and it has improved the performance of a number of things

4. i minimalized the number of times inside() is called and ran a check through the entire source to replace all the instances where orange(0,src) could be used instead
Yut Put wrote:
1. I didn't use set_flags.

The Pixel Movement library calls it automatically. Even if you don't ever read the player's on_left or on_right vars, it needs them for some internal things (I'd like to change this but I'm not sure how). In the profiling of Epic, if I remember the numbers correctly, set_flags() was taking about 2 milliseconds per call. In the most recent versions of the library it shouldn't be taking nearly this long. Maybe it takes longer because there are just more objects on the map.

4. i minimalized the number of times inside() is called and ran a check through the entire source to replace all the instances where orange(0,src) could be used instead

This was related to #3. I don't think that inside()'s performance is bad (it's just calling obounds(0)), but it looked like it may have been called more often than you needed to call it.

Also, I don't think I had mentioned it before, but I had noticed some problems with the lightning bolt tiles (the things that get activated when you step on a pressure switch and cause doors to be opened). There's an early dungeon (I forget the number, something around the 5-8 range maybe) where you have to activate three pressure switches to reach the end. When stepping on them, not all of those tiles would activate and the doors wouldn't open.
i'll see if i can upgrade to the latest version of the library

the power box problem happens because they only get their action proc called if they are within the player's view, and the action proc is what checks for nearby powered objects

i could try and come up with a solution to that
If that's how wires work too, that might be why they're causing lag. You could just check when something changes - when you step on the switch, power all adjacent power boxes. It doesn't seem like you need them to be continuously checking for things to power.
Yut Put resolved issue