diff --git a/code/modules/cooking/machinery/smartfridge.dm b/code/modules/cooking/machinery/smartfridge.dm index 1d2e4ad6281..5b3f3a30918 100644 --- a/code/modules/cooking/machinery/smartfridge.dm +++ b/code/modules/cooking/machinery/smartfridge.dm @@ -43,6 +43,8 @@ var/datum/wires/smartfridge/wires = null atmos_canpass = CANPASS_DENSITY + VAR_PRIVATE/static/list/base64_cache = list() + /obj/machinery/smartfridge/secure is_secure = 1 @@ -95,6 +97,7 @@ for(var/obj/item/reagent_containers/food/snacks/grown/g in contents) item_quants[g.name]++ update_overlays() + update_static_data_for_all_viewers() /obj/machinery/smartfridge/Initialize() . = ..() @@ -230,6 +233,10 @@ if(S.on_dry(src)) //Drying rack keeps the item but changes the name. This prevents pre-dried item lingering in the UI as vendable item_quants[S.name]++ item_quants[old_name]-- + if(item_quants[old_name] <= 0 || item_quants[S.name] == 1) + update_static_data_for_all_viewers() + if(item_quants[old_name] <= 0) + item_quants -= old_name return /obj/machinery/smartfridge/drying_rack/update_overlays() @@ -360,25 +367,32 @@ user.remove_from_mob(attacking_item) attacking_item.forceMove(src) item_quants[attacking_item.name]++ + if(item_quants[attacking_item.name] == 1) + update_static_data_for_all_viewers() user.visible_message("[user] adds \a [attacking_item] to [src].", SPAN_NOTICE("You add [attacking_item] to [src].")) update_overlays() - return + return TRUE if(istype(attacking_item, /obj/item/storage)) var/obj/item/storage/P = attacking_item var/plants_loaded = 0 + var/update_static_data = FALSE for(var/obj/G in P.contents) if(accept_check(G)) if(length(contents) >= max_n_of_items) break P.remove_from_storage(G,src) item_quants[G.name]++ + if(item_quants[G.name] == 1) + update_static_data = TRUE plants_loaded++ if(plants_loaded) user.visible_message("[user] loads [src] with [P].", SPAN_NOTICE("You load [src] with [P].")) if(length(P.contents) > 0) to_chat(user, SPAN_NOTICE("Some items are refused.")) update_overlays() + if(update_static_data) + update_static_data_for_all_viewers() return TRUE to_chat(user, SPAN_NOTICE("[src] smartly refuses [attacking_item].")) return TRUE @@ -416,43 +430,55 @@ /obj/machinery/smartfridge/ui_data(mob/user) var/list/data = list() - data["contents"] = null data["electrified"] = seconds_electrified > 0 data["shoot_inventory"] = shoot_inventory data["locked"] = locked data["secure"] = is_secure data["sort_alphabetically"] = ui_sort_alphabetically - var/list/items = list() - for (var/i = 1 to length(item_quants)) + var/list/stocks + for (var/i in 1 to length(item_quants)) var/K = item_quants[i] var/count = item_quants[K] if(count > 0) + LAZYADDASSOC(stocks, capitalize(K), count) - var/obj/item/item_used = null - for (var/obj/item/O in contents) - if(O.name == K) - item_used = O - break + data["stocks"] = stocks - var/icon/item_icon = null - if(item_used) - if(istype(item_used, /obj/item/seeds)) - var/obj/item/seeds/S = item_used - item_icon = S.update_appearance(TRUE) - else - item_icon = new /icon(item_used.icon, item_used.icon_state) + return data - var/final_icon = null - if(item_icon) - final_icon = icon2base64(item_icon) +/obj/machinery/smartfridge/ui_static_data(mob/user) + var/list/data = list() + data["contents"] = null - items.Add(list(list( - "display_name" = capitalize(K), - "vend" = i, - "quantity" = count, - "icon" = final_icon, - ))) + var/list/items = list() + for (var/i = 1 to length(item_quants)) + var/K = item_quants[i] + var/obj/item/item_used = null + for (var/obj/item/O in contents - component_parts) + if(O.name == K) + item_used = O + break + + if(!item_used) + continue + + var/final_icon = base64_cache["[K]_[item_used.type]_[item_used.icon_state]"] + if(!final_icon) + var/icon/item_icon + if(istype(item_used, /obj/item/seeds)) + var/obj/item/seeds/S = item_used + item_icon = S.update_appearance(TRUE) + else + item_icon = getFlatIcon(item_used) + final_icon = icon2base64(item_icon) + base64_cache["[K]_[item_used.type]_[item_used.icon_state]"] = final_icon + + items.Add(list(list( + "display_name" = capitalize(K), + "vend" = i, + "icon" = final_icon, + ))) if(length(items) > 0) data["contents"] = items @@ -497,6 +523,10 @@ update_overlays() if(i <= 0) break + + if(item_quants[K] <= 0) + update_static_data_for_all_viewers() + item_quants -= K if("switch_sort_alphabetically") ui_sort_alphabetically = !ui_sort_alphabetically @@ -510,6 +540,7 @@ for (var/O in item_quants) if(item_quants[O] <= 0) //Try to use a record that actually has something to dump. + item_quants -= O continue item_quants[O]-- @@ -518,6 +549,10 @@ T.forceMove(loc) throw_item = T break + + if(item_quants[O] <= 0) + update_static_data_for_all_viewers() + item_quants -= O break if(!throw_item) return FALSE diff --git a/html/changelogs/johnwildkins-smartfridge.yml b/html/changelogs/johnwildkins-smartfridge.yml new file mode 100644 index 00000000000..2667a7ec58f --- /dev/null +++ b/html/changelogs/johnwildkins-smartfridge.yml @@ -0,0 +1,14 @@ +# Your name. +author: JohnWildkins + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Move smartfridge icon generation to static data and cache results to improve performance." + - bugfix: "Fix chemical bottles not having proper colors in SmartFridge UI." diff --git a/tgui/packages/tgui/interfaces/SmartFridge.tsx b/tgui/packages/tgui/interfaces/SmartFridge.tsx index ee0c6ef1b63..fee46ce3100 100644 --- a/tgui/packages/tgui/interfaces/SmartFridge.tsx +++ b/tgui/packages/tgui/interfaces/SmartFridge.tsx @@ -5,6 +5,7 @@ import { Window } from '../layouts'; export type FridgeData = { contents: Item[]; + stocks: { [display_name: string]: number }; seconds_electrified: BooleanLike; shoot_inventory: BooleanLike; locked: number; // goes to -1 @@ -15,7 +16,6 @@ export type FridgeData = { type Item = { display_name: string; vend: number; - quantity: number; icon?: string | null; }; @@ -87,93 +87,98 @@ export const ContentsWindow = (props, context) => { }) : itemList; + const itemStock = (item: Item) => data.stocks[item.display_name] || 0; + return (
- {itemListSorted.map((item) => ( - - {/* Item icon */} - {item.icon ? ( + {itemListSorted.map((item) => { + const quantity = itemStock(item); + return ( + + {/* Item icon */} + {item.icon ? ( + + ) : null} + {/* Name stuff */} - ) : null} - {/* Name stuff */} - - {item.display_name} + style={{ + flex: 2, + minWidth: 0, + whiteSpace: 'normal', + overflowWrap: 'break-word', + wordBreak: 'break-word', + }} + > + {item.display_name} + + {/* Amount */}x{quantity} + {/* Vend buttons */} + + {quantity > 0 && ( +
);