diff --git a/.gitignore b/.gitignore index 7e150ad9..9e3f7e90 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,5 @@ dist # Garbage .DS_Store + +.hugo_build.lock \ No newline at end of file diff --git a/README.md b/README.md index 37e52541..f313d493 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# Dark Forest Plugins - -In v0.5 of [Dark Forest](https://zkga.me/), we added the ability to customize the game through "Plugins". These are scripts that are run by the game and provided access to specific aspects of the game. +# Dark Forest ARES Plugins ## WARNING @@ -8,11 +6,42 @@ Plugins are evaluated in the context of your game and can access all of your pri You should not use any plugins that you haven't written yourself or by someone you trust completely. You or someone you trust should control the entire pipeline (such as imported dependencies) and should review plugins before you use them. +# Intro + +In v0.5 of [Dark Forest](https://zkga.me/), Dark Forest office team added the ability to customize the game through "Plugins". These are scripts that are run by the game and provided access to specific aspects of the game. + + + +Dark Forest ARES is a modified version of [Dark Forest v0.6](https://github.com/darkforest-eth/darkforest-v0.6). + +This repository is forked from [Dark Forest Plugins](https://github.com/darkforest-eth/plugins), and we will continue to maintain it. + + + +We deploy DF ARES v0.1.1 on [Redstone](https://redstone.xyz/) , more info please check [here](https://mirror.xyz/dfarchon.eth/8OS1CKPOc2L1ZgwEKmLYheeYKLljsjzxLxrPjFJ9cg8). + +Game Wesite: [https://dfares-redstone.netlify.app](https://dfares-redstone.netlify.app/) + + +| Game Version | Plugin Version | Packages Version | +| ----------------------- | -------------- | ------------------------------------------------------------ | +| Dark Forest v0.6.5 | v0.6.5 | v6.7.29 @darkforest_eth/* [link](https://www.npmjs.com/~ichub_df) | +| Dark Forest ARES v0.1.1 | v0.1.1-dfares | v6.8.5 @dfares/* [link](https://www.npmjs.com/search?q=dfares) | + +If you want to submit the plugins, please use **v0.1.1-dfares** as the version name. + ## Utilities The Dark Forest in game api has two typical interaction points. In the Dark Forest client you'll find the documentation for the [df object](https://github.com/darkforest-eth/client/blob/master/docs/classes/Backend_GameLogic_GameManager.default.md) and the [ui object](https://github.com/darkforest-eth/client/blob/master/docs/classes/Backend_GameLogic_GameUIManager.default.md). -We also provide a series of utilities that plugin authors can use. These are served directly from our website (`https://plugins.zkga.me`) and you can load them in your plugins. Check out what is available in the [javascript directory](javascript/) +| Game Version | df object | ui object | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| Dark Forest v0.6.5 | [link](https://github.com/darkforest-eth/client/blob/master/docs/classes/Backend_GameLogic_GameManager.default.md) | [link](https://github.com/darkforest-eth/client/blob/master/docs/classes/Backend_GameLogic_GameUIManager.default.md) | +| Dark Forest ARES v0.1.1 | [link](https://github.com/dfarchon/DFARES-v0.1/blob/redstone/client/docs/classes/Backend_GameLogic_GameUIManager.default.md) | [link](https://github.com/dfarchon/DFARES-v0.1/blob/redstone/client/docs/classes/Backend_GameLogic_GameUIManager.default.md) | + + + +We also provide a series of utilities that plugin authors can use. These are served directly from our website (`https://dfares-plugins.netlify.app/`) and you can load them in your plugins. Check out what is available in the [javascript directory](javascript/) If we are missing a utility that would be helpful, feel free to open an issue! diff --git a/config.toml b/config.toml index 678fc6f5..84041bfe 100644 --- a/config.toml +++ b/config.toml @@ -1,6 +1,6 @@ -baseURL = "https://plugins.zkga.me" +baseURL = "https://dfares-plugins.netlify.app/" languageCode = "en-us" -title = "Dark Forest Plugins" +title = "Dark Forest ARES Plugins" Paginate = 1000 googleAnalytics = "" theme = "showcase" @@ -8,17 +8,17 @@ disableKinds = ["taxonomy", "taxonomyTerm", "RSS"] staticDir = ["screenshots", "static", "javascript"] [params] - name = "Dark Forest Plugins" - author = "Dark Forest Plugins" - description = "A showcase of Dark Forest plugins from the community!" - message = "Welcome to the Dark Forest Plugin showcase!" + name = "Dark Forest ARES Plugins" + author = "Dark Forest ARES Plugins" + description = "A showcase of Dark Forest ARES plugins from the community!" + message = "Welcome to the Dark Forest ARES Plugin showcase!" hideAutoMenu = false - repo = "darkforest-eth/plugins" - branch = "master" + repo = "dfarchon/plugins" + branch = "main" [[menu.main]] name = "Submit plugin" - url = "https://github.com/darkforest-eth/plugins#adding-your-plugin" + url = "https://github.com/dfarchon/plugins#adding-your-plugin" [social] - twitter = "https://twitter.com/darkforest_eth" + twitter = "https://twitter.com/dfarchon" diff --git a/content/artifacts/artifacts-finder/plugin.js b/content/artifacts/artifacts-finder/plugin.js index 6622e3d5..830c2947 100644 --- a/content/artifacts/artifacts-finder/plugin.js +++ b/content/artifacts/artifacts-finder/plugin.js @@ -1,238 +1,116 @@ -// Artifacts Finder -// -// This plugin offers a button to auto prospect artifacts every 5 minutes and find after prospect finish. -// To stop simply close the plugin -// Simple is Power! - -// Author: SnowTiger - -import { - coords, - canHaveArtifact, -} from 'https://plugins.zkga.me/utils/utils.js'; - -import { - ArtifactType, - PlanetType, - BiomeNames -} from "https://cdn.skypack.dev/@darkforest_eth/types" - import { - isUnconfirmedFindArtifactTx, - isUnconfirmedProspectPlanetTx, -} from 'https://cdn.skypack.dev/@darkforest_eth/serde'; - -// prospect artifacts every 1 minutes -let AUTO_INTERVAL = 1000 * 60 * 1; - - -function blocksLeftToProspectExpiration( - currentBlockNumber, - prospectedBlockNumber -) { - return (prospectedBlockNumber || 0) + 255 - currentBlockNumber; -} - -function prospectExpired(currentBlockNumber, prospectedBlockNumber) { - return blocksLeftToProspectExpiration(currentBlockNumber, prospectedBlockNumber) <= 0; -} - -function gear() { - return df.getMyArtifacts().filter(e => e.artifactType == ArtifactType.ShipGear)[0]; -} - -function whereIsGear() { - const g = gear(); - const pid = (!g || (!!g.onVoyageId && df.getAllVoyages().filter(v => v.eventId == g.onVoyageId).length > 0)) ? undefined : g.onPlanetId; - if (pid !== undefined) { - return df.getPlanetWithId(pid); - } - return pid; -} - -function isFindable(planet, currentBlockNumber) { - return ( - currentBlockNumber !== undefined && - planet.planetType === PlanetType.RUINS && - planet.prospectedBlockNumber !== undefined && - !planet.hasTriedFindingArtifact && - !prospectExpired(currentBlockNumber, planet.prospectedBlockNumber) + html, + render, + useState, +} from "https://unpkg.com/htm/preact/standalone.module.js"; + +let show_planets = []; + +function drawRound(ctx, p, color, width, alpha) { + if (!p || !p.location || !p.location.coords) return; + const viewport = ui.getViewport(); + ctx.strokeStyle = color; + ctx.lineWidth = width; + ctx.globalAlpha = alpha; + const { x, y } = p.location.coords; + const range = p.planetLevel * 20; + const trueRange = viewport.worldToCanvasDist(range); + ctx.beginPath(); + ctx.arc( + viewport.worldToCanvasX(x), + viewport.worldToCanvasY(y), + trueRange, + 0, + 2 * Math.PI ); + ctx.stroke(); } -function isProspectable(planet) { - return ( - planet.planetType === PlanetType.RUINS && - planet.prospectedBlockNumber === undefined - ); -} - -function createDom(tag, text) { - let dom = document.createElement(tag); - if (text) { - let now = new Date(); - now = (now.getMonth() + 1) + "-" + now.getDate() + " " + now.getHours() + - ":" + now.getMinutes() + ":" + now.getSeconds() - dom.innerText = "[" + now + "] " + text; - } - return dom; -} - -function distance(from, to) { - let fromloc = from.location; - let toloc = to.location; - return Math.sqrt((fromloc.coords.x - toloc.coords.x) ** 2 + (fromloc.coords.y - toloc.coords.y) ** 2); -} - -class ArtifactsFinder { - constructor() { - this.logs = null; - this.prospectTimerId = null; - this.findTimerId = null; - this.finding = false; - this.pendingPlanets = []; - this.findArtifactsButton = createDom('button'); - } - - logAction(log, planet) { - let biome = BiomeNames[planet.biome]; - let dom = createDom("div", log.action + " LV" + planet.planetLevel + " " + - biome + " at " + coords(planet)); - dom.addEventListener('click', function () { - ui.centerPlanet(planet) - }); - this.logs.appendChild(dom); - } - - findArtifacts() { - let currentBlockNumber = df.contractsAPI.ethConnection.blockNumber; - let prospectingPlanets = []; - let gearPlanet = whereIsGear(); - if (!gearPlanet) { - return; - } - while (this.pendingPlanets.length > 0) { - if (!this.finding) break; - let planet = this.pendingPlanets.shift(); - if (planet === undefined) { - break; - } - planet = df.getPlanetWithId(planet.locationId); - if (planet.locationId === gearPlanet.locationId && isFindable(planet, currentBlockNumber)) { - try { - let log = { - planet: planet, - action: 'Finding' - } - df.findArtifact(planet.locationId); - this.logAction(log, planet); - } catch (err) { - console.log(err); - } - } else if (planet.prospectedBlockNumber === undefined) { - // still prospecting - prospectingPlanets.push(planet); +function main_ui() { + const [levelFilter, setLevelFilter] = useState(3); + + const cacheArtifactPlanets = () => { + show_planets = []; + for (let planet of df.getAllPlanets()) { + if ( + planet.planetLevel >= levelFilter && + df.isPlanetMineable(planet) && + !planet.hasTriedFindingArtifact + ) { + show_planets.push(planet); } } - Array.from(prospectingPlanets) - .forEach(planet => { - this.pendingPlanets.push(planet); - }) - } - - async prospectArtifacts() { - let gearId = gear()?.id; - let gearPlanet = whereIsGear(); - let currentBlockNumber = df.contractsAPI.ethConnection.blockNumber; - - if (!gearPlanet) { - return; - } - if (gearPlanet.owner === df.account && isProspectable(gearPlanet)) { - if (!gearPlanet.transactions?.hasTransaction(isUnconfirmedProspectPlanetTx)) { - let log = { - planet: gearPlanet, - action: 'Prospecting' - } - this.logAction(log, gearPlanet); - const tx = await df.prospectPlanet(gearPlanet.locationId); - await tx.confirmedPromise; - this.pendingPlanets.push(gearPlanet); - } - } else if (gearPlanet.owner === df.account && isFindable(gearPlanet, currentBlockNumber)) { - if (!gearPlanet.transactions?.hasTransaction(isUnconfirmedFindArtifactTx) && - this.pendingPlanets.filter(p => p.locationId === gearPlanet.locationId).length === 0) { - this.pendingPlanets.push(gearPlanet); - } - } else { - // find nearest Foundry - let ps = Array.from(df.getMyPlanets()) - .filter(canHaveArtifact) - .filter(p => p.locationId !== gearPlanet.locationId) - .map(to => { - return [to, distance(gearPlanet, to)] - }) - .sort((a, b) => a[1] - b[1]); - if (ps.length > 0) { - const to = ps[0][0]; - ui.terminal.current?.printShellLn( - `df.move('${gearPlanet.locationId}', '${to.locationId}', 0, 0, '${gearId}')` - ); - df.move(gearPlanet.locationId, to.locationId, 0, 0, gearId); - let log = { - planet: to, - action: 'Moving to' - } - this.logAction(log, to); - } - } - } + }; + + const handleLevelChange = (e) => { + setLevelFilter(parseInt(e.target.value, 10)); + }; + + const handleHighlight = () => { + cacheArtifactPlanets(); + }; + + const flexRow = { + display: "flex", + flexDirection: "column", + marginTop: "16px", + marginLeft: "10px", + marginBottom: "10px", + }; + + return html`
+ + + +
`; +} - clearTimer() { - if (this.prospectTimerId) { - clearInterval(this.prospectTimerId); - } - if (this.findTimerId) { - clearInterval(this.findTimerId); - } +class Plugin { + constructor() { + this.container = null; } - async startFind() { - this.clearTimer(); - this.finding = !this.finding; - if (this.finding) { - this.logs.appendChild(createDom("div", "Start Finding")); - setTimeout(this.findArtifacts.bind(this), 0); - setTimeout(this.prospectArtifacts.bind(this), 0); - this.prospectTimerId = setInterval(this.prospectArtifacts.bind(this), AUTO_INTERVAL); - this.findTimerId = setInterval(this.findArtifacts.bind(this), 10000); - this.findArtifactsButton.innerText = " Cancel Finding "; - } else { - this.findArtifactsButton.innerText = ' Start Find '; - this.logs.appendChild(createDom("div", "Cancel Find")) - } + draw(ctx) { + ctx.save(); + show_planets.forEach((p) => drawRound(ctx, p, "red", 5, 1)); + ctx.restore(); } async render(container) { - let self = this; - container.style.width = '550px'; - this.findArtifactsButton.innerText = ' Start Find '; - container.appendChild(this.findArtifactsButton); - container.appendChild(createDom('br')); - container.appendChild(createDom('br')); - this.findArtifactsButton.addEventListener('click', () => { - self.startFind() - }); - this.logs = createDom('div'); - container.appendChild(this.logs); - this.logs.style.maxHeight = '300px'; - this.logs.style.overflowX = 'hidden'; - this.logs.style.overflowY = 'scroll'; + this.container = container; + container.style.width = "250px"; + container.style.height = "200px"; + render(html`<${main_ui} />`, container); } destroy() { - this.clearTimer(); + render(null, this.container); } } -export default ArtifactsFinder; +export default Plugin; \ No newline at end of file diff --git a/content/productivity/pink-it/index.md b/content/productivity/pink-it/index.md new file mode 100644 index 00000000..3e94aeef --- /dev/null +++ b/content/productivity/pink-it/index.md @@ -0,0 +1,6 @@ +--- +title: Pink It +date: 2024-01-29T17:52:08.679Z +subtitle: Automatically destroy planets inside pink circle +version: 0.1 +--- diff --git a/content/productivity/pink-it/plugin.js b/content/productivity/pink-it/plugin.js new file mode 100644 index 00000000..1b2c93f2 --- /dev/null +++ b/content/productivity/pink-it/plugin.js @@ -0,0 +1,614 @@ +/* + made for DF Archon Ares v0.1 Round 2 + https://mirror.xyz/dfarchon.eth/hns4_mHAdUvPVDLrnCVxxlg1MrxpQMDgPTHsBgLXhRw + + features: + - can automatically destroy all planets inside the pink circle (using dropped bomb from the pink ship) + - shows a list of all pink circles in view and their owners/operators + - click any planet to see how big a pink circle would be if a bomb were dropped on it +*/ + +import { getPlayerColor } from 'https://cdn.skypack.dev/@dfares/procedural'; + +const pluginName = 'Pink It'; + +const simulate = false; // for testing purposes this can be set to true (if true it wont destroy planets) + +const cSpace = ' '; +const minCircleSizePx = 5; +const minDrawPlanetRadius = 20; +const circleThickness = 2; +const PI2 = Math.PI * 2; + +const pinkCircleRadius = 2000; +const minPinkLevel = 3; // cant pink level below 3 + +let choosenPlanets = []; +let deadPlanets = []; +let dieingPlanet = null; +let stopPinkIt = false; +let excludeMyPlanets = true; +let excludeOwnedPlanets = false; +let pinkItIsRunning = false; +let butPinkIt = null; +let butPinkItIsReady = false; +let myPinkZone = null; +let hlPinkZoneCounter = 0; +const hlPinkZoneCounterMax = 200; +let lastSelectedPlanet = null; +let tablePinkZoneList = null; +let intervUpdateTablePZList = null; +const lastWorldCoords = { + x: Number.MAX_SAFE_INTEGER, + y: Number.MAX_SAFE_INTEGER, +}; +let pzHoveringInList = null; + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function planetHasNoOwner(planet) { + return planet.owner === '0x0000000000000000000000000000000000000000'; +} + +function planetIsMine(planet) { + return planet.owner === df.account; +} + +function createToggleButton(text, onClick, onOrOff = false) { + const button = {}; + button.element = document.createElement('button'); + button.element.innerText = text; + button.onOrOff = false; + button.set = function (b) { + button.onOrOff = b; + if (button.onOrOff) { + // on + button.element.style.background = '#CCC'; + button.element.style.color = '#000000'; + } else { + // off + button.element.style.background = '#333333'; + button.element.style.color = '#FFF'; + } + }; + button.set(onOrOff); + button.element.addEventListener('click', () => { + button.set(!button.onOrOff); + onClick(button.onOrOff); + }); + return button; +} + +function FullButtonLine(buttons) { + const table = document.createElement('table'); + table.style.textAlign = 'center'; + table.style.width = '100%'; + table.style.tableLayout = 'fixed'; // to make all buttons the same width + + let first = true; + for (const button of buttons) { + const td = document.createElement('td'); + const ele = button.element ? button.element : button; + ele.style.border = '1px solid white'; + ele.style.width = '100%'; + td.style.width = '100%'; // to make all buttons the same width + td.style.padding = '5px'; + if (!first) { + td.style.paddingLeft = '0px'; + } + td.append(ele); + table.append(td); + + first = false; + } + + return table; +} + +function createTableHeader(table, strArr) { + const tr = document.createElement('tr'); + for (const str of strArr) { + const th = document.createElement('th'); + th.innerText = str; + th.style.border = '1px solid white'; + tr.appendChild(th); + } + + table.appendChild(tr); +} + +function addAsTd(tr, text, width = null, color = null, center = true) { + const td = document.createElement('td'); + td.style.border = '1px solid white'; + td.innerHTML = text; + if (width) td.width = `${width}px`; + if (color) td.style.color = color; + if (center) td.style['text-align'] = 'center'; + tr.appendChild(td); + + return td; +} + +function intToStrHexColor(num) { + return num.toString(16).toUpperCase().padStart(2, 0); +} + +function percentToStrHexColor(percent) { + return intToStrHexColor(parseInt(percent * 255)); +} + +function getPlanetRingRadius( + planet, + multiplier = 1.3, + min = minDrawPlanetRadius, +) { + const viewport = ui.getViewport(); + const radius = + viewport.worldToCanvasDist(ui.getRadiusOfPlanetLevel(planet.planetLevel)) * + multiplier; + + return radius < min ? min : radius; +} + +function drawRingAnimationOnPlanet(ctx, planet, level, color, reverse = false) { + const viewport = ui.getViewport(); + const { x: planetX, y: planetY } = viewport.worldToCanvasCoords( + planet.location.coords, + ); + + const radius = getPlanetRingRadius(planet); + const animationDuration = 1500 * (1 - level * 0.1); + + let millis = Date.now(); + for (let i = 0; i <= level; ++i) { + drawRingAnimation( + ctx, + planetX, + planetY, + radius, + millis, + animationDuration, + color, + reverse, + ); + millis += animationDuration / (level + 1); + } +} + +function drawRingAnimation( + ctx, + x, + y, + radius, + millis, + animationDuration, + color, + reverse = false, +) { + let time = (millis % animationDuration) / animationDuration; + if (reverse) time = 1 - time; + const thickness = 1 - time * 0.2; + let opacity = 1 - time; + if (opacity > 0.6) opacity *= 1 - (opacity - 0.6) / 0.4; + opacity = percentToStrHexColor(opacity); + radius += radius * time * 1.1; + drawRing2(ctx, x, y, radius, thickness, color + opacity); +} + +function drawRing2(ctx, x, y, radius, thickness = 0.8, color) { + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.fillStyle = color; + ctx.arc(x, y, radius, 0, PI2, false); + ctx.arc(x, y, radius * thickness, 0, PI2, true); + ctx.fill(); +} + +function drawPinkZone(ctx, coords, color = '#FFF') { + const viewport = ui.getViewport(); + const { x, y } = viewport.worldToCanvasCoords(coords); + const radius = viewport.worldToCanvasDist(pinkCircleRadius); + ctx.beginPath(); + ctx.fillStyle = color; + ctx.arc(x, y, radius, 0, PI2, false); + ctx.fill(); +} + +function drawHlPinkZone(ctx) { + if (hlPinkZoneCounter <= 0) return; + const selectedPlanet = ui.getSelectedPlanet(); + if (!selectedPlanet) return; + + const alpha = (hlPinkZoneCounter / hlPinkZoneCounterMax) * 0.4; + const color = `hsla(0, 100%, 40%, ${alpha})`; + drawPinkZone(ctx, selectedPlanet.location.coords, color); + hlPinkZoneCounter--; +} + +function drawListHoveringPZ(ctx) { + if (!pzHoveringInList) return; + + const color = 'hsla(300, 100%, 40%, 0.7)'; + drawPinkZone(ctx, pzHoveringInList.coords, color); +} + +function drawButPinkItAnimation() { + if (!butPinkIt) return; + if (!butPinkItIsReady) return; + const hueStart = 0; // orange-red + const hueEnd = 55; // yellow + const animationSpeed = 500; + const t = (Date.now() % animationSpeed) / animationSpeed; + const hue = hueStart + (hueEnd - hueStart) * t; + const color = `hsl(${hue}, 100%, 40%)`; + butPinkIt.style.backgroundColor = color; + butPinkIt.style.color = '#000'; +} + +function getDistBetweenPlanets(planetA, planetB) { + return df.getDistCoords(planetA.location.coords, planetB.location.coords); +} + +function pinkZoneIsInView(pinkZone) { + const viewPort = ui.getViewport(); + if (viewPort.getBottomBound() > pinkZone.coords.y + pinkCircleRadius) + return false; + if (viewPort.getTopBound() < pinkZone.coords.y - pinkCircleRadius) + return false; + if (viewPort.getLeftBound() > pinkZone.coords.x + pinkCircleRadius) + return false; + if (viewPort.getRightBound() < pinkZone.coords.x - pinkCircleRadius) + return false; + return true; +} + +// returns null of we dont have a pink zone at selected planet +function getMyPinkZoneAtSelectedPlanet() { + const selectedPlanet = ui.getSelectedPlanet(); + if (!selectedPlanet) return null; + myPinkZone = null; + for (let pz of df.getMyPinkZones()) { + if (pz.locationId === selectedPlanet.locationId) { + myPinkZone = pz; + break; + } + } + + return myPinkZone; +} + +function setChoosenPlanets() { + if (pinkItIsRunning) return; + const selectedPlanet = ui.getSelectedPlanet(); + choosenPlanets = []; + deadPlanets = []; + setPinkItButton(); + if (!selectedPlanet) return; + let planets = df.getAllPlanets(); + for (let p of planets) { + if (!p.location) continue; + if (p.planetLevel < minPinkLevel) continue; + if (excludeOwnedPlanets && !planetHasNoOwner(p)) continue; + if (excludeMyPlanets && planetIsMine(p)) continue; + if (getDistBetweenPlanets(selectedPlanet, p) > pinkCircleRadius) continue; + if (p.destroyed) deadPlanets.push(p); + else choosenPlanets.push(p); + } + setPinkItButton(); +} + +async function pinkIt() { + if (pinkItIsRunning) return; + pinkItIsRunning = true; + await sleep(2000); // give the user 2 seconds to abort before starting to destroy planets + if (!stopPinkIt) await go(); + async function go() { + for (let p of choosenPlanets) { + if (stopPinkIt) break; + if (p.destroyed) continue; + dieingPlanet = p; + try { + console.log(`df.pinkLocation('${p.locationId}')`); + if (!simulate) await df.pinkLocation(p.locationId); + } catch (err) { + console.error(err); + } + + if (simulate) { + await sleep(3000); + } else { + // we have to wait for planet being destroyed otherwise next df.pinkLocation will fail + for (let i = 0; i < 30; ++i) { + if (p.destroyed) break; + await sleep(500); + if (stopPinkIt) break; + } + } + deadPlanets.push(p); + } + } + dieingPlanet = null; + pinkItIsRunning = false; + stopPinkIt = false; + setChoosenPlanets(); +} + +function setExcludeOwnedPlanets(onOrOff) { + setChoosenPlanets(); + excludeOwnedPlanets = onOrOff; +} + +function setExcludeMyPlanets(onOrOff) { + setChoosenPlanets(); + excludeMyPlanets = onOrOff; +} + +function onMouseClick() { + myPinkZone = getMyPinkZoneAtSelectedPlanet(); + if (lastSelectedPlanet !== ui.getSelectedPlanet()) { + hlPinkZoneCounter = hlPinkZoneCounterMax; + setTablePinkZoneList(); + } + setChoosenPlanets(); + lastSelectedPlanet = ui.getSelectedPlanet(); +} + +function setPinkItButton() { + if (!butPinkIt) return; + butPinkIt.style.color = '#FFF'; + butPinkIt.style.backgroundColor = '#000'; + butPinkItIsReady = false; + if (!myPinkZone) { + butPinkIt.innerHTML = 'please select one of your pink zones'; + } else if (choosenPlanets.length === 0) { + butPinkIt.innerHTML = 'no destroyable planets found'; + } else if (pinkItIsRunning) { + if (stopPinkIt) butPinkIt.innerHTML = 'stopping ...'; + else butPinkIt.innerHTML = 'STOP destroying planets'; + } else { + butPinkIt.innerHTML = + `start DESTROYING ${choosenPlanets.length} planets`; + butPinkItIsReady = true; + } +} + +function onButPinkItClick() { + if (!pinkItIsRunning) { + if (!ui.getSelectedPlanet()) { + console.error('first you have to select a planet'); + return; + } + if (!myPinkZone) return; + if (choosenPlanets.length === 0) return; + pinkIt(); + setPinkItButton(); + } else { + stopPinkIt = true; + setPinkItButton(); + } +} + +function getPinkZonesInView() { + return Array.from(df.getPinkZones()).filter(pinkZoneIsInView); +} + +const planetType = {}; +planetType.PLANET = 0; +planetType.ASTEROID = 1; +planetType.FOUNDRY = 2; +planetType.SPACETIME = 3; +planetType.QUASAR = 4; + +function getPlanetTypeName(planet) { + for (const type in planetType) { + if (planet.planetType === planetType[type]) { + return type; + } + } + + throw new Error( + `cannot find planet type name for type ${planet.planetType}`, + ); +} + +function getPlanetDesc(planet) { + if (typeof planet === 'string') { + planet = df.getPlanetWithId(planet); + } + + return `LvL. ${planet.planetLevel} ${getPlanetTypeName(planet)}`; +} + +function setTablePinkZoneList() { + if (!tablePinkZoneList) return; + tablePinkZoneList.innerHTML = ''; + + const pinkZones = getPinkZonesInView(); + if (pinkZones.length === 0) { + return; + } + + createTableHeader(tablePinkZoneList, ['twitter', 'address', 'planet']); + for (const pz of pinkZones) { + const tr = document.createElement('tr'); + const operatorAddress = pz.operator; + const player = df.getPlayer(operatorAddress); + const playerColor = getPlayerColor(operatorAddress); + + addAsTd(tr, player.twitter ? player.twitter : '', null, playerColor); + addAsTd(tr, operatorAddress.substr(0, 8), null, playerColor); + addAsTd(tr, getPlanetDesc(pz.locationId)); + + tr.style.cursor = 'pointer'; + tr.style.backgroundColor = '#000'; + let selectedPlanet = ui.getSelectedPlanet(); + if (selectedPlanet && selectedPlanet.locationId === pz.locationId) + tr.style.backgroundColor = '#400'; + tr.addEventListener('mouseenter', () => { + tr.style.backgroundColor = '#333'; + let selectedPlanet = ui.getSelectedPlanet(); + if (selectedPlanet && selectedPlanet.locationId === pz.locationId) + tr.style.backgroundColor = '#600'; + pzHoveringInList = pz; + }); + tr.addEventListener('mouseleave', () => { + tr.style.backgroundColor = '#000'; + let selectedPlanet = ui.getSelectedPlanet(); + if (selectedPlanet && selectedPlanet.locationId === pz.locationId) + tr.style.backgroundColor = '#400'; + pzHoveringInList = null; + }); + tr.addEventListener('click', () => { + ui.centerLocationId(pz.locationId); + hlPinkZoneCounter = hlPinkZoneCounterMax; + setTablePinkZoneList(); + }); + + tablePinkZoneList.append(tr); + } +} + +function updateTablePinkZoneList() { + // we check centerWorldCoords to see if the user moved, only then we update the pinkZoneList table + const worldCoords = ui.getViewport().centerWorldCoords; + if ( + worldCoords.x === lastWorldCoords.x && + worldCoords.y === lastWorldCoords.y + ) { + return; + } + + lastWorldCoords.x = worldCoords.x; + lastWorldCoords.y = worldCoords.y; + setTablePinkZoneList(); +} + +function Plugin() { + var o = {}; + + o.container = null; + + o.destroy = function () { + stopPinkIt = true; + clearInterval(intervUpdateTablePZList); + window.removeEventListener('click', o.onMouseClick); + }; + + o.init = function () { + window.addEventListener('click', onMouseClick); + setChoosenPlanets(); + intervUpdateTablePZList = setInterval(updateTablePinkZoneList, 330); + }; + + o.render = function (container) { + container.width = '400px'; + o.container = container; + let div = document.createElement('div'); + div.innerHTML = + 'select the planet in the center of the pink circle
highlights all planets that will be destroyed
black = dead planets
purple = destroy these planets'; + div.style.width = '100%'; + div.style.textAlign = 'center'; + container.append(div); + + let butExcludeOwned = createToggleButton( + 'exclude owned planets', + setExcludeOwnedPlanets, + false, + ); + let butExcludeMine = createToggleButton( + 'exclude my planets', + setExcludeMyPlanets, + true, + ); + + let excludeButLine = FullButtonLine([butExcludeOwned, butExcludeMine]); + container.append(excludeButLine); + + butPinkIt = document.createElement('button'); + butPinkIt.style.width = '100%'; + butPinkIt.style.height = '2.0rem'; + butPinkIt.style.fontSize = '1.2rem'; + butPinkIt.addEventListener('click', onButPinkItClick); + setPinkItButton(); + container.append(butPinkIt); + + tablePinkZoneList = document.createElement('table'); + tablePinkZoneList.style.textAlign = 'center'; + tablePinkZoneList.style.width = '100%'; + tablePinkZoneList.style.marginTop = '5px'; + setTablePinkZoneList(); + container.append(tablePinkZoneList); + }; + + o.draw = function (ctx) { + o.drawAllRings(ctx); + drawListHoveringPZ(ctx); + drawHlPinkZone(ctx); + drawButPinkItAnimation(); + }; + + o.drawAllRings = function (ctx) { + if (dieingPlanet) { + drawRingAnimationOnPlanet(ctx, dieingPlanet, 2, '#000000', true); + } + for (let p of choosenPlanets) { + o.drawRingAroundPlanet(p, ctx, '#60F'); + } + for (let p of deadPlanets) { + o.drawRingAroundPlanet(p, ctx, '#000'); + } + }; + + o.drawRingAroundPlanet = function (planet, ctx, color = '#60A') { + const viewport = ui.getViewport(); + + // planet coordinates relative to the player + const { x: planetX, y: planetY } = viewport.worldToCanvasCoords( + planet.location.coords, + ); + + // planet radius in px + var planetCtxPixelRadius = viewport.worldToCanvasDist( + ui.getRadiusOfPlanetLevel(planet.planetLevel), + ); + planetCtxPixelRadius *= 0.75; + if (planetCtxPixelRadius < minCircleSizePx) + planetCtxPixelRadius = minCircleSizePx; + + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.fillStyle = color; + ctx.arc(planetX, planetY, planetCtxPixelRadius * 2, 0, Math.PI * 2, false); + ctx.arc( + planetX, + planetY, + planetCtxPixelRadius * 2 - circleThickness, + 0, + Math.PI * 2, + true, + ); + ctx.fill(); + }; + + o.init(); + return o; +} + +class PinkIt { + constructor() { + this.plugin = Plugin(); + } + render(div) { + this.plugin.render(div); + } + draw(ctx) { + this.plugin.draw(ctx); + } + destroy() { + this.plugin.destroy(); + } +} + +export default PinkIt; diff --git a/content/productivity/pink-it/screenshot.png b/content/productivity/pink-it/screenshot.png new file mode 100644 index 00000000..f4694c0c Binary files /dev/null and b/content/productivity/pink-it/screenshot.png differ diff --git a/content/productivity/pink-it/videoExample.mp4 b/content/productivity/pink-it/videoExample.mp4 new file mode 100644 index 00000000..e3aace60 Binary files /dev/null and b/content/productivity/pink-it/videoExample.mp4 differ diff --git a/content/utilities/map-filter-export/index.md b/content/utilities/map-filter-export/index.md index 045cd5c5..c2735867 100644 --- a/content/utilities/map-filter-export/index.md +++ b/content/utilities/map-filter-export/index.md @@ -1,6 +1,6 @@ --- title: Map Filter Export -date: 2022-02-01 +date: 2023-11-22 subtitle: Export filtered planets with or without background. -version: 0.6.5 +version: 0.1.1-dfares --- diff --git a/content/utilities/map-filter-export/plugin.js b/content/utilities/map-filter-export/plugin.js index 8ba11c41..a6ef7255 100755 --- a/content/utilities/map-filter-export/plugin.js +++ b/content/utilities/map-filter-export/plugin.js @@ -1,38 +1,38 @@ // -// author: https://twitter.com/DfArchon +// author: https://twitter.com/DFArchon // -// Map Filter Export -// -// Export filtered planets with or without background. -// -// the speed of export and import is faster :-) -// -// notice 1: If the number of planets is too large, the website may crash, -// so we recommend choose a reasonable planetLevel range, such as [3,9]. -// We don't recommend to choose the planetLevel 0, -// because the planets's amount maybe very large. -// -// notice 2: If you choose to [Download Map With Background], -// plugin will export the map which has a lot of 16x16 pixel blocks, -// the import speed is fast, but you may need to wait the planets to show up for a while. -// Click the button [Show Planets] and Use the middle mouse button to zoom in -// and out may help to make the planets show up more quickly. +// Map Filter Export +// +// Export filtered planets with or without background. +// +// the speed of export and import is faster :-) +// +// notice 1: If the number of planets is too large, the website may crash, +// so we recommend choose a reasonable planetLevel range, such as [3,9]. +// We don't recommend to choose the planetLevel 0, +// because the planets's amount maybe very large. +// +// notice 2: If you choose to [Download Map With Background], +// plugin will export the map which has a lot of 16x16 pixel blocks, +// the import speed is fast, but you may need to wait the planets to show up for a while. +// Click the button [Show Planets] and Use the middle mouse button to zoom in +// and out may help to make the planets show up more quickly. // -// notice 3: Your planets can still be attacked by other's small planets which you can't see. +// notice 3: Your planets can still be attacked by other's small planets which you can't see. // -// When writing this plugin, we learn a lot from the plugin named map export, -// Thanks to the authors of map export ! +// When writing this plugin, we learn a lot from the plugin named map export, +// Thanks to the authors of map export ! // import { PlanetLevel, PlanetType, SpaceType } from - "https://cdn.skypack.dev/@darkforest_eth/types"; + "https://cdn.skypack.dev/@dfares/types"; import { html, render, useState } from - "https://unpkg.com/htm/preact/standalone.module.js"; + "https://unpkg.com/htm/preact/standalone.module.js"; import { getPlayerColor } from - "https://cdn.skypack.dev/@darkforest_eth/procedural"; + "https://cdn.skypack.dev/@dfares/procedural"; let showPlanets = []; @@ -47,535 +47,551 @@ export const inGreenSpace = planet => planet.spaceType === SpaceType.DEAD_SPACE; export const inBlueSpace = planet => planet.spaceType === SpaceType.NEBULA; export const inDarkblueSpace = planet => planet.spaceType === SpaceType.SPACE; export const destroyedFilter = plt => { - return plt.location !== undefined && plt.destroyed === false; + return plt.location !== undefined && plt.destroyed === false; } export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); function drawRound(ctx, p, color, width = 1) { - if (!p) return '(???,???)'; - const viewport = ui.getViewport(); - ctx.strokeStyle = color; - ctx.lineWidth = width; - const { - x, - y - } = viewport.worldToCanvasCoords(p.location.coords); - const range = p.range * 0.01 * 20; - const trueRange = viewport.worldToCanvasDist(range); - ctx.beginPath(); - // ctx.setLineDash([10,10]); - ctx.arc(x, y, trueRange, 0, 2 * Math.PI); - ctx.stroke(); - return `(${p.location.coords.x},${p.location.coords.y})`; + if (!p) return '(???,???)'; + const viewport = ui.getViewport(); + ctx.strokeStyle = color; + ctx.lineWidth = width; + const { + x, + y + } = viewport.worldToCanvasCoords(p.location.coords); + const range = p.range * 0.01 * 20; + const trueRange = viewport.worldToCanvasDist(range); + ctx.beginPath(); + // ctx.setLineDash([10,10]); + ctx.arc(x, y, trueRange, 0, 2 * Math.PI); + ctx.stroke(); + return `(${p.location.coords.x},${p.location.coords.y})`; } function zeroFill(i) { - if (i >= 0 && i <= 9) return "0" + i; - else return i; + if (i >= 0 && i <= 9) return "0" + i; + else return i; } function getCurrentTime() { - var date = new Date(); - var month = zeroFill(date.getMonth() + 1); - var day = zeroFill(date.getDate()); - var hour = zeroFill(date.getHours()); - var minute = zeroFill(date.getMinutes()); - var second = zeroFill(date.getSeconds()); + var date = new Date(); + var month = zeroFill(date.getMonth() + 1); + var day = zeroFill(date.getDate()); + var hour = zeroFill(date.getHours()); + var minute = zeroFill(date.getMinutes()); + var second = zeroFill(date.getSeconds()); - var curTime = date.getFullYear() + "-" + month + "-" + day - + "_" + hour + "-" + minute + "-" + second; + var curTime = date.getFullYear() + "-" + month + "-" + day + + "_" + hour + "-" + minute + "-" + second; - return curTime; + return curTime; } const PLANET_LEVELS = Object.values(PlanetLevel).map((level) => ({ - value: level, - text: level.toString(), + value: level, + text: level.toString(), })); function mapFilterExport() { - const [leftLevel, setLeftLevel] = useState(3); - const [rightLevel, setRightLevel] = useState(9); - - const [hasPlanet, setHasPlanet] = useState(true); - const [hasAsteroidField, setHasAsteroidField] = useState(true); - const [hasFoundry, setHasFoundry] = useState(true); - const [hasSpacetimeRip, setHasSpacetimeRip] = useState(true); - const [hasQuasar, setHasQuasar] = useState(false); + const [leftLevel, setLeftLevel] = useState(3); + const [rightLevel, setRightLevel] = useState(9); + + const [hasPlanet, setHasPlanet] = useState(true); + const [hasAsteroidField, setHasAsteroidField] = useState(true); + const [hasFoundry, setHasFoundry] = useState(true); + const [hasSpacetimeRip, setHasSpacetimeRip] = useState(true); + const [hasQuasar, setHasQuasar] = useState(false); - const [ohBlackSpace, setOhBlackSpace] = useState(true); - const [ohGreenSpace, setOhGreenSpace] = useState(true); - const [ohBlueSpace, setOhBlueSpace] = useState(true); - const [ohDarkblueSpace, setOhDarkblueSpace] = useState(true); - const [onlyMe, setOnlyMe] = useState(false); - - const [info, setInfo] = useState(''); - const [info2, setInfo2] = useState(''); + const [ohBlackSpace, setOhBlackSpace] = useState(true); + const [ohGreenSpace, setOhGreenSpace] = useState(true); + const [ohBlueSpace, setOhBlueSpace] = useState(true); + const [ohDarkblueSpace, setOhDarkblueSpace] = useState(true); + const [onlyMe, setOnlyMe] = useState(false); + + const [info, setInfo] = useState(''); + const [info2, setInfo2] = useState(''); - //functions - function judgeLevel(plt) { - let minLevel = Math.min(leftLevel, rightLevel); - let maxLevel = Math.max(leftLevel, rightLevel); - return minLevel <= plt.planetLevel && plt.planetLevel <= maxLevel; - } - - function judgePlanetType(plt) { - if (hasPlanet && isPlanet(plt)) return true; - if (hasAsteroidField && isAsteroidField(plt)) return true; - if (hasFoundry && isFoundry(plt)) return true; - if (hasSpacetimeRip && isSpacetimeRip(plt)) return true; - if (hasQuasar && isQuasar(plt)) return true; - return false; - } - - function judgeOwner(plt) { - if (onlyMe === false) return true; - if (plt.owner === df.account) return true; - return false; - - } - - function judgeSpaceType(plt) { - if (ohBlackSpace && inBlackSpace(plt)) return true; - if (ohGreenSpace && inGreenSpace(plt)) return true; - if (ohBlueSpace && inBlueSpace(plt)) return true; - if (ohDarkblueSpace && inDarkblueSpace(plt)) return true; - return false; - } - - function generateMapWithoutBackground() { - let chunks = ui.getExploredChunks(); - let chunksAsArray = Array.from(chunks); - - let res = []; - - let planetsCount = 0; - let mapPixelsCnt = 0; - - - for (let i = 0; i < chunksAsArray.length; i++) { - const chunk = chunksAsArray[i]; - - let chunkFootprint = chunk.chunkFootprint; - let bottomLeft = chunkFootprint.bottomLeft; - let sideLength = chunkFootprint.sideLength; - let chunkPerlin = chunkFootprint.perlin; - - let planetLocations = chunk.planetLocations; - - let smallLength = 16; - let number = sideLength / smallLength; - - if (sideLength < smallLength) continue; - - mapPixelsCnt += number * number; - - let planetLocationsWithMark = []; - - planetLocations.forEach(item => { - const coords = item.coords; - let plt = df.getPlanetWithCoords(coords); - - let flag = true; - - if (judgeLevel(plt) === false) flag = false; - if (judgePlanetType(plt) === false) flag = false; - if (judgeSpaceType(plt) === false) flag = false; - if (judgeOwner(plt) === false) flag = false; - if (destroyedFilter(plt) === false) flag = false; - - if (flag) { - let tx = coords.x - bottomLeft.x; - let ty = coords.y - bottomLeft.y; - tx = Math.floor(tx / smallLength); - ty = Math.floor(ty / smallLength); - - let value = tx * number + ty; - let newItem = item; - newItem.mark = value; - planetLocationsWithMark.push(newItem); - planetsCount++; - } - }); - - planetLocationsWithMark = planetLocationsWithMark.sort((a, b) => a.mark - b.mark); - - let stack = []; - - for (let i = 0; i < planetLocationsWithMark.length; i++) { - let item = planetLocationsWithMark[i]; - let mark = item.mark; - let rhs = {}; - rhs.biomebase = item.biomebase; - rhs.coords = item.coords; - rhs.hash = item.hash; - rhs.perlin = item.perlin; - - stack.push(rhs); - - if ((i === planetLocationsWithMark.length - 1) || - (i + 1 < planetLocationsWithMark.length && - planetLocationsWithMark[i].mark != planetLocationsWithMark[i + 1].mark) - ) { - - let newChunk = {}; - newChunk.chunkFootprint = {}; - - let tx = Math.floor(mark / number) * smallLength; - let ty = (mark - number * Math.floor(mark / number)) * smallLength; - tx += bottomLeft.x; - ty += bottomLeft.y; - let coords = { x: tx, y: ty }; - newChunk.chunkFootprint.bottomLeft = coords; - newChunk.chunkFootprint.sideLength = smallLength; - newChunk.perlin = chunkPerlin; - let notCnt = 0; - for (let j = 0; j < stack.length; j++) { - let pltCoords = stack[j].coords; - if (pltCoords.x >= tx && pltCoords.x < tx + smallLength && pltCoords.y >= ty && pltCoords.y < ty + smallLength); - else notCnt++; - } - - //notice: normally notCnt===0 - if (notCnt !== 0) console.error('notCnt:' + notCnt); - - newChunk.planetLocations = stack; - if (stack.length !== 0) { - res.push(newChunk); - stack = []; - } - } - } - } - - let newInfo = html`
-
export ${planetsCount} planets
-
${mapPixelsCnt} 16x16 pixel blocks before
-
${res.length} 16x16 pixel blocks now
-
`; - setInfo(newInfo); - return res; - } - - let onDownloadWithoutBackground = async () => { - let newInfo = html`
Begin To Download Map Without Background
`; - setInfo(newInfo); - let newInfo2 = html`
You may need to wait for a while...
`; - setInfo2(newInfo2); - // notice : sleep is to refresh page - await sleep(100); - - let mapRaw = generateMapWithoutBackground(); - try { - let map = JSON.stringify(mapRaw); - var blob = new Blob([map], { type: 'application/json' }), - anchor = document.createElement('a'); - let currentTime = getCurrentTime(); - anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; - anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); - anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); - anchor.click(); - let newInfo = html`
Download Map Successfully :-)
`; - setInfo2(newInfo); - - } catch (err) { - console.error(err); - let newInfo = html`
Download Map Error :-|
`; - setInfo(newInfo); - } - } - - function generateMapWithBackground() { - let chunks = ui.getExploredChunks(); - let chunksAsArray = Array.from(chunks); - - let planetsCount = 0; - - for (let i = 0; i < chunksAsArray.length; i++) { - const chunk = chunksAsArray[i]; - let planetLocations = chunk.planetLocations; - - planetLocations = planetLocations.filter(item=>{ - const coords = item.coords; - let plt = df.getPlanetWithCoords(coords); - if(judgeLevel(plt)===false) return false; - if(judgePlanetType(plt)===false) return false; - if(judgeSpaceType(plt)===false) return false; - if(judgeOwner(plt)===false) return false; - if(destroyedFilter(plt)===false) return false; - return true; - }); - - chunksAsArray[i].planetLocations = planetLocations; - planetsCount+=planetLocations.length; - } - - let newInfo = html`
-
export ${planetsCount} planets
-
`; - setInfo(newInfo); - return chunksAsArray; - } - - let onDownloadWithBackground = async () => { - let newInfo = html`
Begin To Download Map With Background
`; - setInfo(newInfo); - let newInfo2 = html`
You may need to wait for a while...
`; - setInfo2(newInfo2); - // notice : sleep is to refresh page - await sleep(100); - - let mapRaw = generateMapWithBackground(); - try { - let map = JSON.stringify(mapRaw); - var blob = new Blob([map], { type: 'application/json' }), - anchor = document.createElement('a'); - let currentTime = getCurrentTime(); - anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; - anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); - anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); - anchor.click(); - let newInfo = html`
Download Map Successfully :-)
`; - setInfo2(newInfo); - - } catch (err) { - console.error(err); - let newInfo = html`
Download Map Error :-|
`; - setInfo(newInfo); - } - } - - - - - async function processMap(input) { - let chunks; - try { - chunks = JSON.parse(input); - - } catch (err) { - console.error(err); - let newInfo = html`
Invalid map data. Check the data in your file.
`; - setInfo(newInfo); - return; - } - - let newInfo = html`
Importing, this will take a while...
`; - setInfo(newInfo); - try { - await df.bulkAddNewChunks(chunks) - let newInfo = html`
Successfully imported map :-)
`; - setInfo(newInfo); - } catch (err) { - console.error(err); - let newInfo = html`
Encountered an unexpected error :-(
`; - setInfo(newInfo); - } - } - - let onUpload = async () => { - let newInfo = html`
Begin To Upload
`; - setInfo(newInfo); - let newInfo2 = html`
You may need to wait For a while...
`; - setInfo2(newInfo2); - - let inputFile = document.createElement('input'); - inputFile.type = 'file'; - inputFile.onchange = () => { - try { - var file = inputFile.files.item(0); - var reader = new FileReader(); - reader.onload = () => { - processMap(reader.result); - }; - reader.readAsText(file); - - newInfo2 = html`
NOTICE: Filter Functions Only Used In Download!
`; - setInfo2(newInfo2); - - } catch (err) { - console.error(err); - let newInfo = html`
Unable to upload map :-(
`; - setInfo(newInfo); - setInfo2(''); - return; - } - } - inputFile.click(); - } - - let updatePlanets = () => { - showPlanets = Array.from(df.getAllPlanets()) - .filter(destroyedFilter) - .filter(judgeLevel) - .filter(judgeOwner) - .filter(judgeSpaceType); - } - - let clearPlanets = () => { - showPlanets = []; - } - - // css style - let divStyle = { - textAlign: 'center', - justifyContent: "space-around", - width: "100%", - marginTop: "10px", - }; - - let buttonStyle = { height: "25px", width: "130px" }; - - let longButtonStyle = { height: "25px", width: "300px" }; - let selectStyle = { - background: "rgb(8,8,8)", - width: "100px", - padding: "3px 5px", - border: "1px solid white", - borderRadius: "3px", - }; - - let planetLevelStyle = { - marginTop: "5px", - marginBottom: "5px" - }; - - // Component - const leftLevelSelect = html` - - `; - const rightLevelSelect = html` - - `; - - let levelComponent = html`
- ${leftLevelSelect} - ${' '} - ${rightLevelSelect} -
`; - - let thePlanetComponent = html`
- setHasPlanet(!hasPlanet)}/> - ${' Planet'}
`; - - let theAsteroidFiledComponent = html`
- setHasAsteroidField(!hasAsteroidField)}/> - ${' AsteroidField'}
`; - - let theFoundryComponent = html`
- setHasFoundry(!hasFoundry)}/> - ${' Foundry'}
`; - - let theSpacetimeRipComponent = html`
- setHasSpacetimeRip(!hasSpacetimeRip)}/> - ${' SpacetimeRip'}
`; - - let theQuasarComponent = html`
- setHasQuasar(!hasQuasar)}/> - ${' Quasar'}
`; - - let planetTypeComponent = html` -
- ${thePlanetComponent} - ${theAsteroidFiledComponent} - ${theFoundryComponent} - ${theSpacetimeRipComponent} - ${theQuasarComponent} -
- `; - - let theBlackSpaceComponent = html`
- setOhBlackSpace(!ohBlackSpace)}/> - ${' Black'}
`; - - let theGreenSpaceComponent = html`
- setOhGreenSpace(!ohGreenSpace)}/> - ${' Green'}
`; - - let theBlueSpaceComponent = html`
- setOhBlueSpace(!ohBlackSpace)}/> - ${' Blue'}
`; - let theDarkblueSpaceComponent = html`
- setOhDarkblueSpace(!ohDarkblueSpace)}/> - ${' Darkblue'}
`; - - let spaceTypeComponent = html` -
- - ${theBlackSpaceComponent} - ${theGreenSpaceComponent} - ${theBlueSpaceComponent} - ${theDarkblueSpaceComponent} -
`; - - let ownerComponent = html` -
- setOnlyMe(!onlyMe)}/> - - ${' All '} - setOnlyMe(!onlyMe)}/> - ${' Me '} -
`; - - return html`
- ${levelComponent} -
- ${planetTypeComponent} - ${ownerComponent} - ${spaceTypeComponent} - -
-
- -
-
- -
-
- -
-
- - ${' '} - -
- - - ${info} - ${info2} -
`; + //functions + function judgeLevel(plt) { + let minLevel = Math.min(leftLevel, rightLevel); + let maxLevel = Math.max(leftLevel, rightLevel); + return minLevel <= plt.planetLevel && plt.planetLevel <= maxLevel; + } + + function judgePlanetType(plt) { + if (hasPlanet && isPlanet(plt)) return true; + if (hasAsteroidField && isAsteroidField(plt)) return true; + if (hasFoundry && isFoundry(plt)) return true; + if (hasSpacetimeRip && isSpacetimeRip(plt)) return true; + if (hasQuasar && isQuasar(plt)) return true; + return false; + } + + function judgeOwner(plt) { + if (onlyMe === false) return true; + if (plt.owner === df.account) return true; + return false; + + } + + function judgeSpaceType(plt) { + if (ohBlackSpace && inBlackSpace(plt)) return true; + if (ohGreenSpace && inGreenSpace(plt)) return true; + if (ohBlueSpace && inBlueSpace(plt)) return true; + if (ohDarkblueSpace && inDarkblueSpace(plt)) return true; + return false; + } + + function generateMapWithoutBackground() { + let chunks = ui.getExploredChunks(); + let chunksAsArray = Array.from(chunks); + + let res = []; + + let planetsCount = 0; + let mapPixelsCnt = 0; + + + for (let i = 0; i < chunksAsArray.length; i++) { + const chunk = chunksAsArray[i]; + + let chunkFootprint = chunk.chunkFootprint; + let bottomLeft = chunkFootprint.bottomLeft; + let sideLength = chunkFootprint.sideLength; + let chunkPerlin = chunkFootprint.perlin; + + let planetLocations = chunk.planetLocations; + + let smallLength = 16; + let number = sideLength / smallLength; + + if (sideLength < smallLength) continue; + + mapPixelsCnt += number * number; + + let planetLocationsWithMark = []; + + planetLocations.forEach(item => { + const coords = item.coords; + let plt = df.getPlanetWithCoords(coords); + + let flag = true; + + if (judgeLevel(plt) === false) flag = false; + if (judgePlanetType(plt) === false) flag = false; + if (judgeSpaceType(plt) === false) flag = false; + if (judgeOwner(plt) === false) flag = false; + if (destroyedFilter(plt) === false) flag = false; + + if (flag) { + let tx = coords.x - bottomLeft.x; + let ty = coords.y - bottomLeft.y; + tx = Math.floor(tx / smallLength); + ty = Math.floor(ty / smallLength); + + let value = tx * number + ty; + let newItem = item; + newItem.mark = value; + planetLocationsWithMark.push(newItem); + planetsCount++; + } + }); + + planetLocationsWithMark = planetLocationsWithMark.sort((a, b) => a.mark - b.mark); + + let stack = []; + + for (let i = 0; i < planetLocationsWithMark.length; i++) { + let item = planetLocationsWithMark[i]; + let mark = item.mark; + let rhs = {}; + rhs.biomebase = item.biomebase; + rhs.coords = item.coords; + rhs.hash = item.hash; + rhs.perlin = item.perlin; + + stack.push(rhs); + + if ((i === planetLocationsWithMark.length - 1) || + (i + 1 < planetLocationsWithMark.length && + planetLocationsWithMark[i].mark != planetLocationsWithMark[i + 1].mark) + ) { + + let newChunk = {}; + newChunk.chunkFootprint = {}; + + let tx = Math.floor(mark / number) * smallLength; + let ty = (mark - number * Math.floor(mark / number)) * smallLength; + tx += bottomLeft.x; + ty += bottomLeft.y; + let coords = { x: tx, y: ty }; + newChunk.chunkFootprint.bottomLeft = coords; + newChunk.chunkFootprint.sideLength = smallLength; + newChunk.perlin = chunkPerlin; + let notCnt = 0; + for (let j = 0; j < stack.length; j++) { + let pltCoords = stack[j].coords; + if (pltCoords.x >= tx && pltCoords.x < tx + smallLength && pltCoords.y >= ty && pltCoords.y < ty + smallLength); + else notCnt++; + } + + //notice: normally notCnt===0 + if (notCnt !== 0) console.error('notCnt:' + notCnt); + + newChunk.planetLocations = stack; + if (stack.length !== 0) { + res.push(newChunk); + stack = []; + } + } + } + } + + let newInfo = html`
+
export ${planetsCount} planets
+
${mapPixelsCnt} 16x16 pixel blocks before
+
${res.length} 16x16 pixel blocks now
+
`; + setInfo(newInfo); + return res; + } + + let onDownloadWithoutBackground = async () => { + let newInfo = html`
Begin To Download Map Without Background
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait for a while...
`; + setInfo2(newInfo2); + // notice : sleep is to refresh page + await sleep(100); + + let mapRaw = generateMapWithoutBackground(); + try { + let map = JSON.stringify(mapRaw); + var blob = new Blob([map], { type: 'application/json' }), + anchor = document.createElement('a'); + let currentTime = getCurrentTime(); + anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; + anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); + anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); + anchor.click(); + let newInfo = html`
Download Map Successfully :-)
`; + setInfo2(newInfo); + + } catch (err) { + console.error(err); + let newInfo = html`
Download Map Error :-|
`; + setInfo(newInfo); + } + } + + function generateMapWithBackground() { + let chunks = ui.getExploredChunks(); + let chunksAsArray = Array.from(chunks); + + let planetsCount = 0; + + + + let res = []; + + for (let i = 0; i < chunksAsArray.length; i++) { + const chunk = chunksAsArray[i]; + const planetLocations = chunk.planetLocations; + let planetLocationsWithMark = []; + let newChunk = {}; + newChunk.chunkFootprint = {}; + newChunk.chunkFootprint.bottomLeft = chunk.chunkFootprint.bottomLeft; + newChunk.chunkFootprint.sideLength = chunk.chunkFootprint.sideLength; + newChunk.perlin = chunk.perlin; + + + planetLocations.forEach(item=>{ + const coords = item.coords; + let plt = df.getPlanetWithCoords(coords); + let flag = true; + if(judgeLevel(plt)===false) flag = false; + if(judgePlanetType(plt)===false) flag = false; + if(judgeSpaceType(plt)===false) flag = false; + if(judgeOwner(plt)===false) flag = false; + if(destroyedFilter(plt)===false) flag = false; + if(flag){ + planetLocationsWithMark.push(item); + + } + }); + + newChunk.planetLocations = planetLocationsWithMark; + res.push(newChunk); + planetsCount+=planetLocationsWithMark.length; + } + + let newInfo = html`
+
export ${planetsCount} planets
+
`; + setInfo(newInfo); + return res; + } + + let onDownloadWithBackground = async () => { + let newInfo = html`
Begin To Download Map With Background
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait for a while...
`; + setInfo2(newInfo2); + // notice : sleep is to refresh page + await sleep(100); + + let mapRaw = generateMapWithBackground(); + try { + let map = JSON.stringify(mapRaw); + var blob = new Blob([map], { type: 'application/json' }), + anchor = document.createElement('a'); + let currentTime = getCurrentTime(); + anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; + anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); + anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); + anchor.click(); + let newInfo = html`
Download Map Successfully :-)
`; + setInfo2(newInfo); + + } catch (err) { + console.error(err); + let newInfo = html`
Download Map Error :-|
`; + setInfo(newInfo); + } + } + + + + + async function processMap(input) { + let chunks; + try { + chunks = JSON.parse(input); + + } catch (err) { + console.error(err); + let newInfo = html`
Invalid map data. Check the data in your file.
`; + setInfo(newInfo); + return; + } + + let newInfo = html`
Importing, this will take a while...
`; + setInfo(newInfo); + try { + await df.bulkAddNewChunks(chunks) + let newInfo = html`
Successfully imported map :-)
`; + setInfo(newInfo); + } catch (err) { + console.error(err); + let newInfo = html`
Encountered an unexpected error :-(
`; + setInfo(newInfo); + } + } + + let onUpload = async () => { + let newInfo = html`
Begin To Upload
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait For a while...
`; + setInfo2(newInfo2); + + let inputFile = document.createElement('input'); + inputFile.type = 'file'; + inputFile.onchange = () => { + try { + var file = inputFile.files.item(0); + var reader = new FileReader(); + reader.onload = () => { + processMap(reader.result); + }; + reader.readAsText(file); + + newInfo2 = html`
NOTICE: Filter Functions Only Used In Download!
`; + setInfo2(newInfo2); + + } catch (err) { + console.error(err); + let newInfo = html`
Unable to upload map :-(
`; + setInfo(newInfo); + setInfo2(''); + return; + } + } + inputFile.click(); + } + + let updatePlanets = () => { + showPlanets = Array.from(df.getAllPlanets()) + .filter(destroyedFilter) + .filter(judgeLevel) + .filter(judgeOwner) + .filter(judgeSpaceType); + } + + let clearPlanets = () => { + showPlanets = []; + } + + // css style + let divStyle = { + textAlign: 'center', + justifyContent: "space-around", + width: "100%", + marginTop: "10px", + }; + + let buttonStyle = { height: "25px", width: "130px" }; + + let longButtonStyle = { height: "25px", width: "300px" }; + let selectStyle = { + background: "rgb(8,8,8)", + width: "100px", + padding: "3px 5px", + border: "1px solid white", + borderRadius: "3px", + }; + + let planetLevelStyle = { + marginTop: "5px", + marginBottom: "5px" + }; + + // Component + const leftLevelSelect = html` + + `; + const rightLevelSelect = html` + + `; + + let levelComponent = html`
+ ${leftLevelSelect} + ${' '} + ${rightLevelSelect} +
`; + + let thePlanetComponent = html`
+ setHasPlanet(!hasPlanet)}/> + ${' Planet'}
`; + + let theAsteroidFiledComponent = html`
+ setHasAsteroidField(!hasAsteroidField)}/> + ${' AsteroidField'}
`; + + let theFoundryComponent = html`
+ setHasFoundry(!hasFoundry)}/> + ${' Foundry'}
`; + + let theSpacetimeRipComponent = html`
+ setHasSpacetimeRip(!hasSpacetimeRip)}/> + ${' SpacetimeRip'}
`; + + let theQuasarComponent = html`
+ setHasQuasar(!hasQuasar)}/> + ${' Quasar'}
`; + + let planetTypeComponent = html` +
+ ${thePlanetComponent} + ${theAsteroidFiledComponent} + ${theFoundryComponent} + ${theSpacetimeRipComponent} + ${theQuasarComponent} +
+ `; + + let theBlackSpaceComponent = html`
+ setOhBlackSpace(!ohBlackSpace)}/> + ${' Black'}
`; + + let theGreenSpaceComponent = html`
+ setOhGreenSpace(!ohGreenSpace)}/> + ${' Green'}
`; + + let theBlueSpaceComponent = html`
+ setOhBlueSpace(!ohBlackSpace)}/> + ${' Blue'}
`; + let theDarkblueSpaceComponent = html`
+ setOhDarkblueSpace(!ohDarkblueSpace)}/> + ${' Darkblue'}
`; + + let spaceTypeComponent = html` +
+ + ${theBlackSpaceComponent} + ${theGreenSpaceComponent} + ${theBlueSpaceComponent} + ${theDarkblueSpaceComponent} +
`; + + let ownerComponent = html` +
+ setOnlyMe(!onlyMe)}/> + + ${' All '} + setOnlyMe(!onlyMe)}/> + ${' Me '} +
`; + + return html`
+ ${levelComponent} +
+ ${planetTypeComponent} + ${ownerComponent} + ${spaceTypeComponent} + +
+
+ +
+
+ +
+
+ +
+
+ + ${' '} + +
+ + + ${info} + ${info2} +
`; } class Plugin { - constructor() { - this.container = null; - } - - draw(ctx) { - showPlanets.forEach(p => { - let color = getPlayerColor(p.owner); - drawRound(ctx, p, color, 2); - }); - } - - async render(container) { - this.container = container; - container.style.width = "320px"; - container.style.height = "380px"; - render(html`<${mapFilterExport} />`, container); - } - - destroy() { - render(null, this.container); - } + constructor() { + this.container = null; + } + + draw(ctx) { + showPlanets.forEach(p => { + let color = getPlayerColor(p.owner); + drawRound(ctx, p, color, 2); + }); + } + + async render(container) { + this.container = container; + container.style.width = "320px"; + container.style.height = "380px"; + render(html`<${mapFilterExport} />`, container); + } + + destroy() { + render(null, this.container); + } } export default Plugin; diff --git a/layouts/index.html b/layouts/index.html index d0a7f556..4aba96c9 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -13,7 +13,7 @@ href="https://github.com/{{ .Site.Params.Repo }}/blob/{{ .Site.Params.Branch }}/content/{{ .File.Dir }}plugin.js" class="card border-2 border-green-400 sm:mb-4 mb-6 hover:shadow-xl hover:bg-green-400 text-gray-400 hover:text-black transition duration-200 ease-in rounded-lg {{ lower .Section }}">
- {{ if eq .Params.version "0.6.5" }} + {{ if eq .Params.version "0.1.1-dfares" }} v{{ .Params.Version }} {{ else }}