|
| 1 | + |
| 2 | +//* This file is explicitly licensed under the MIT license. *// |
| 3 | +//* Copyright (c) 2025 Citadel Station Developers *// |
| 4 | + |
| 5 | +/** |
| 6 | + * All bitfield datums |
| 7 | + */ |
| 8 | +GLOBAL_LIST(bitfields) |
| 9 | +/** |
| 10 | + * All bitfield datums by path |
| 11 | + */ |
| 12 | +GLOBAL_LIST(bitfields_by_path) |
| 13 | +/** |
| 14 | + * All bitfield datums by var name |
| 15 | + */ |
| 16 | +GLOBAL_LIST(bitfields_by_var) |
| 17 | + |
| 18 | +// TODO: why don't we just tgui picker bitfields so we don't need to do insane lookups? |
| 19 | +/proc/init_bitfield_meta() |
| 20 | + // TODO: GLOBAL_ALIST |
| 21 | + var/list/bitfields = list() |
| 22 | + var/list/bitfield_by_path = list() |
| 23 | + var/list/bitfield_by_var = list() |
| 24 | + |
| 25 | + for(var/datum/bitfield/path as anything in subtypesof(/datum/bitfield)) |
| 26 | + if(path.abstract_type == path) |
| 27 | + continue |
| 28 | + var/datum/bitfield/instance = new path |
| 29 | + bitfields += instance |
| 30 | + // add legacy shit |
| 31 | + var/list/legacy_bitfields = generate_bitfields() |
| 32 | + for(var/var_name in legacy_bitfields) |
| 33 | + var/list/reverse_lookup = legacy_bitfields[var_name] |
| 34 | + var/datum/bitfield/legacy_instance = new |
| 35 | + for(var/name in reverse_lookup) |
| 36 | + var/bit = reverse_lookup[name] |
| 37 | + legacy_instance.names += name |
| 38 | + legacy_instance.bits += bit |
| 39 | + legacy_instance.paths = list((/datum) = var_name) |
| 40 | + bitfields += legacy_instance |
| 41 | + for(var/datum/bitfield/bitfield as anything in bitfields) |
| 42 | + for(var/path in bitfield.paths) |
| 43 | + if(!bitfield_by_path[path]) |
| 44 | + bitfield_by_path[path] = list(bitfield) |
| 45 | + else |
| 46 | + bitfield_by_path[path] += bitfield |
| 47 | + var/list/name_or_names = bitfield.paths[path] |
| 48 | + if(islist(name_or_names)) |
| 49 | + for(var/name in name_or_names) |
| 50 | + if(!bitfield_by_var[name]) |
| 51 | + bitfield_by_var[name] = list(bitfield) |
| 52 | + else |
| 53 | + bitfield_by_var[name] += bitfield |
| 54 | + else if(name_or_names) |
| 55 | + if(!bitfield_by_var[name_or_names]) |
| 56 | + bitfield_by_var[name_or_names] = list(bitfield) |
| 57 | + else |
| 58 | + bitfield_by_var[name_or_names] += bitfield |
| 59 | + else |
| 60 | + STACK_TRACE("Bitfield [bitfield.type] ([json_encode(bitfield.names)]) had no var name on path [path]") |
| 61 | + |
| 62 | + GLOB.bitfields = bitfields |
| 63 | + GLOB.bitfields_by_path = bitfield_by_path |
| 64 | + GLOB.bitfields_by_var = bitfield_by_var |
| 65 | + |
| 66 | +#if DM_VERSION > 516 |
| 67 | + #error remove the guards on path == /datum; byond will have fixed the crash bug by now |
| 68 | +#endif |
| 69 | + |
| 70 | +/proc/fetch_all_bitfields(datum/path) |
| 71 | + . = list() |
| 72 | + do |
| 73 | + var/list/maybe_bitfields = GLOB.bitfields_by_path[path] |
| 74 | + if(maybe_bitfields) |
| 75 | + . += maybe_bitfields |
| 76 | + if(path == /datum) |
| 77 | + break |
| 78 | + path = path.parent_type |
| 79 | + while(path) |
| 80 | + |
| 81 | +/proc/fetch_bitfield(datum/path, var_name) as /datum/bitfield |
| 82 | + if(istype(path)) |
| 83 | + path = path.type |
| 84 | + for(var/datum/bitfield/bitfield as anything in GLOB.bitfields_by_var[var_name]) |
| 85 | + for(var/match in bitfield.paths) |
| 86 | + if(ispath(path, match)) |
| 87 | + return bitfield |
| 88 | + |
| 89 | +/** |
| 90 | + * Bitfield datums used to reflect bitfield values in the game's code. |
| 91 | + */ |
| 92 | +/datum/bitfield |
| 93 | + abstract_type = /datum/bitfield |
| 94 | + /// typepaths this is valid on associated to variable or list of variables |
| 95 | + var/list/paths = list() |
| 96 | + var/list/bits |
| 97 | + var/list/names |
| 98 | + |
| 99 | +/datum/bitfield/New() |
| 100 | + var/list/constants = get_bit_constants() |
| 101 | + bits = list() |
| 102 | + names = list() |
| 103 | + for(var/name in constants) |
| 104 | + var/bit = constants[name] |
| 105 | + bits += bit |
| 106 | + names += name |
| 107 | + |
| 108 | +/datum/bitfield/proc/get_bit_name(bit) |
| 109 | + . = bits.Find(bit) |
| 110 | + return . ? names[.] : null |
| 111 | + |
| 112 | +/datum/bitfield/proc/get_bit(name) |
| 113 | + . = names.Find(name) |
| 114 | + return . ? bits[.] : null |
| 115 | + |
| 116 | +/** |
| 117 | + * This is NOT necessarily the number of bits in the bitfield. This is only how many of them |
| 118 | + * were declared in ourselves. Please be careful when using this; |
| 119 | + */ |
| 120 | +/datum/bitfield/proc/get_declared_count() |
| 121 | + return length(bits) |
| 122 | + |
| 123 | +/** |
| 124 | + * @return list(NAME = BIT, ...) |
| 125 | + */ |
| 126 | +/datum/bitfield/proc/get_bit_constants() |
| 127 | + return list() |
0 commit comments