Files
Bubberstation/code/modules/mining/machine_silo.dm
Zephyr fbec9c14e9 JSON Logging Take Two (#73604)
## About The Pull Request

Converts all logging, excluding perf and investigate, to json.
I focused on making the system as easy to use and as easy to add new
categories as possible.

Due to issues related to logging to world at global creation logger is
now a byond real, which is created directly before Master

Log categories support versioning, secret flagging, and sub-category
filtering. Although all of this is entirely optional for coders.
If you ever want to add a new category and use it, all you need to do is
make the barebones category datum and the define.
I've kept existing procs such as log_game, and simply turned them into a
wrapper for Logger.Log(xxx, ...)
## Why It's Good For The Game

Makes processing and filtering logs much easier in the future, while
only minimally downgrading log crawling experience.
I am also working on a log viewer frontend for admin usage however that
will take a little bit longer to finish up.
Also makes special logging and data tracking much easier thanks to a
data list processing implementation and handling
## Changelog
🆑
server: All logs are now formatted in json, excluding perf and
investigations
/🆑

---------

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com>
Co-authored-by: Kyle Spier-Swenson <kyleshome@gmail.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
2023-05-22 14:51:00 +12:00

276 lines
9.2 KiB
Plaintext

GLOBAL_DATUM(ore_silo_default, /obj/machinery/ore_silo)
GLOBAL_LIST_EMPTY(silo_access_logs)
/obj/machinery/ore_silo
name = "ore silo"
desc = "An all-in-one bluespace storage and transmission system for the station's mineral distribution needs."
icon = 'icons/obj/mining.dmi'
icon_state = "silo"
density = TRUE
circuit = /obj/item/circuitboard/machine/ore_silo
/// The machine UI's page of logs showing ore history.
var/log_page = 1
/// List of all connected components that are on hold from accessing materials.
var/list/holds = list()
/// List of all components that are sharing ores with this silo.
var/list/datum/component/remote_materials/ore_connected_machines = list()
/obj/machinery/ore_silo/Initialize(mapload)
. = ..()
var/static/list/materials_list = list(
/datum/material/iron,
/datum/material/glass,
/datum/material/silver,
/datum/material/gold,
/datum/material/diamond,
/datum/material/plasma,
/datum/material/uranium,
/datum/material/bananium,
/datum/material/titanium,
/datum/material/bluespace,
/datum/material/plastic,
)
AddComponent(/datum/component/material_container, materials_list, INFINITY, MATCONTAINER_NO_INSERT, allowed_items=/obj/item/stack)
if (!GLOB.ore_silo_default && mapload && is_station_level(z))
GLOB.ore_silo_default = src
/obj/machinery/ore_silo/Destroy()
if (GLOB.ore_silo_default == src)
GLOB.ore_silo_default = null
for(var/datum/component/remote_materials/mats as anything in ore_connected_machines)
mats.disconnect_from(src)
ore_connected_machines = null
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/living/user, obj/item/stack/I, breakdown_flags=NONE)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
// stolen from /datum/component/material_container/proc/OnAttackBy
if(user.combat_mode)
return
if(I.item_flags & ABSTRACT)
return
if(!istype(I) || (I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION))
to_chat(user, span_warning("[M] won't accept [I]!"))
return
var/item_mats = materials.get_item_material_amount(I, breakdown_flags)
if(!item_mats)
to_chat(user, span_warning("[I] does not contain sufficient materials to be accepted by [M]."))
return
// assumes unlimited space...
var/amount = I.amount
materials.user_insert(I, user, breakdown_flags)
var/list/matlist = I.get_material_composition(breakdown_flags)
silo_log(M, "deposited", amount, I.name, matlist)
return TRUE
/obj/machinery/ore_silo/attackby(obj/item/W, mob/user, params)
if(default_deconstruction_screwdriver(user, icon_state, icon_state, W))
updateUsrDialog()
return
if(default_deconstruction_crowbar(W))
return
if(!powered())
return ..()
if (isstack(W))
return remote_attackby(src, user, W)
return ..()
/obj/machinery/ore_silo/ui_interact(mob/user)
user.set_machine(src)
var/datum/browser/popup = new(user, "ore_silo", null, 600, 550)
popup.set_content(generate_ui())
popup.open()
/obj/machinery/ore_silo/proc/generate_ui()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/list/ui = list("<head><title>Ore Silo</title></head><body><div class='statusDisplay'><h2>Stored Material:</h2>")
var/any = FALSE
for(var/M in materials.materials)
var/datum/material/mat = M
var/amount = materials.materials[M]
var/sheets = round(amount) / SHEET_MATERIAL_AMOUNT
var/ref = REF(M)
if (sheets)
if (sheets >= 1)
ui += "<a href='?src=[REF(src)];ejectsheet=[ref];eject_amt=1'>Eject</a>"
else
ui += "<span class='linkOff'>Eject</span>"
if (sheets >= 20)
ui += "<a href='?src=[REF(src)];ejectsheet=[ref];eject_amt=20'>20x</a>"
else
ui += "<span class='linkOff'>20x</span>"
ui += "<b>[mat.name]</b>: [sheets] sheets<br>"
any = TRUE
if(!any)
ui += "Nothing!"
ui += "</div><div class='statusDisplay'><h2>Connected Machines:</h2>"
for(var/datum/component/remote_materials/mats as anything in ore_connected_machines)
var/atom/parent = mats.parent
ui += "<a href='?src=[REF(src)];remove=[REF(mats)]'>Remove</a>"
ui += "<a href='?src=[REF(src)];hold=[REF(mats)]'>[holds[mats] ? "Allow" : "Hold"]</a>"
ui += " <b>[parent.name]</b> in [get_area_name(parent, TRUE)]<br>"
if(!ore_connected_machines.len)
ui += "Nothing!"
ui += "</div><div class='statusDisplay'><h2>Access Logs:</h2>"
var/list/logs = GLOB.silo_access_logs[REF(src)]
var/len = LAZYLEN(logs)
var/num_pages = 1 + round((len - 1) / 30)
var/page = clamp(log_page, 1, num_pages)
if(num_pages > 1)
for(var/i in 1 to num_pages)
if(i == page)
ui += "<span class='linkOff'>[i]</span>"
else
ui += "<a href='?src=[REF(src)];page=[i]'>[i]</a>"
ui += "<ol>"
any = FALSE
for(var/i in (page - 1) * 30 + 1 to min(page * 30, len))
var/datum/ore_silo_log/entry = logs[i]
ui += "<li value=[len + 1 - i]>[entry.formatted]</li>"
any = TRUE
if (!any)
ui += "<li>Nothing!</li>"
ui += "</ol></div>"
return ui.Join()
/obj/machinery/ore_silo/Topic(href, href_list)
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["remove"])
var/datum/component/remote_materials/mats = locate(href_list["remove"]) in ore_connected_machines
if (mats)
mats.disconnect_from(src)
updateUsrDialog()
return TRUE
else if(href_list["hold"])
var/datum/component/remote_materials/mats = locate(href_list["hold"]) in ore_connected_machines
mats.toggle_holding()
updateUsrDialog()
return TRUE
else if(href_list["ejectsheet"])
var/datum/material/eject_sheet = locate(href_list["ejectsheet"])
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/count = materials.retrieve_sheets(text2num(href_list["eject_amt"]), eject_sheet, drop_location())
var/list/matlist = list()
matlist[eject_sheet] = SHEET_MATERIAL_AMOUNT * count
silo_log(src, "ejected", -count, "sheets", matlist)
return TRUE
else if(href_list["page"])
log_page = text2num(href_list["page"]) || 1
updateUsrDialog()
return TRUE
/obj/machinery/ore_silo/multitool_act(mob/living/user, obj/item/multitool/I)
. = ..()
if (istype(I))
to_chat(user, span_notice("You log [src] in the multitool's buffer."))
I.buffer = src
return TRUE
/**
* Creates a log entry for depositing/withdrawing from the silo both ingame and in text based log
*
* Arguments:
* - [M][/obj/machinery]: The machine performing the action.
* - action: Text that visually describes the action (smelted/deposited/resupplied...)
* - amount: The amount of sheets/objects deposited/withdrawn by this action. Positive for depositing, negative for withdrawing.
* - noun: Name of the object the action was performed with (sheet, units, ore...)
* - [mats][list]: Assoc list in format (material datum = amount of raw materials). Wants the actual amount of raw (iron, glass...) materials involved in this action. If you have 10 metal sheets each worth 2000 iron you would pass a list with the iron material datum = 20000
*/
/obj/machinery/ore_silo/proc/silo_log(obj/machinery/M, action, amount, noun, list/mats)
if (!length(mats))
return
var/datum/ore_silo_log/entry = new(M, action, amount, noun, mats)
var/list/datum/ore_silo_log/logs = GLOB.silo_access_logs[REF(src)]
if(!LAZYLEN(logs))
GLOB.silo_access_logs[REF(src)] = logs = list(entry)
else if(!logs[1].merge(entry))
logs.Insert(1, entry)
updateUsrDialog()
flick("silo_active", src)
/obj/machinery/ore_silo/examine(mob/user)
. = ..()
. += span_notice("[src] can be linked to techfabs, circuit printers and protolathes with a multitool.")
/datum/ore_silo_log
var/name // for VV
var/formatted // for display
var/timestamp
var/machine_name
var/area_name
var/action
var/noun
var/amount
var/list/materials
/datum/ore_silo_log/New(obj/machinery/M, _action, _amount, _noun, list/mats=list())
timestamp = station_time_timestamp()
machine_name = M.name
area_name = get_area_name(M, TRUE)
action = _action
amount = _amount
noun = _noun
materials = mats.Copy()
format()
var/list/data = list(
"machine_name" = machine_name,
"area_name" = AREACOORD(M),
"action" = action,
"amount" = abs(amount),
"noun" = noun,
"raw_materials" = get_raw_materials(""),
"direction" = amount < 0 ? "withdrawn" : "deposited",
)
logger.Log(
LOG_CATEGORY_SILO,
"[machine_name] in \[[AREACOORD(M)]\] [action] [abs(amount)]x [noun] | [get_raw_materials("")]",
data,
)
/datum/ore_silo_log/proc/merge(datum/ore_silo_log/other)
if (other == src || action != other.action || noun != other.noun)
return FALSE
if (machine_name != other.machine_name || area_name != other.area_name)
return FALSE
timestamp = other.timestamp
amount += other.amount
for(var/each in other.materials)
materials[each] += other.materials[each]
format()
return TRUE
/datum/ore_silo_log/proc/format()
name = "[machine_name]: [action] [amount]x [noun]"
formatted = "([timestamp]) <b>[machine_name]</b> in [area_name]<br>[action] [abs(amount)]x [noun]<br> [get_raw_materials("")]"
/datum/ore_silo_log/proc/get_raw_materials(separator)
var/list/msg = list()
for(var/key in materials)
var/datum/material/M = key
var/val = round(materials[key])
msg += separator
separator = ", "
msg += "[amount < 0 ? "-" : "+"][val] [M.name]"
return msg.Join()