Files
Paradise/tools/migrate_attack_chain.py
warriorstar-orion 525c68d617 Attack chain, initial setup. (pull *immediately* for *any* TM issues) (#26834)
* refactor: Attack chain, initial setup.

* migrate curtain to make dreamchecker happy

* update thurible

* don't call attacked_by separately for legacy attack chain

* remove duplicate proc

* condense similar code, put allowances for legacy code in new procs

* update docs, include diagram source

* add comment on how to update diagram

* fix admonition

* mindflayer updates

* remove commented out code

* clarify all steps

* after_attack should be overridable

* whoops

* retrofit recent changes

* duh, can't restrict this yet because of tool_acts

* i hate ore bags with the fire of a thousand suns

* return correct value for object attack logic

* Various cleanups.

We don't want to attempt to pull stuff out of `/obj/item/attackby`,
because those pieces are part of the related objects' migrations, not
`/obj/item` itself. Attempting to do this causes knockon effects where
things expected to call e.g. `/obj/item/storage/attackby` in the call
chain were not ferried over to the new item interaction code, because
the related objects hadn't actually been migrated over yet.

I've used refactoring /obj/vehicle as the example for migrating
`attackby` methods instead.

* simplify some argument names

* fuck it

* make it do the thing

* Rename CI module call

* Prove that CI works

* improve test output

* aaand fix it again

* fix curtain tool interactions

* fix compile error

* fix compile error

* Better docs, introduce migration plan tool.
2024-12-02 23:36:36 +00:00

101 lines
3.0 KiB
Python

from dataclasses import dataclass, field
import sys
from avulto import DME, Path as p
@dataclass(frozen=True)
class MigrationPlan:
target_path: p
toggle_on: p
additional_paths: list[p] = field(default_factory=list)
ASSISTED_PATHS = [
p("/obj"),
p("/obj/item"),
p("/mob"),
p("/mob/living"),
p("/atom"),
]
def has_legacy_procs(dme: DME, pth: p) -> bool:
td = dme.type_decl(pth)
proc_names = td.proc_names(modified=True)
return any([x for x in proc_names if "legacy__attackchain" in x])
def get_migration_plan(
dme: DME, target_path: p, checked_types: set | None = None
) -> None | MigrationPlan:
if checked_types is None:
checked_types = set()
td = dme.type_decl(target_path)
new_attack_chain = td.var_decl("new_attack_chain", parents=True)
if new_attack_chain.const_val:
print(
f"Type {target_path} appears to be migrated already. Run CI tests to confirm valid migration."
)
return
additional_paths = set()
for subtype in dme.subtypesof(target_path):
if has_legacy_procs(dme, subtype):
additional_paths.add(subtype)
if subtype not in checked_types:
checked_types.add(subtype)
migration_plan = get_migration_plan(dme, subtype, checked_types)
if migration_plan:
additional_paths.update(migration_plan.additional_paths)
toggle_on = target_path
parent = target_path
while not any([parent == x for x in ASSISTED_PATHS]):
parent = parent.parent
if not has_legacy_procs(dme, parent):
continue
if parent in ASSISTED_PATHS:
continue
toggle_on = parent
if parent not in checked_types:
checked_types.add(parent)
migration_plan = get_migration_plan(dme, parent, checked_types)
if migration_plan:
additional_paths.update(migration_plan.additional_paths)
additional_paths.add(parent)
return MigrationPlan(
target_path=target_path,
toggle_on=toggle_on,
additional_paths=additional_paths,
)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("usage: migrate_attack_chain.py /target/path")
sys.exit(1)
dme = DME.from_file("paradise.dme")
target_path = p(sys.argv[1])
if not target_path.child_of("/atom"):
print(f"Type {target_path} is not an atom.")
sys.exit(1)
if target_path in ASSISTED_PATHS:
print(f"Type {target_path} should not be migrated.")
sys.exit(1)
migration_plan = get_migration_plan(dme, target_path)
if migration_plan:
print(f"Migration Plan for Path {target_path}")
if migration_plan.additional_paths:
print("Required Additional Migrations:")
for addl_path in sorted(migration_plan.additional_paths):
print(f"\t{addl_path}")
else:
print("No Additional Migrations Required")
print(f"Toggle `new_attack_chain = TRUE` on:\n\t{migration_plan.toggle_on}")