Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PORT TG][TOOLS][UNIT-TEST] Ports AutoWiki. coding cataloging the redux esquire #22518

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/autowiki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Autowiki
on:
schedule:
- cron: "5 4 * * *"
workflow_dispatch:
permissions:
contents: read

jobs:
autowiki:
runs-on: ubuntu-20.04
steps:
- name: "Check for AUTOWIKI_USERNAME"
id: secrets_set
env:
ENABLER_SECRET: ${{ secrets.AUTOWIKI_USERNAME }}
run: |
unset SECRET_EXISTS
if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi
echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT
- name: Checkout
if: steps.secrets_set.outputs.SECRETS_ENABLED
uses: actions/checkout@v4
- name: Restore BYOND cache
if: steps.secrets_set.outputs.SECRETS_ENABLED
uses: actions/cache@v4
with:
path: ~/BYOND
key: ${{ runner.os }}-byond-${{ hashFiles('dependencies.sh') }}
- name: Install rust-g
if: steps.secrets_set.outputs.SECRETS_ENABLED
run: |
bash tools/ci/install_rust_g.sh
- name: Compile and generate Autowiki files
if: steps.secrets_set.outputs.SECRETS_ENABLED
run: |
bash tools/ci/install_byond.sh
source $HOME/BYOND/byond/bin/byondsetup
tools/build/build --ci autowiki
- name: Run Autowiki
if: steps.secrets_set.outputs.SECRETS_ENABLED
env:
USERNAME: ${{ secrets.AUTOWIKI_USERNAME }}
PASSWORD: ${{ secrets.AUTOWIKI_PASSWORD }}
run: |
cd tools/autowiki
npm install
cd ../..
node tools/autowiki/autowiki.js data/autowiki_edits.txt data/autowiki_files/
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,6 @@ tools/MapAtmosFixer/MapAtmosFixer/bin/*

# Running OpenDream locally
tgstation.json

# Autowiki
/tools/autowiki/node_modules
4 changes: 4 additions & 0 deletions code/_compile_options.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
// If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between
//#define UNIT_TESTS

/// If this is uncommented, Autowiki will generate edits and shut down the server.
/// Prefer the autowiki build target instead.
// #define AUTOWIKI

// If defined, we will NOT defer asset generation till later in the game, and will instead do it all at once, during initiialize
//#define DO_NOT_DEFER_ASSETS

Expand Down
1 change: 0 additions & 1 deletion code/controllers/configuration/config_entry.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry

var/deprecated_by //the /datum/config_entry type that supercedes this one

var/protection = NONE
var/abstract_type = /datum/config_entry //do not instantiate if type matches this

Expand Down
3 changes: 2 additions & 1 deletion code/controllers/subsystem/processing/station.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ PROCESSING_SUBSYSTEM_DEF(station)
/datum/controller/subsystem/processing/station/Initialize(timeofday)

//If doing unit tests we don't do none of that trait shit ya know?
#ifndef UNIT_TESTS
// Autowiki also wants consistent outputs, for example making sure the vending machine page always reports the normal products
#if !defined(UNIT_TESTS) && !defined(AUTOWIKI)
SetupTraits()
PrepareReport()
#endif
Expand Down
4 changes: 2 additions & 2 deletions code/game/mecha/mech_fabricator.dm
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@

var/list/part = list(
"name" = D.name,
"desc" = initial(built_item.desc),
"desc" = D.get_description(),
"printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
"cost" = cost,
"id" = D.id,
Expand All @@ -272,7 +272,7 @@
/**
* Generates a list of resources / materials available to this Exosuit Fab
*
* Returns null if there is no material container available.
* Returns null if there is no material container available.B
wonderinghost marked this conversation as resolved.
Show resolved Hide resolved
* List format is list(material_name = list(amount = ..., ref = ..., etc.))
*/
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
Expand Down
4 changes: 4 additions & 0 deletions code/game/world.dm
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ GLOBAL_VAR(restart_counter)
HandleTestRun()
#endif

#ifdef AUTOWIKI
setup_autowiki()
#endif

/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
Expand Down
33 changes: 33 additions & 0 deletions code/modules/autowiki/autowiki.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// When the `AUTOWIKI` define is enabled, will generate an output file for tools/autowiki/autowiki.js to consume.
/// Autowiki code intentionally still *exists* even without the define, to ensure developers notice
/// when they break it immediately, rather than until CI or worse, call time.
#if defined(AUTOWIKI) || defined(UNIT_TESTS)
/proc/setup_autowiki()
Master.sleep_offline_after_initializations = FALSE
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(generate_autowiki)))
SSticker.start_immediately = TRUE
CONFIG_SET(number/round_end_countdown, 0)

/proc/generate_autowiki()
var/output = generate_autowiki_output()
rustg_file_write(output, "data/autowiki_edits.txt")
qdel(world)
#endif

/// Returns a string of the autowiki output file
/proc/generate_autowiki_output()
var/total_output = ""

for (var/datum/autowiki/autowiki_type as anything in subtypesof(/datum/autowiki))
var/datum/autowiki/autowiki = new autowiki_type
var/output = autowiki.generate()

if (!istext(output))
CRASH("[autowiki_type] does not generate a proper output!")

total_output += json_encode(list(
"title" = autowiki.page,
"text" = output,
)) + "\n"

return total_output
54 changes: 54 additions & 0 deletions code/modules/autowiki/pages/base.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/// A representation of an automated wiki page.
/datum/autowiki
/// The page on the wiki to be replaced.
/// This should never be a user-facing page, like "Guide to circuits".
/// It should always be a template that only Autowiki should touch.
/// For example: "Template:Autowiki/CircuitInfo".
var/page

/// Override and return the new text of the page.
/// This proc can be impure, usually to call `upload_file`.
/datum/autowiki/proc/generate()
SHOULD_CALL_PARENT(FALSE)
CRASH("[type] does not implement generate()!")

/// Generates an auto formatted template user.
/// Your autowiki should ideally be a *lot* of these.
/// It lets wiki editors edit it much easier later, without having to enter repo.
/// Parameters will be passed in by name. That means your template should expect
/// something that looks like `{{ Autowiki_Circuit|name=Combiner|description=This combines }}`
/// Lists, which must be array-like (no keys), will be turned into a flat list with their key and a number,
/// such that list("food" = list("fruit", "candy")) -> food1=fruit|food2=candy
/datum/autowiki/proc/include_template(name, parameters)
var/template_text = "{{[name]"

var/list/prepared_parameters = list()
for (var/key in parameters)
var/value = parameters[key]
if (islist(value))
for (var/index in 1 to length(value))
prepared_parameters["[key][index]"] = "[value[index]]"
else
prepared_parameters[key] = value

for (var/parameter_name in prepared_parameters)
template_text += "|[parameter_name]="
template_text += "[prepared_parameters[parameter_name]]"

template_text += "}}"

return template_text

/// Takes an icon and uploads it to Autowiki-name.png.
/// Do your best to make sure this is unique, so it doesn't clash with other autowiki icons.
/datum/autowiki/proc/upload_icon(icon/icon, name)
// Fuck you
if (IsAdminAdvancedProcCall())
return

fcopy(icon, "data/autowiki_files/[name].png")

/// Escape a parameter such that it can be correctly put inside a wiki output
/datum/autowiki/proc/escape_value(parameter)
// | is a special character in MediaWiki, and must be escaped by...using another template.
return replacetextEx(parameter, "|", "{{!}}")
86 changes: 86 additions & 0 deletions code/modules/autowiki/pages/stockparts.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/// Automtically generated string list of stock part templates and relevant data for the /tg/station wiki
/datum/autowiki/stock_parts
page = "Template:Autowiki/Content/StockParts"

var/list/battery_whitelist = list(
/obj/item/stock_parts/cell,
/obj/item/stock_parts/cell/high,
/obj/item/stock_parts/cell/super,
/obj/item/stock_parts/cell/hyper,
/obj/item/stock_parts/cell/bluespace,
)

/datum/autowiki/stock_parts/generate()
var/output = ""

for(var/part_type in subtypesof(/obj/item/stock_parts))
var/obj/item/stock_parts/type_to_check = part_type
if(initial(type_to_check.abstract_type) == part_type)

Check failure on line 18 in code/modules/autowiki/pages/stockparts.dm

View workflow job for this annotation

GitHub Actions / Lints

undefined field: "abstract_type" on /obj/item/stock_parts
continue

if(!battery_whitelist.Find(part_type) && ispath(part_type, /obj/item/stock_parts/cell))
continue

var/obj/item/stock_parts/stock_part = new part_type()

var/datum/design/recipe = find_design(stock_part)

if(!recipe)
continue

var/datum/techweb_node/required_node = find_research(recipe)

var/list/entry_contents = list()

entry_contents["name"] = escape_value(format_text(stock_part.name))
entry_contents["icon"] = escape_value(format_text(create_icon(stock_part)))
entry_contents["desc"] = escape_value(format_text(stock_part.desc))
entry_contents["tier"] = escape_value(format_text("[stock_part.rating]"))
entry_contents["sources"] = escape_value(format_text(generate_source_list(recipe)))
entry_contents["node"] = escape_value(format_text(required_node.display_name))
entry_contents["materials"] = escape_value(format_text(generate_material_list(recipe)))

output += include_template("Autowiki/StockPart", entry_contents)

return output

/datum/autowiki/stock_parts/proc/find_design(obj/item/stock_parts/stock_part)
for(var/design_type in subtypesof(/datum/design))
var/datum/design/recipe = new design_type()

if(ispath(recipe.build_path, stock_part.type))
return recipe

/datum/autowiki/stock_parts/proc/find_research(datum/design/recipe)
for(var/node_type in subtypesof(/datum/techweb_node))
var/datum/techweb_node/node = new node_type()

if(node.design_ids.Find(recipe.id))
return node

/datum/autowiki/stock_parts/proc/create_icon(obj/item/stock_parts/stock_part)
var/filename = SANITIZE_FILENAME(escape_value(stock_part.icon_state))
upload_icon(icon(stock_part.icon, stock_part.icon_state, SOUTH, 1, FALSE), filename)

return "Autowiki-[filename].png"

/datum/autowiki/stock_parts/proc/generate_source_list(datum/design/recipe)
var/list/source_list = list()

if(recipe.build_type & PROTOLATHE)
source_list.Add("Protolathe")

if(recipe.build_type & AUTOLATHE)
source_list.Add("Autolathe")

return source_list.Join(", ")

/datum/autowiki/stock_parts/proc/generate_material_list(datum/design/recipe)
var/list/materials = list()

for(var/ingredient_type in recipe.materials)
var/datum/material/ingredient = new ingredient_type()

materials += "[recipe.materials[ingredient_type]] [ingredient.name]"

return materials.Join("<br>")
68 changes: 68 additions & 0 deletions code/modules/autowiki/pages/techweb.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/datum/autowiki/techweb
page = "Template:Autowiki/Content/Techweb"

/datum/autowiki/techweb/generate()
var/output = ""

for (var/node_id in sort_list(SSresearch.techweb_nodes, /proc/sort_research_nodes))
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
if (!node.show_on_wiki)
continue

if (!valid_node(node))
continue

output += "\n\n" + include_template("Autowiki/TechwebEntry", list(
"name" = escape_value(node.display_name),
"description" = escape_value(node.description),
"prerequisites" = generate_prerequisites(node.prereq_ids),
"designs" = generate_designs(node.design_ids),
))

return output

/datum/autowiki/techweb/proc/valid_node(datum/techweb_node/node)
return !node.experimental

Check failure on line 25 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

undefined field: "experimental" on /datum/techweb_node

/datum/autowiki/techweb/proc/generate_designs(list/design_ids)
var/output = ""

for (var/design_id in design_ids)
var/datum/design/design = SSresearch.techweb_designs[design_id]
output += include_template("Autowiki/TechwebEntryDesign", list(
"name" = escape_value(design.name),
"description" = escape_value(design.get_description()),
))

return output

/datum/autowiki/techweb/proc/generate_prerequisites(list/prereq_ids)
var/output = ""

for (var/prereq_id in prereq_ids)
var/datum/techweb_node/node = SSresearch.techweb_nodes[prereq_id]
output += include_template("Autowiki/TechwebEntryPrerequisite", list(
"name" = escape_value(node.display_name),
))

return output

/datum/autowiki/techweb/experimental
page = "Template:Autowiki/Content/Techweb/Experimental"

/datum/autowiki/techweb/experimental/valid_node(datum/techweb_node/node)
return node.experimental

Check failure on line 54 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

undefined field: "experimental" on /datum/techweb_node

/proc/sort_research_nodes(node_id_a, node_id_b)
var/datum/techweb_node/node_a = SSresearch.techweb_nodes[node_id_a]
var/datum/techweb_node/node_b = SSresearch.techweb_nodes[node_id_b]

var/prereq_difference = node_a.prereq_ids.len - node_b.prereq_ids.len
if (prereq_difference != 0)
return prereq_difference

var/experiment_difference = node_a.required_experiments.len - node_b.required_experiments.len

Check failure on line 64 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

undefined field: "required_experiments" on /datum/techweb_node

Check warning on line 64 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

field access requires static type: "len"

Check failure on line 64 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

undefined field: "required_experiments" on /datum/techweb_node

Check warning on line 64 in code/modules/autowiki/pages/techweb.dm

View workflow job for this annotation

GitHub Actions / Lints

field access requires static type: "len"
if (experiment_difference != 0)
return experiment_difference

return sorttext(node_b.display_name, node_a.display_name)
Loading
Loading