properly set occupant hash, max quantity, sorting class

This commit is contained in:
Rachel Powers
2024-04-24 22:08:54 -07:00
parent c87d3f8bd8
commit 19c85c1078
8 changed files with 28954 additions and 7493 deletions

1
www/data/Enums.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,305 @@
import { html, css } from "lit";
import { customElement, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
import SlDrawer from "@shoelace-style/shoelace/dist/components/drawer/drawer.js";
import type { DeviceDBEntry } from "virtual_machine/device_db";
import { repeat } from "lit/directives/repeat.js";
import { cache } from "lit/directives/cache.js";
import { default as uFuzzy } from "@leeoniya/ufuzzy";
import { when } from "lit/directives/when.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { VMDeviceDBMixin } from "virtual_machine/base_device";
@customElement("vm-add-device-button")
export class VMAddDeviceButton extends VMDeviceDBMixin(BaseElement) {
static styles = [
...defaultCss,
css`
.add-device-drawer {
--size: 36rem;
--footer-spacing: var(--sl-spacing-small);
}
.card {
margin-top: var(--sl-spacing-small);
margin-right: var(--sl-spacing-small);
}
`,
];
@query("sl-drawer") drawer: SlDrawer;
@query(".device-search-input") searchInput: SlInput;
private _structures: Map<string, DeviceDBEntry> = new Map();
private _datapoints: [string, string][] = [];
private _haystack: string[] = [];
postDBSetUpdate(): void {
this._structures = new Map(
Object.values(this.deviceDB.db)
.filter((entry) => this.deviceDB.structures.includes(entry.name), this)
.filter(
(entry) => this.deviceDB.logic_enabled.includes(entry.name),
this,
)
.map((entry) => [entry.name, entry]),
);
const datapoints: [string, string][] = [];
for (const entry of this._structures.values()) {
datapoints.push(
[entry.title, entry.name],
[entry.name, entry.name],
[entry.desc, entry.name],
);
}
const haystack: string[] = datapoints.map((data) => data[0]);
this._datapoints = datapoints;
this._haystack = haystack;
this.performSearch();
}
private _filter: string = "";
get filter() {
return this._filter;
}
@state()
set filter(val: string) {
this._filter = val;
this.page = 0;
this.performSearch();
}
private _searchResults: {
entry: DeviceDBEntry;
haystackEntry: string;
ranges: number[];
}[] = [];
private filterTimeout: number | undefined;
performSearch() {
if (this._filter) {
const uf = new uFuzzy({});
const [_idxs, info, order] = uf.search(
this._haystack,
this._filter,
0,
1e3,
);
const filtered = order?.map((infoIdx) => ({
name: this._datapoints[info.idx[infoIdx]][1],
haystackEntry: this._haystack[info.idx[infoIdx]],
ranges: info.ranges[infoIdx],
}));
const unique = [...new Set(filtered.map((obj) => obj.name))].map(
(result) => {
return filtered.find((obj) => obj.name === result);
},
);
this._searchResults = unique.map(({ name, haystackEntry, ranges }) => ({
entry: this._structures.get(name)!,
haystackEntry,
ranges,
}));
} else {
// return everything
this._searchResults = [...this._structures.values()].map((st) => ({
entry: st,
haystackEntry: st.title,
ranges: [],
}));
}
}
connectedCallback(): void {
super.connectedCallback();
window.VM.get().then((vm) =>
vm.addEventListener(
"vm-device-db-loaded",
this._handleDeviceDBLoad.bind(this),
),
);
}
_handleDeviceDBLoad(e: CustomEvent) {
this.deviceDB = e.detail;
}
@state() private page = 0;
renderSearchResults() {
const perPage = 40;
const totalPages = Math.ceil((this._searchResults?.length ?? 0) / perPage);
let pageKeys = Array.from({ length: totalPages }, (_, index) => index);
const extra: {
entry: { title: string; name: string };
haystackEntry: string;
ranges: number[];
}[] = [];
if (this.page < totalPages - 1) {
extra.push({
entry: { title: "", name: this.filter },
haystackEntry: "...",
ranges: [],
});
}
return when(
typeof this._searchResults !== "undefined" &&
this._searchResults.length < 20,
() =>
repeat(
this._searchResults ?? [],
(result) => result.entry.name,
(result) =>
cache(html`
<vm-device-template
prefab_name=${result.entry.name}
class="card"
@add-device-template=${this._handleDeviceAdd}
>
</vm-device-template>
`),
),
() => html`
<div class="p-2">
<div class="flex flex-row">
<p class="p-2">
<sl-format-number
.value=${this._searchResults?.length}
></sl-format-number>
results, filter more to get cards
</p>
<div class="p-2 ml-2">
Page:
${pageKeys.map(
(key, index) => html`
<span
class="p-2 cursor-pointer hover:text-purple-400 ${index ===
this.page
? " text-purple-500"
: ""}"
key=${key}
@click=${this._handlePageChange}
>${key + 1}${index < totalPages - 1 ? "," : ""}</span
>
`,
)}
</div>
</div>
<div class="flex flex-row flex-wrap">
${[
...this._searchResults.slice(
perPage * this.page,
perPage * this.page + perPage,
),
...extra,
].map((result) => {
let hay = result.haystackEntry.slice(0, 15);
if (result.haystackEntry.length > 15) hay += "...";
const ranges = result.ranges.filter((pos) => pos < 20);
const key = result.entry.name;
return html`
<div
class="m-2 text-neutral-200/90 italic cursor-pointer rounded bg-neutral-700 hover:bg-purple-500 px-1"
key=${key}
@click=${this._handleHaystackClick}
>
${result.entry.title} (<small class="text-sm">
${ranges.length
? unsafeHTML(uFuzzy.highlight(hay, ranges))
: hay} </small
>)
</div>
`;
})}
</div>
</div>
`,
);
}
_handlePageChange(e: Event) {
const span = e.currentTarget as HTMLSpanElement;
const key = parseInt(span.getAttribute("key"));
this.page = key;
}
_handleHaystackClick(e: Event) {
const div = e.currentTarget as HTMLDivElement;
const key = div.getAttribute("key");
if (key === this.filter) {
this.page += 1;
} else {
this.filter = key;
this.searchInput.value = key;
}
}
_handleDeviceAdd() {
this.drawer.hide();
}
render() {
return html`
<sl-button
variant="neutral"
outline
pill
@click=${this._handleAddButtonClick}
>
Add Device
</sl-button>
<sl-drawer class="add-device-drawer" placement="bottom" no-header>
<sl-input
class="device-search-input"
autofocus
placeholder="filter"
clearable
@sl-input=${this._handleSearchInput}
>
<span slot="prefix">Search Structures</span>
<sl-icon slot="suffix" name="search"></sl-icon>
</sl-input>
<div class="flex flex-row overflow-x-auto">
${this.renderSearchResults()}
</div>
<sl-button
slot="footer"
variant="primary"
@click=${() => {
this.drawer.hide();
}}
>
Close
</sl-button>
</sl-drawer>
`;
}
_handleSearchInput(e: CustomEvent) {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
const that = this;
this.filterTimeout = setTimeout(() => {
that.filter = that.searchInput.value;
that.filterTimeout = undefined;
}, 200);
}
_handleAddButtonClick() {
this.drawer.show();
this.searchInput.select();
}
}

View File

@@ -0,0 +1,243 @@
import { html, css } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMDeviceDBMixin } from "virtual_machine/base_device";
import type { DeviceDB, DeviceDBEntry } from "virtual_machine/device_db";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.component.js";
import { VMDeviceCard } from "./card";
import { when } from "lit/directives/when.js";
import uFuzzy from "@leeoniya/ufuzzy";
import { LogicField, SlotLogicType, SlotOccupantTemplate } from "ic10emu_wasm";
@customElement("vm-slot-add-dialog")
export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
static styles = [
...defaultCss,
css`
.slot-card {
--padding: var(--sl-spacing-x-small);
}
.slot-card::part(header) {
padding: var(--sl-spacing-x-small);
}
.slot-card::part(base) {
background-color: var(--sl-color-neutral-50);
}
.quantity-input sl-input::part(input) {
width: 3rem;
}
`,
];
private _items: Map<string, DeviceDBEntry> = new Map();
private _datapoints: [string, string][] = [];
private _haystack: string[] = [];
private _filter: string = "";
get filter() {
return this._filter;
}
@state()
set filter(val: string) {
this._filter = val;
this.performSearch();
}
private _searchResults: {
entry: DeviceDBEntry;
haystackEntry: string;
ranges: number[];
}[] = [];
postDBSetUpdate(): void {
this._items = new Map(
Object.values(this.deviceDB.db)
.filter((entry) => this.deviceDB.items.includes(entry.name), this)
.map((entry) => [entry.name, entry]),
);
this.performSearch();
}
performSearch() {
if (this._filter) {
const device = window.VM.vm.devices.get(this.deviceID);
const dbDevice = this.deviceDB.db[device.prefabName]
const slot = dbDevice.slots[this.slotIndex]
const typ = slot.typ;
let filterdItems = Array.from(this._items.values());
if (typ !== "None") {
filterdItems = Array.from(this._items.values()).filter(item => item.item.slotclass === typ);
}
const datapoints: [string, string][] = [];
for (const entry of filterdItems) {
datapoints.push(
[entry.title, entry.name],
[entry.name, entry.name],
[entry.desc, entry.name],
);
}
const haystack: string[] = datapoints.map((data) => data[0]);
this._datapoints = datapoints;
this._haystack = haystack;
const uf = new uFuzzy({});
const [_idxs, info, order] = uf.search(
this._haystack,
this._filter,
0,
1e3,
);
const filtered = order?.map((infoIdx) => ({
name: this._datapoints[info.idx[infoIdx]][1],
haystackEntry: this._haystack[info.idx[infoIdx]],
ranges: info.ranges[infoIdx],
})) ?? [];
const uniqueNames = new Set(filtered.map((obj) => obj.name));
const unique = [...uniqueNames].map(
(result) => {
return filtered.find((obj) => obj.name === result);
},
);
this._searchResults = unique.map(({ name, haystackEntry, ranges }) => ({
entry: this._items.get(name)!,
haystackEntry,
ranges,
}));
} else {
// return everything
this._searchResults = [...this._items.values()].map((st) => ({
entry: st,
haystackEntry: st.title,
ranges: [],
}));
}
}
renderSearchResults() {
return html`
<div class="mt-2 max-h-48 overflow-y-auto w-full">
<div class="cursor-pointer hover:bg-neutral-600 rounded px-2 me-1" @click=${this._handleClickNone}>
None
</div>
${this._searchResults.map((result) => {
const imgSrc = `img/stationpedia/${result.entry.name}.png`;
const img = html`
<img class="w-8 h-8" src=${imgSrc} onerror="this.src = '${VMDeviceCard.transparentImg}'" />
`;
return html`
<div class="cursor-pointer hover:bg-neutral-600 rounded px-2 me-1 flex flex-row" key=${result.entry.name} @click=${this._handleClickItem}>
${img}
<div>${result.entry.title}</div>
</div>
`;
})}
</div>
`;
}
_handleClickNone() {
console.log("Clear Slot");
}
_handleClickItem(e: Event) {
const div = e.currentTarget as HTMLDivElement;
const key = div.getAttribute("key");
const entry = this.deviceDB.db[key];
const device = window.VM.vm.devices.get(this.deviceID);
const dbDevice = this.deviceDB.db[device.prefabName]
const sorting = this.deviceDB.enums["SortingClass"][entry.item.sorting ?? "Default"] ?? 0;
console.log("using entry", dbDevice);
const fields: { [key in SlotLogicType]?: LogicField } = Object.fromEntries(
Object.entries(dbDevice.slotlogic[this.slotIndex] ?? {})
.map(([slt_s, field_type]) => {
let slt = slt_s as SlotLogicType;
let value = 0.0
if (slt === "FilterType") {
value = this.deviceDB.enums["GasType"][entry.item.filtertype]
}
const field: LogicField = { field_type, value};
return [slt, field];
})
);
fields["PrefabHash"] = { field_type: "Read", value: entry.hash };
fields["MaxQuantity"] = { field_type: "Read", value: entry.item.maxquantity ?? 1.0 };
fields["SortingClass"] = { field_type: "Read", value: sorting };
const template: SlotOccupantTemplate = {
fields
}
window.VM.vm.setDeviceSlotOccupant(this.deviceID, this.slotIndex, template);
}
@query("sl-dialog.slot-add-dialog") dialog: SlDialog;
@query(".device-search-input") searchInput: SlInput;
render() {
const device = window.VM.vm.devices.get(this.deviceID);
const name = device?.name ?? device?.prefabName ?? "";
const id = this.deviceID ?? 0;
return html`
<sl-dialog
label="Edit device ${id} : ${name} Slot ${this.slotIndex}"
class="slot-add-dialog"
@sl-hide=${this._handleDialogHide}
>
<sl-input class="device-search-input" autofocus placeholder="filter" clearable
@sl-input=${this._handleSearchInput}>
<span slot="prefix">Search Items</span>
<sl-icon slot="suffix" name="search"></sl-icon>
</sl-input>
${when(
typeof this.deviceID !== "undefined" &&
typeof this.slotIndex !== "undefined",
() => html`
<div class="flex flex-row overflow-x-auto">
${this.renderSearchResults()}
</div>
`,
() => html``,
)}
</sl-dialog>
`;
}
private filterTimeout: number | undefined;
_handleSearchInput(_e: CustomEvent) {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
const that = this;
this.filterTimeout = setTimeout(() => {
that.filter = that.searchInput.value;
that.filterTimeout = undefined;
}, 200);
}
_handleDialogHide() {
this.deviceID = undefined;
this.slotIndex = undefined;
}
@state() private deviceID: number;
@state() private slotIndex: number;
show(deviceID: number, slotIndex: number) {
this.deviceID = deviceID;
this.slotIndex = slotIndex;
this.dialog.show();
this.searchInput.select();
}
hide() {
this.dialog.hide();
}
}

View File

@@ -90,16 +90,6 @@ export class VmDeviceTemplate extends VMDeviceDBMixin(BaseElement) {
}
setupState() {
const slotlogicmap: { [key: number]: SlotLogicType[] } = {};
for (const [slt, slotIndexes] of Object.entries(
this.dbDevice?.slotlogic ?? {},
)) {
for (const slotIndex of slotIndexes) {
const list = slotlogicmap[slotIndex] ?? [];
list.push(slt as SlotLogicType);
slotlogicmap[slotIndex] = list;
}
}
this.fields = Object.fromEntries(
Object.entries(this.dbDevice?.logic ?? {}).map(([lt, ft]) => {

View File

@@ -1,4 +1,14 @@
import { LogicType, SlotLogicType, SortingClass, SlotType, FieldType, ReagentMode, BatchMode, ConnectionType, ConnectionRole } from "ic10emu_wasm";
import {
LogicType,
SlotLogicType,
SortingClass,
SlotType,
FieldType,
ReagentMode,
BatchMode,
ConnectionType,
ConnectionRole,
} from "ic10emu_wasm";
export interface DeviceDBItem {
slotclass: SlotType;
sorting: SortingClass;
@@ -6,7 +16,7 @@ export interface DeviceDBItem {
filtertype?: string;
consumable?: boolean;
ingredient?: boolean;
reagents?: { [key: string]: number};
reagents?: { [key: string]: number };
}
export interface DeviceDBDevice {
@@ -22,6 +32,22 @@ export interface DeviceDBConnection {
name: string;
}
export interface DeviceDBInstruction {
typ: string;
value: number;
desc: string;
}
export interface DeviceDBMemory {
size: number;
sizeDisplay: string;
access: MemoryAccess
instructions?: { [key: string]: DeviceDBInstruction };
}
export type MemoryAccess = "Read" | "Write" | "ReadWrite" | "None";
export interface DeviceDBEntry {
name: string;
hash: number;
@@ -29,12 +55,15 @@ export interface DeviceDBEntry {
desc: string;
slots?: { name: string; typ: SlotType }[];
logic?: { [key in LogicType]?: FieldType };
slotlogic?: { [key in SlotLogicType]?: number[] };
slotlogic?: { [key: number]: {[key in SlotLogicType]?: FieldType } };
modes?: { [key: number]: string };
conn?: { [key: number]: DeviceDBConnection };
conn?: { [key: number]: DeviceDBConnection }
item?: DeviceDBItem;
device?: DeviceDBDevice;
};
transmitter: boolean;
receiver: boolean;
memory?: DeviceDBMemory;
}
export interface DBStates {
activate: boolean;
@@ -45,6 +74,12 @@ export interface DBStates {
open: boolean;
}
export interface DeviceDBReagent {
Hash: number;
Unit: string;
Sources?: { [key: string]: number };
}
export interface DeviceDB {
logic_enabled: string[];
slot_logic_enabled: string[];
@@ -55,6 +90,6 @@ export interface DeviceDB {
[key: string]: DeviceDBEntry;
};
names_by_hash: { [key: number]: string };
reagent_hashes: { [key: string]: number}
};
reagents: { [key: string]: DeviceDBReagent };
enums: { [key: string]: { [key: string]: number } };
}

View File

@@ -5,6 +5,11 @@ from pathlib import Path
from pprint import pprint
from typing import Any, NotRequired, TypedDict # type: ignore[Any]
try:
import markdown
except ImportError:
markdown = None
class SlotInsert(TypedDict):
SlotIndex: str
@@ -40,6 +45,24 @@ class PediaPageDevice(TypedDict):
DevicesLength: NotRequired[int]
class MemoryInstruction(TypedDict):
Type: str
Value: int
Description: str
class PediaPageMemory(TypedDict):
MemorySize: int
MemorySizeReadable: str
MemoryAccess: str
Instructions: dict[str, MemoryInstruction] | None
class PediaPageLogicInfo(TypedDict):
LogicSlotTypes: dict[str, dict[str, str]]
LogicTypes: dict[str, str]
class PediaPage(TypedDict):
Key: str
Title: str
@@ -51,13 +74,30 @@ class PediaPage(TypedDict):
LogicSlotInsert: list[LInsert]
ModeInsert: list[LInsert]
ConnectionInsert: list[LInsert]
Device: NotRequired[PediaPageDevice]
LogicInfo: PediaPageLogicInfo | None
Item: NotRequired[PediaPageItem]
Device: NotRequired[PediaPageDevice]
WirelessLogic: bool | None
Memory: PediaPageMemory | None
TransmissionReceiver: bool | None
class ScriptCommand(TypedDict):
desc: str
example: str
class PediaReagent(TypedDict):
Hash: int
Unit: str
Sources: dict[str, float] | None
class Pedia(TypedDict):
pages: list[PediaPage]
reagents: dict[str, int]
scriptCommands: dict[str, ScriptCommand]
class DBSlot(TypedDict):
name: str
@@ -96,6 +136,19 @@ class DBPageItem(TypedDict):
reagents: NotRequired[dict[str, float]]
class DBPageMemoryInstruction(TypedDict):
typ: str
value: int
desc: str
class DBPageMemory(TypedDict):
size: int
sizeDisplay: str
access: str
instructions: dict[str, DBPageMemoryInstruction] | None
class DBPage(TypedDict):
name: str
hash: int
@@ -103,16 +156,21 @@ class DBPage(TypedDict):
desc: str
slots: list[DBSlot] | None
logic: dict[str, str] | None
slotlogic: dict[str, list[int]] | None
slotlogic: dict[str, dict[str, str]] | None
modes: dict[int, str] | None
conn: dict[int, DBPageConnection] | None
item: NotRequired[DBPageItem]
device: NotRequired[DBPageDevice]
transmitter: bool
receiver: bool
memory: DBPageMemory | None
translation_regex = re.compile(r"<N:([A-Z]{2}):(\w+)>")
translation_keys: set[str] = set()
translation_codes: set[str] = set()
def replace_translation(m: re.Match[str]) -> str:
match m.groups():
case (code, key):
@@ -123,19 +181,67 @@ def replace_translation(m: re.Match[str]) -> str:
print("bad translation match?", g, m.string)
return m.string
def trans(s: str) -> str:
return re.sub(translation_regex, replace_translation, s)
color_regex = re.compile(
r"<color=(#?\w+)>((:?(?!<color=(?:#?\w+)>).)+?)</color>", re.DOTALL
)
link_regex = re.compile(r"<link=(\w+)>(.+?)</link>")
def strip_color(s: str) -> str:
replacemnt = r"\2"
last = s
new = color_regex.sub(replacemnt, last)
while new != last:
last = new
new = color_regex.sub(replacemnt, last)
return new
def color_to_html(s: str) -> str:
replacemnt = r"""<div style="color: \1;">\2</div>"""
last = s
new = color_regex.sub(replacemnt, last)
while new != last:
last = new
new = color_regex.sub(replacemnt, last)
return new
def strip_link(s: str) -> str:
replacemnt = r"\2"
last = s
new = link_regex.sub(replacemnt, last)
while new != last:
last = new
new = link_regex.sub(replacemnt, last)
return new
def extract_all() -> None:
db: dict[str, DBPage] = {}
pedia: Pedia = {"pages": [], "reagents": {}}
linkPat = re.compile(r"<link=\w+><color=[\w#]+>(.+?)</color></link>")
pedia: Pedia = {"pages": [], "reagents": {}, "scriptCommands": {}}
with (Path("data") / "Stationpedia.json").open("r") as f:
pedia = json.load(f)
for page in pedia["pages"]:
item: DBPage = defaultdict(list) # type: ignore[reportAssignmentType]
item: DBPage = {
"name": "",
"hash": 0,
"title": "",
"desc": "",
"slots": None,
"logic": None,
"slotlogic": None,
"modes": None,
"conn": None,
"transmitter": False,
"receiver": False,
"memory": None,
}
match page:
case {
"Key": _,
@@ -149,7 +255,6 @@ def extract_all() -> None:
"ModeInsert": modes,
"ConnectionInsert": conninsert,
}:
connNames = {
int(insert["LogicAccessTypes"]): insert["LogicName"]
for insert in conninsert
@@ -157,10 +262,14 @@ def extract_all() -> None:
device = page.get("Device", None)
item_props = page.get("Item", None)
logicinfo = page.get("LogicInfo", None)
wireless = page.get("WirelessLogic", False)
receiver = page.get("TransmissionReceiver", False)
memory = page.get("Memory", None)
item["name"] = name
item["hash"] = name_hash
item["title"] = trans(title)
item["desc"] = trans(re.sub(linkPat, r"\1", desc))
item["desc"] = trans(strip_link(strip_color(desc)))
match slots:
case []:
item["slots"] = None
@@ -178,7 +287,7 @@ def extract_all() -> None:
case _:
item["logic"] = {}
for lat in logic:
item["logic"][re.sub(linkPat, r"\1", lat["LogicName"])] = (
item["logic"][strip_link(strip_color(lat["LogicName"]))] = (
lat["LogicAccessTypes"].replace(" ", "")
)
@@ -189,8 +298,8 @@ def extract_all() -> None:
item["slotlogic"] = {}
for slt in slotlogic:
item["slotlogic"][
re.sub(linkPat, r"\1", slt["LogicName"])
] = [int(s) for s in slt["LogicAccessTypes"].split(", ")]
strip_link(strip_color(slt["LogicName"]))
] = {s: "Read" for s in slt["LogicAccessTypes"].split(", ")}
match modes:
case []:
@@ -216,7 +325,6 @@ def extract_all() -> None:
"HasActivateState": hasActivateState,
"HasColorState": hasColorState,
}:
match connections:
case []:
item["conn"] = None
@@ -256,7 +364,7 @@ def extract_all() -> None:
item["device"] = dbdevice
case _:
print(f"NON-CONFORMING: ")
print("NON-CONFORMING: ")
pprint(device)
return
@@ -305,18 +413,70 @@ def extract_all() -> None:
item["item"] = dbitem
case _:
print(f"NON-CONFORMING: ")
print("NON-CONFORMING: ")
pprint(item_props)
return
match logicinfo:
case None:
pass
case _:
for lt, access in logicinfo["LogicTypes"].items():
if item["logic"] is None:
item["logic"] = {}
item["logic"][lt] = access
for slot, slotlogicinfo in logicinfo["LogicSlotTypes"].items():
if item["slotlogic"] is None:
item["slotlogic"] = {}
if slot not in item["slotlogic"]:
item["slotlogic"][slot] = {}
for slt, access in slotlogicinfo.items():
item["slotlogic"][slot][slt] = access
if wireless:
item["transmitter"] = True
if receiver:
item["receiver"] = True
match memory:
case None:
pass
case _:
item["memory"] = {
"size": memory["MemorySize"],
"sizeDisplay": memory["MemorySizeReadable"],
"access": memory["MemoryAccess"],
"instructions": None,
}
instructions = memory.get("Instructions", None)
match instructions:
case None:
pass
case _:
def condense_lines(s: str) -> str:
return "\r\n".join(
[" ".join(line.split()) for line in s.splitlines()]
)
item["memory"]["instructions"] = {
inst: {
"typ": info["Type"],
"value": info["Value"],
"desc": condense_lines(
strip_color(strip_link(info["Description"]))
),
}
for inst, info in instructions.items()
}
case _:
print(f"NON-CONFORMING: ")
print("NON-CONFORMING: ")
pprint(page)
return
db[name] = item
print("Translation codes:")
pprint(translation_codes)
print("Translations keys:")
@@ -340,11 +500,28 @@ def extract_all() -> None:
return [clean_nones(x) for x in value if x is not None] # type: ignore[unknown]
elif isinstance(value, dict):
return {
key: clean_nones(val) for key, val in value.items() if val is not None # type: ignore[unknown]
key: clean_nones(val)
for key, val in value.items() # type:ignore[reportUnknownVariable]
if val is not None
}
else:
return value # type: ignore[Any]
enums: dict[str, dict[str, int]] = {}
with open("data/Enums.json", "r") as f:
exported_enums: dict[str, dict[str, int]] = json.load(f)
for cat, cat_enums in exported_enums.items():
for enum, val in cat_enums.items():
key = cat
if cat == "Enums":
if "." in enum:
key, enum = enum.split(".")
else :
key = "Condition"
if key not in enums:
enums[key] = {}
enums[key][enum] = val
with open("data/database.json", "w") as f:
json.dump(
clean_nones(
@@ -358,7 +535,8 @@ def extract_all() -> None:
"names_by_hash": {
page["hash"]: page["name"] for page in db.values()
},
"reagent_hashes": pedia["reagents"]
"reagents": pedia["reagents"],
"enums": enums,
}
),
f,