ID:2891627
 
(See the best response by Ter13.)
Some background:

I'm using multiple map controls to display the player's inventory and crafting windows. When I update the Inventory window I need to clear the map control inside to refresh it. The only way I can think to do this is by using:

src.client.screen = null

The problem with this is if my crafting window is open, or there are any other elements on the screen, they ALL get reset and also need to be refreshed.

Is there a way I can "null" the map control inside the Inventory window without nulling the entire client screen?
Ideally, you should be keeping track of which screen objects belong to each map. Storing a list for each mapid is the way to go, then you can just subtract that list from client.screen and then remove the list from the client registry where you are storing it.

There is no built in way to filter screen objects by which map control they are showing on, and you should avoid doing it, because it's extra work on the server for something you should be tracking yourself.
I should mention I'm starting from Schnitzelnagler's Crafting Demo, which creates a Grid inside the map to hold each item in the user's contents.

Each time the inventory is opened, this code is called:

mob/verb/UpdateInv()
set hidden = 1 // Hides this from any lists of commands
src.client.screen = null //Clear the inventory so we don't get the updated version overlapping the old
for(var/Column = 1 to 8) for(var/Row = 1 to 5) //Define a grid composed of 5 columns and 10 rows.
var/Grid/G = new // Label the grid so we can point to it later and create it
G.screen_loc = "Inv:[Row],[Column]" // Define where that new grid should go
src.client.screen += G // add it to the player's inventory window
winset(usr, "Inventory", "pos = 1495,80")
winshow(src, "Inventory", 1) // show the inventory window
for(var/obj/I in src.contents) src.AddItems(I) // Add items from the user's contents to the grid

mob/proc/AddItems(obj/I) // Label the item being added
for(var/Grid/G in src.client.screen) // loop through cells in the inventory grid
if(G.used) continue // if it already has an item in it, move on to the next cell
I.screen_loc = G.screen_loc ; src.client.screen+=I // set the location of the item the same as the cell, and add it to the player's screen
if(I.amount >= 1) // if the item's amount is greater than 1
if(I.stackable == 1) // redundant check for stackability
I.maptext = "<div align=right><font color=white><b>x[I.amount]</div>" // display the amount over the item
G.used =1 ; return


Is this still the "wrong" way of using a map?

I use the same system for the crafting window, but they're conflicting because of the "src.client.screeen = null" to reset the inventory. Without the line, the inventory window stacks a Grid on a new layer above the old each time it's opened.
Best response
Tooffless wrote:
Is this still the "wrong" way of using a map?

Very much so.

Right here:
for(var/Grid/G in src.client.screen)


If you ever loop over the world or screen looking for something specific, you've designed your data structures incorrectly. You aren't hanging on to data how you should be.

I wrote a whole snippet sunday on this topic.
Heard. Reading through all of that (including the wild-ass comments...), I've come to the realization that I just need to rework A LOT of the system lol.

Thanks a lot for putting me on a new path so I didn't waste a bunch of time making things worse.
You might also see some value from this post

BYOND has come a long way. We no longer jam hundreds of objects into the screen, because we have something better now: vis_contents.

Check out the bit specifically about UI widgets in the post I linked. There's a better way than what schnitzelnagler had access to in '09.