| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import type { DataRawDump } from "../factorio-process-data.models.ts";
- /**
- * Compare two prototype objects by their `order` field.
- * If `order` is missing, it defaults to an empty string.
- *
- * @param a - First prototype object.
- * @param b - Second prototype object.
- * @returns Negative if `a.order < b.order`, positive if greater, zero otherwise.
- */
- function orderFactorioPrototype(a: { order?: string }, b: { order?: string }) {
- return (a.order ?? "")?.localeCompare(b.order ?? "");
- }
- export type SubGroup<T> = {
- name: string;
- order?: string;
- children: Array<T>;
- };
- export type Group<T> = {
- name: string;
- order?: string;
- icon?: string;
- subGroup: Array<SubGroup<T>>;
- };
- /** Type of an object that can be grouped by its `subgroup` property. */
- export interface GroupablaPrototype {
- subgroup: string;
- order?: string;
- }
- /**
- * Create a map of subgroup names to their corresponding `SubGroup` objects.
- *
- * @param prototypes - The prototypes to group.
- * @param subGroupsDefinitions - Definition objects for the available subgroups.
- * @returns Map where the key is the subgroup name and the value is a `SubGroup`.
- */
- function createSubGroupMap<T extends GroupablaPrototype>(
- prototypes: Array<T>,
- subGroupsDefinitions: Array<{ name: string; order?: string }>
- ): Map<string, SubGroup<T>> {
- const map = new Map<string, SubGroup<T>>();
- for (const proto of prototypes) {
- if (!map.has(proto.subgroup)) {
- const subGroup = subGroupsDefinitions.find((sg) => sg.name === proto.subgroup);
- if (subGroup) {
- map.set(proto.subgroup, {
- name: subGroup.name,
- order: subGroup.order ?? "",
- children: [],
- });
- }
- }
- const subgroup = map.get(proto.subgroup);
- subgroup?.children.push(proto);
- }
- return map;
- }
- /**
- * Create a map of group names to their corresponding `Group` objects.
- *
- * @param subGroupMap - Map of subgroup names to `SubGroup` objects.
- * @param groupsDef - Definition objects for the available groups.
- * @param subGroupsDef - Definition objects for the available subgroups.
- * @returns Map where the key is the group name and the value is a `Group`.
- */
- function createGroupMap<T extends GroupablaPrototype>(
- subGroupMap: Map<string, SubGroup<T>>,
- groupsDef: Array<{ name: string; order?: string }>,
- subGroupsDef: Array<{ name: string; group: string; order?: string }>
- ): Map<string, Group<T>> {
- const map = new Map<string, Group<T>>();
- for (const subGroupDef of subGroupsDef) {
- const subGroup = subGroupMap.get(subGroupDef.name);
- if (!subGroup || subGroup.children.length === 0) continue;
- if (!map.has(subGroupDef.group)) {
- const groupDef = groupsDef.find((g) => g.name === subGroupDef.group);
- if (groupDef) {
- map.set(subGroupDef.group, {
- name: groupDef.name,
- icon: `item-group/${groupDef.name}.png`,
- order: groupDef.order,
- subGroup: [],
- });
- }
- }
- map.get(subGroupDef.group)?.subGroup.push(subGroup);
- }
- return map;
- }
- /**
- * Sort groups, subgroups, and their children by the `order` field.
- *
- * @param groups - Array of `Group` objects to be sorted.
- */
- function sortGroups<T extends GroupablaPrototype>(groups: Group<T>[]) {
- groups.sort(orderFactorioPrototype);
- for (const group of groups) {
- group.subGroup.sort(orderFactorioPrototype);
- for (const subGroup of group.subGroup) {
- subGroup.children.sort(orderFactorioPrototype);
- }
- }
- }
- /**
- * Remove the `order` property from all groups, subgroups, and prototypes.
- *
- * @param groups - Array of `Group` objects from which to delete `order`.
- */
- function stripOrder<T extends GroupablaPrototype>(groups: Group<T>[]) {
- for (const group of groups) {
- delete group.order;
- group.subGroup.sort(orderFactorioPrototype);
- for (const subGroup of group.subGroup) {
- delete subGroup.order;
- for (const child of subGroup.children) {
- delete child.order;
- }
- }
- }
- }
- /**
- * Group the factorio prototypes according to there subgroups
- * @param arr the array of item to be grouped
- * @param data the rawData object extracted from Factorio
- * @param keepOrder flag to indicate if the order values must be kept in the final output
- * @returns
- */
- export function groupPrototypes<T extends GroupablaPrototype>(
- arr: Array<T>,
- data: DataRawDump,
- keepOrder: boolean = true
- ): Group<T>[] {
- const itemGroups = Object.values(data["item-group"]).filter((o) => !o.hidden);
- const itemSubGroups = Object.values(data["item-subgroup"]).filter((o) => !o.hidden);
- const subGroupMap = createSubGroupMap(arr, itemSubGroups);
- const groupMap = createGroupMap(subGroupMap, itemGroups, itemSubGroups);
- const output = Array.from(groupMap.values());
- // Sort the output
- sortGroups(output);
- if (!keepOrder) {
- stripOrder(output);
- }
- return output;
- }
|