Greasy Fork is available in English.
Makes it easy to export large areas
// ==UserScript==
// @name OWOP Export+
// @namespace https://greasyfork.org/en/users/1502179/
// @version 1.0
// @description Makes it easy to export large areas
// @author NothingHere7759
// @match https://ourworldofpixels.com/*
// @exclude https://ourworldofpixels.com/api*
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCA1LjEuMTITAUd0AAAAuGVYSWZJSSoACAAAAAUAGgEFAAEAAABKAAAAGwEFAAEAAABSAAAAKAEDAAEAAAADAAAAMQECABEAAABaAAAAaYcEAAEAAABsAAAAAAAAAKOTAADoAwAAo5MAAOgDAABQYWludC5ORVQgNS4xLjEyAAADAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAWgBAABAAAAlgAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAAHd36etszaFAAAArVJREFUeF7t27uRE1EQQFGJLLBIAIc0sAgVa9PA2QSwNozFn4KqVm2jq8855hiaGenWM7pL59OD+P756/vx2iN7eXs9H6/do0/HC3BNAiQlQFICJCVAUgIkJUBSAiQlQFLZNL3aXPz49uV46ab8/PX7eOkqqs2KE5CUAEkJkJQASQmQlABJCZCUAEkJkNT69Ht7w/Fsm4vt991+vu2NiROQlABJCZCUAEkJkJQASQmQlABJCZDUeKpdbTi2J/nT+07d+vNNbb/HdGPiBCQlQFICJCVAUgIkJUBSAiQlQFICJDWaVp8u2IRMJ/nbk/dt0/eoTL+/7feY3tcmhLsgQFICJCVAUgIkJUBSAiQlQFICJHWebjimppP36US9Mn2PZ7P9uzkBSQmQlABJCZCUAEkJkJQASQmQlABJjTch1WZge/K+/R7bz7dt+32npt+LE5CUAEkJkJQASQmQlABJCZCUAEkJkNTNb0Iq00n+o9j+faffnxOQlABJCZCUAEkJkJQASQmQlABJCZDU+iZkOgGfmt53avv5ns3095h+z05AUgIkJUBSAiQlQFICJCVAUgIkJUBSAiQlQFICJCVAUgIkJUBSAiQlQFICJCVAUuP/hExN/zNQmf5XgetwApISICkBkhIgKQGSEiApAZISICkBkjofL/zLdGOyvQmZbi6m951+Hh/z8vY6assJSEqApARISoCkBEhKgKQESEqApARIajStPl2wCZmabi4qNiYfYxPCXRAgKQGSEiApAZISICkBkhIgKQGSGk2rL2Fj8timG44pJyApAZISICkBkhIgKQGSEiApAZISIKnVqfYltjcmUzYrf7e94ZhyApISICkBkhIgKQGSEiApAZISICkBkkqm3/9DtVmpVJuLbU5AUgIkJUBSAiQlQFICJCVAUgIkJUBSfwBZPnv4nnRz4wAAAABJRU5ErkJggg==
// @grant none
// @license MIT
// ==/UserScript==
const waitUntil = (probe, cb, t = 200) => {
const id = setInterval(() => { try { if (probe()) { clearInterval(id); cb(); } } catch { } }, t);
};
waitUntil(() => window.OWOP && OWOP.camera?.zoom && OWOP.camera?.centerCameraTo && OWOP.options?.unloadDistance && OWOP.misc?.world?.getChunkAt && OWOP.windowSys?.addWindow && OWOP.windowSys.class?.window && OWOP.windowSys.centerWindow, install);
function install() {
// NH Style
if (!document.getElementById('nhStyle') || +document.getElementById('nhStyle').getAttribute("version") < 1) {
document.getElementById('nhStyle')?.remove();
let nhStyle = document.createElement('style');
nhStyle.id = 'nhStyle';
nhStyle.setAttribute("version", "1");
nhStyle.innerHTML = `.nhCont {
& input {
background-color: rgba(0, 0, 0, 0.3);
color: white;
}
& input::placeholder {
color: #bfbfbf;
}
& > div > input[type="number"],
& > div > input[type="range"],
& > div > input[type="text"],
& > div > select {
flex-grow: 1;
flex-basis: 171px;
}
& select {
background-color: #ABA389;
border: 6px #ABA389 solid;
border-image: url(/img/small_border..png) 6 repeat;
border-image-outset: 1px;
}
& > div {
display: flex;
align-items: center;
}
& > div > label {
text-wrap: nowrap;
}
}`;
document.head.appendChild(nhStyle);
};
// Export function
async function exportArea(x1, y1, x2, y2) {
console.time("export");
OWOP.camera.zoom = 1;
OWOP.options.unloadDistance = Infinity;
x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2;
if (x1 > x2) [x1, x2] = [x2, x1];
if (y1 > y2) [y1, y2] = [y2, y1];
let w = x2 - x1 + 1, h = y2 - y1 + 1;
const canvas = document.createElement("canvas");
canvas.width = w * 16;
canvas.height = h * 16;
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;
for (let c = 0; c < w * h; c++) {
let cx = c % w + x1, cy = Math.floor(c / w) + y1;
const imageData = ctx.createImageData(16, 16);
const data = imageData.data;
if (!OWOP.misc.world.getChunkAt(cx, cy)) {
OWOP.camera.centerCameraTo(cx * 16, cy * 16);
await new Promise((resolve) => {
let checkChunkLoaded = setInterval(() => {
if (OWOP.misc.world.getChunkAt(cx, cy)) {
resolve();
clearInterval(checkChunkLoaded);
}
}, 10);
});
};
let chunk = OWOP.misc.world.getChunkAt(cx, cy);
for (let i = 0; i < data.length; i += 4) {
let p = chunk.get(i / 4 % imageData.width, Math.floor(i / 4 / imageData.width));
[data[i], data[i + 1], data[i + 2], data[i + 3]] = [p & 255, p >> 8 & 255, p >> 16 & 255, 255];
};
ctx.putImageData(imageData, c * 16 % canvas.width, Math.floor(c * 16 / canvas.width) * 16);
};
OWOP.options.unloadDistance = 10;
console.timeEnd("export");
return canvas.toDataURL('image/png');
};
let count = 0; // Counts the number of exports
let exportWin = OWOP.windowSys.addWindow(new OWOP.windowSys.class.window("Export", { closeable: true }, (exportWin) => {
exportWin.container.className = "wincontainer nhCont";
exportWin.container.innerHTML = `<div><label for="esel">Coords measured in: </label><select name="esel" id="esel"><option>Pixels</option><option>Chunks</option></select></div><div><label for="ex1">x1: </label><input type="number" name="ex1" id="ex1"/> <label for="ey1">y1: </label><input type="number" name="ey1" id="ey1"/></div>
<div><label for="ex2">x2: </label><input type="number" name="ex2" id="ex2"/> <label for="ey2">y2: </label><input type="number" name="ey2" id="ey2"/></div>
<button>Export</button>`;
exportWin.container.querySelector("#ex1").addEventListener("blur", () => { exportWin.container.querySelector("#ex1").value = Math.floor(exportWin.container.querySelector("#ex1").value) });
exportWin.container.querySelector("#ex2").addEventListener("blur", () => { exportWin.container.querySelector("#ex2").value = Math.floor(exportWin.container.querySelector("#ex2").value) });
exportWin.container.querySelector("#ey1").addEventListener("blur", () => { exportWin.container.querySelector("#ey1").value = Math.floor(exportWin.container.querySelector("#ey1").value) });
exportWin.container.querySelector("#ey2").addEventListener("blur", () => { exportWin.container.querySelector("#ey2").value = Math.floor(exportWin.container.querySelector("#ey2").value) });
exportWin.container.querySelector("button").addEventListener("click", () => {
count++;
let resultingImageWindow = OWOP.windowSys.addWindow(new OWOP.windowSys.class.window(`Resulting Image #${count}`, { closeable: true }, async (resultingWin) => {
resultingWin.container.className = 'wincontainer centeredChilds';
let image = document.createElement("img");
if (exportWin.container.querySelector("#esel").value == "Chunks") {
image.src = await exportArea(exportWin.container.querySelector("#ex1").value, exportWin.container.querySelector("#ey1").value, exportWin.container.querySelector("#ex2").value, exportWin.container.querySelector("#ey2").value);
} else {
function pxToChunk(n) {
return Math.floor(n / 16);
}
image.src = await exportArea(pxToChunk(exportWin.container.querySelector("#ex1").value), pxToChunk(exportWin.container.querySelector("#ey1").value), pxToChunk(exportWin.container.querySelector("#ex2").value), pxToChunk(exportWin.container.querySelector("#ey2").value));
}
image.onload = () => {
if (image.width < image.height) image.height = 500; else image.width = 500;
OWOP.windowSys.centerWindow(resultingImageWindow);
};
resultingWin.addObj(image);
}));
OWOP.windowSys.centerWindow(resultingImageWindow);
});
}));
exportWin.move(innerWidth - exportWin.realw - 10, 60);
}