Compare commits

...

2 Commits

Author SHA1 Message Date
CodedSakura 4fb19ada79 fix issue with stale metadata throwing errors 2026-08-11 15:38:36 +03:00
CodedSakura bf66f5ea31 fix moderator line validation 2026-08-11 15:27:18 +03:00
9 changed files with 84 additions and 41 deletions

View File

@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GitSharedSettings">
<option name="FORCE_PUSH_PROHIBITED_PATTERNS">
<list />
</option>
<option name="synchronizeBranchProtectionRules" value="false" />
</component>
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>

View File

@ -0,0 +1 @@
{"addons":[],"configuration":{"nuclearcraft:overhaul_sfr":{"blocks":[{"name":"nuclearcraft:solid_fission_controller","type":"legacy_block"},{"name":"nuclearcraft:fission_vent","type":"legacy_block","blockstate":{"active":false}},{"name":"nuclearcraft:fission_vent","type":"legacy_block","blockstate":{"active":true}},{"name":"nuclearcraft:fission_casing","type":"legacy_block"},{"name":"nuclearcraft:fission_glass","type":"legacy_block"},{"metadata":2,"name":"nuclearcraft:fission_source","type":"legacy_block","blockstate":{"type":"californium"}},{"name":"nuclearcraft:solid_fission_cell","type":"legacy_block","modules":{"ncpf:block_recipes":{"recipes":[{"oredict":"ingotHEU233ZA","type":"oredict"}]}}},{"name":"nuclearcraft:fission_cell_port","type":"legacy_block","blockstate":{"active":false},"modules":{"ncpf:block_recipes":{"recipes":[{"oredict":"ingotHEU233ZA","type":"oredict"}]}}},{"name":"nuclearcraft:fission_cell_port","type":"legacy_block","blockstate":{"active":true},"modules":{"ncpf:block_recipes":{"recipes":[{"oredict":"ingotHEU233ZA","type":"oredict"}]}}},{"name":"nuclearcraft:heavy_water_moderator","type":"legacy_block"},{"metadata":0,"name":"nuclearcraft:fission_shield","type":"legacy_block","blockstate":{"active":false,"type":"boron_silver"}},{"metadata":0,"name":"nuclearcraft:fission_shield","type":"legacy_block","blockstate":{"active":true,"type":"boron_silver"}}],"coolant_recipes":[{"elements":[{"name":"water","type":"legacy_fluid"},{"name":"condensate_water","type":"legacy_fluid"}],"type":"list"}]}},"designs":[{"design":[[[3,3,3,3,3,3,3,3,3],[3,0,1,2,7,8,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,3,3,3,3,3,3,3,3]],[[3,5,4,4,4,4,4,4,3],[4,6,-1,-1,-1,6,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,9,-1,-1,-1,9,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,10,-1,-1,-1,10,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,9,-1,-1,-1,9,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,6,9,11,9,6,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,4,4,4,4,4,4,4,3],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[4,-1,-1,-1,-1,-1,-1,-1,4],[3,4,4,4,4,4,4,4,3]],[[3,3,3,3,3,3,3,3,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,4,4,4,4,4,4,4,3],[3,3,3,3,3,3,3,3,3]]],"block_recipes":[[[0,0]],[[0,0]],[[0,0]]],"type":"nuclearcraft:overhaul_sfr","coolant_recipe":0,"dimensions":[9,7,9]}],"version":1}

View File

@ -126,7 +126,7 @@
</section> </section>
</aside> </aside>
<footer> <footer>
<div>alpha 1.7</div> <div>alpha 1.8</div>
<div> <div>
<a href="https://discord.gg/Eq72HwPqfg">Discord server</a> <a href="https://discord.gg/Eq72HwPqfg">Discord server</a>
</div> </div>

View File

@ -39,7 +39,7 @@ registerLoadCallback(() => {
}); });
awaitEvent("config:end").then(() => { awaitEvent("config:end").then(() => {
void loadExampleFile("Pandora's Fission Reactor"); void loadExampleFile("shield test");
}); });
queueMicrotask(() => emitEvent("dev-mode:end")); queueMicrotask(() => emitEvent("dev-mode:end"));

View File

@ -18,6 +18,8 @@ export function setDomMetadata(domNode, data) {
export function setCellMetadata(node, key, value) { export function setCellMetadata(node, key, value) {
if (!node.dataset.metadata) { if (!node.dataset.metadata) {
node.dataset.metadata = createMetadata({ [key]: value }).toString(10); node.dataset.metadata = createMetadata({ [key]: value }).toString(10);
} else if (!metadata[Number(node.dataset.metadata)]) {
metadata[Number(node.dataset.metadata)] = { [key]: value };
} else { } else {
metadata[Number(node.dataset.metadata)][key] = value; metadata[Number(node.dataset.metadata)][key] = value;
} }
@ -38,6 +40,7 @@ export function getMetadata(id) {
return metadata[id]; return metadata[id];
} }
export function getCellMetadata(node, key) { export function getCellMetadata(node, key) {
if (!node.dataset.metadata) return null;
return metadata[Number(node.dataset.metadata)][key]; return metadata[Number(node.dataset.metadata)][key];
} }
@ -53,6 +56,7 @@ export function deleteMetadata(id) {
} }
export function clearCellMetadata(node, key) { export function clearCellMetadata(node, key) {
if (!node.dataset.metadata) return; if (!node.dataset.metadata) return;
if (!metadata[Number(node.dataset.metadata)]) return;
delete metadata[Number(node.dataset.metadata)][key]; delete metadata[Number(node.dataset.metadata)][key];
processCellOverlays(node, key, false); processCellOverlays(node, key, false);
} }

View File

@ -3,6 +3,8 @@ import { getAtlasIndexFromMetadata, makeAtlasImage } from "./atlas.js";
export function processCellOverlays(node, key = null, added = null) { export function processCellOverlays(node, key = null, added = null) {
if (key) { if (key) {
node.replaceChildren(...node.querySelectorAll(`:scope > *:not([data-overlay="${key}"])`));
const metadata = getCellMetadata(node, key); const metadata = getCellMetadata(node, key);
const atlasIndex = getAtlasIndexFromMetadata(metadata); const atlasIndex = getAtlasIndexFromMetadata(metadata);
if (atlasIndex && atlasIndex !== -1) { if (atlasIndex && atlasIndex !== -1) {
@ -12,15 +14,10 @@ export function processCellOverlays(node, key = null, added = null) {
node.appendChild(overlayNode); node.appendChild(overlayNode);
} }
if (key === "active" && metadata) { if (key === "active" && added) {
const overlayNode = makeAtlasImage(-1); const overlayNode = makeAtlasImage(-1);
overlayNode.dataset.overlay = key; overlayNode.dataset.overlay = key;
overlayNode.classList.add("planner--overlay"); overlayNode.dataset.active = metadata ? "true" : "false";
node.appendChild(overlayNode);
}
if (key === "active" && !metadata) {
const overlayNode = makeAtlasImage(-1);
overlayNode.dataset.overlay = "inactive";
overlayNode.classList.add("planner--overlay"); overlayNode.classList.add("planner--overlay");
node.appendChild(overlayNode); node.appendChild(overlayNode);
} }

View File

@ -6,7 +6,7 @@ import { initialize3dArray } from "./js-utils.js";
import { recall, save } from "./storage.js"; import { recall, save } from "./storage.js";
import { registerLoadCallback } from "./main.js"; import { registerLoadCallback } from "./main.js";
import { getBlockPickerActiveItem, getBlockPickerRecipe } from "./block-picker.js"; import { getBlockPickerActiveItem, getBlockPickerRecipe } from "./block-picker.js";
import { clearCellMetadata, getMetadata, setCellMetadata } from "./metadata.js"; import { clearCellMetadata, deleteMetadata, getMetadata, setCellMetadata } from "./metadata.js";
import { retainTooltipHover } from "./tooltip.js"; import { retainTooltipHover } from "./tooltip.js";
import { checkEquivalence, lookupFromMetadata, parseRuleAsString } from "./ncpf-utils.js"; import { checkEquivalence, lookupFromMetadata, parseRuleAsString } from "./ncpf-utils.js";
@ -250,13 +250,14 @@ function cellClickEvent(e) {
if (e.target.tile === "-1") return; if (e.target.tile === "-1") return;
e.target.dataset.previewRemove = "yes"; e.target.dataset.previewRemove = "yes";
clearCellMetadata(e.target, "block_recipe"); deleteMetadata(e.target);
} else if (e.buttons === 1) { } else if (e.buttons === 1) {
// add // add
if (e.target.dataset.preview === activeItem.toString(10)) return; if (e.target.dataset.preview === activeItem.toString(10)) return;
e.target.dataset.preview = activeItem.toString(10); e.target.dataset.preview = activeItem.toString(10);
e.target.replaceChildren(makeAtlasImage(activeItem)); e.target.replaceChildren(makeAtlasImage(activeItem));
deleteMetadata(e.target);
const pickerRecipe = getBlockPickerRecipe(); const pickerRecipe = getBlockPickerRecipe();
if (pickerRecipe) { if (pickerRecipe) {
setCellMetadata(e.target, "block_recipe", pickerRecipe); setCellMetadata(e.target, "block_recipe", pickerRecipe);

View File

@ -7,11 +7,14 @@ import {
getPlannerMultiblockType getPlannerMultiblockType
} from "./planner.js"; } from "./planner.js";
import { checkEquivalence, findFullEntry, findFullEntryFromAtlasMetadata } from "./ncpf-utils.js"; import { checkEquivalence, findFullEntry, findFullEntryFromAtlasMetadata } from "./ncpf-utils.js";
import { deleteMetadata, getMetadata, setCellMetadata, setDomMetadata } from "./metadata.js"; import { clearCellMetadata, deleteMetadata, getMetadata, setCellMetadata, setDomMetadata } from "./metadata.js";
import { registerLoadCallback } from "./main.js"; import { registerLoadCallback } from "./main.js";
import { getAtlasMetadata } from "./atlas.js"; import { getAtlasMetadata } from "./atlas.js";
import { initialize3dArray } from "./js-utils.js"; import { initialize3dArray } from "./js-utils.js";
const SFR_MODERATOR_MAX_LEN = 3;
const SFR_MODERATOR_REFLECTOR_MAX_LEN = 2;
registerLoadCallback(() => { registerLoadCallback(() => {
listenTo("fileLoad:end", runSolver); listenTo("fileLoad:end", runSolver);
listenTo("planner:cell:change", runSolver); listenTo("planner:cell:change", runSolver);
@ -95,7 +98,8 @@ async function debugBlockSolver(data) {
} }
export async function runSolver() { export async function runSolver() {
emitEvent("solver:begin") const startTime = performance.now()
emitEvent("solver:begin");
const multiblockType = getPlannerMultiblockType(); const multiblockType = getPlannerMultiblockType();
@ -107,6 +111,7 @@ export async function runSolver() {
.map(idx => [idx, getAtlasMetadata(idx)]) .map(idx => [idx, getAtlasMetadata(idx)])
.map(([idx, md]) => [idx, findFullEntry("blocks", md, { configurationHint: multiblockType })])); .map(([idx, md]) => [idx, findFullEntry("blocks", md, { configurationHint: multiblockType })]));
plannerBlocks.forEach(v => v.tile = tileMap[v.tile]); plannerBlocks.forEach(v => v.tile = tileMap[v.tile]);
plannerBlocks.forEach(v => clearCellMetadata(v.dom, "active"));
const plannerBlocksGrid = initialize3dArray(...getPlannerMultiblockSize()); const plannerBlocksGrid = initialize3dArray(...getPlannerMultiblockSize());
plannerBlocks.forEach(b => { plannerBlocks.forEach(b => {
@ -158,6 +163,7 @@ export async function runSolver() {
} }
setCellMetadata(cell.dom, "primer", cell.primer); setCellMetadata(cell.dom, "primer", cell.primer);
}); });
console.log(fuelCells)
await debugBlockSolver("primed"); await debugBlockSolver("primed");
@ -167,46 +173,70 @@ export async function runSolver() {
while (activeCellIndex < activeCells.length) { while (activeCellIndex < activeCells.length) {
const cell = activeCells[activeCellIndex]; const cell = activeCells[activeCellIndex];
if (!cell.axes) return; // ignore bad cells if (!cell.axes) return; // ignore bad cells
Object.keys(sixAxes).map((name, i) => { Object.keys(sixAxes).map((directionName, i) => {
let moderatorSum = 0; let valid = false;
let moderatorPath = []; let moderatorPath = [];
let length = 0;
let reflectMultiplier = 1;
let reflect = false;
let fluxDestination;
for (const block of cell.axes[i]) { for (const block of cell.axes[i]) {
if (!block) break; if (!block) break;
if (block.tile.modules["nuclearcraft:overhaul_sfr:moderator"]) { if (block.tile.modules["nuclearcraft:overhaul_sfr:moderator"]) {
moderatorSum += block.tile.modules["nuclearcraft:overhaul_sfr:moderator"].flux;
moderatorPath.push(block); moderatorPath.push(block);
seenModerators.add(block); seenModerators.add(block);
if (!block.flux) { length += 1;
block.flux = {}; continue;
} }
block.flux[name] = moderatorSum; if (block.tile.modules["nuclearcraft:overhaul_sfr:neutron_shield"]) {
length += 1;
continue; continue;
} }
if (block.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"] || block.tile.modules["nuclearcraft:overhaul_sfr:irradiator"]) { if (block.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"] || block.tile.modules["nuclearcraft:overhaul_sfr:irradiator"]) {
block.flux = (block.flux ?? 0) + moderatorSum; valid = length <= SFR_MODERATOR_MAX_LEN;
fluxDestination = block;
} }
if (block.tile.modules["nuclearcraft:overhaul_sfr:reflector"]) { if (block.tile.modules["nuclearcraft:overhaul_sfr:reflector"]) {
const backAxis = name.replace(/^[+-]/, s => s === "+" ? "-" : "+"); valid = length <= SFR_MODERATOR_REFLECTOR_MAX_LEN;
for (const blockBack of moderatorPath.toReversed()) { reflect = true;
moderatorSum += blockBack.tile.modules["nuclearcraft:overhaul_sfr:moderator"].flux; reflectMultiplier = block.tile.modules["nuclearcraft:overhaul_sfr:reflector"].reflectivity;
moderatorPath.push(blockBack); console.log(reflectMultiplier)
blockBack.flux[backAxis] = moderatorSum; fluxDestination = cell;
}
cell.flux = (cell.flux ?? 0) + moderatorSum;
}
if (block.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"] && !block.active) {
if (!block.recipe) break; // FIXME
const fuelStats = block.recipe.modules["nuclearcraft:overhaul_sfr:fuel_stats"];
if (fuelStats.criticality <= block.flux) {
block.active = true;
activeCells.push(block);
}
} }
break; break;
} }
if (moderatorPath.length > 0) { if (moderatorPath.length < 1) {
valid = false;
}
if (!valid) return;
moderatorPath[0].active = true; moderatorPath[0].active = true;
let totalFlux = 0;
for (const mod of moderatorPath) {
totalFlux += mod.tile.modules["nuclearcraft:overhaul_sfr:moderator"].flux;
if (!mod.flux) {
mod.flux = {};
}
mod.flux[directionName] = totalFlux;
}
if (reflect) {
totalFlux *= reflectMultiplier;
const backAxis = directionName.replace(/^[+-]/, s => s === "+" ? "-" : "+");
for (const mod of moderatorPath.toReversed()) {
totalFlux += mod.tile.modules["nuclearcraft:overhaul_sfr:moderator"].flux * reflectMultiplier;
mod.flux[backAxis] = totalFlux;
}
}
fluxDestination.flux = (fluxDestination.flux ?? 0) + totalFlux;
if (fluxDestination.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"] && !fluxDestination.active) {
if (!fluxDestination.recipe) return; // FIXME
const fuelStats = fluxDestination.recipe.modules["nuclearcraft:overhaul_sfr:fuel_stats"];
if (fuelStats.criticality <= fluxDestination.flux) {
fluxDestination.active = true;
activeCells.push(fluxDestination);
}
} }
}); });
@ -249,7 +279,8 @@ export async function runSolver() {
if (n.tile.modules) { if (n.tile.modules) {
return n.tile.modules["nuclearcraft:overhaul_sfr:reflector"] return n.tile.modules["nuclearcraft:overhaul_sfr:reflector"]
|| n.tile.modules["nuclearcraft:overhaul_sfr:irradiator"] || n.tile.modules["nuclearcraft:overhaul_sfr:irradiator"]
|| n.tile.modules["nuclearcraft:overhaul_sfr:casing"]; || n.tile.modules["nuclearcraft:overhaul_sfr:casing"]
|| n.tile.modules["nuclearcraft:overhaul_sfr:neutron_shield"];
} }
return false; return false;
}); });
@ -277,6 +308,9 @@ export async function runSolver() {
await debugBlockSolver("heatsinks"); await debugBlockSolver("heatsinks");
} }
const endTime = performance.now()
console.log(`Solver took ${endTime - startTime}ms`);
} }
function checkHeatSinkRule(hs, rule, activeNeighbors) { function checkHeatSinkRule(hs, rule, activeNeighbors) {

View File

@ -271,11 +271,11 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
.planner--cell > .planner--overlay[data-overlay="block_recipe"] { .planner--cell > .planner--overlay[data-overlay="block_recipe"] {
transform: scale(var(--recipe-scale-factor, 0.8)); transform: scale(var(--recipe-scale-factor, 0.8));
} }
#planner .planner--cell > .planner--overlay[data-overlay="active"] { #planner .planner--cell > .planner--overlay[data-overlay="active"][data-active="true"] {
outline-offset: calc(var(--scale-factor) * -1px); outline-offset: calc(var(--scale-factor) * -1px);
outline: calc(var(--scale-factor) * 1px) solid var(--cell-active-outline, #0f08); outline: calc(var(--scale-factor) * 1px) solid var(--cell-active-outline, #0f08);
} }
#planner .planner--cell > .planner--overlay[data-overlay="inactive"] { #planner .planner--cell > .planner--overlay[data-overlay="active"][data-active="false"] {
outline-offset: calc(var(--scale-factor) * -1px); outline-offset: calc(var(--scale-factor) * -1px);
outline: calc(var(--scale-factor) * 1px) solid var(--cell-inactive-outline, #f008); outline: calc(var(--scale-factor) * 1px) solid var(--cell-inactive-outline, #f008);
} }