From 698078a874a89aa147b9536a113ab3603cad24fd Mon Sep 17 00:00:00 2001 From: fengyanfengyu Date: Sun, 15 Aug 2021 16:59:49 +0800 Subject: [PATCH 1/2] Add auto-crawl-plants to plugin Add auto-crawl-plants to plugin --- .../productivity/auto-crawl-planets/index.md | 6 + .../productivity/auto-crawl-planets/plugin.js | 668 ++++++++++++++++++ .../auto-crawl-planets/screenshot.png | Bin 0 -> 21555 bytes 3 files changed, 674 insertions(+) create mode 100644 content/productivity/auto-crawl-planets/index.md create mode 100644 content/productivity/auto-crawl-planets/plugin.js create mode 100644 content/productivity/auto-crawl-planets/screenshot.png diff --git a/content/productivity/auto-crawl-planets/index.md b/content/productivity/auto-crawl-planets/index.md new file mode 100644 index 00000000..da68c46b --- /dev/null +++ b/content/productivity/auto-crawl-planets/index.md @@ -0,0 +1,6 @@ +--- +title: Auto Crawl Planets +date: 2021-08-15T14:00:00+02:00 +subtitle: Auto Crawl Plants Towards the Center ! +version: 0.6.0 +--- diff --git a/content/productivity/auto-crawl-planets/plugin.js b/content/productivity/auto-crawl-planets/plugin.js new file mode 100644 index 00000000..26bfeeae --- /dev/null +++ b/content/productivity/auto-crawl-planets/plugin.js @@ -0,0 +1,668 @@ +// Auto Crawl Planets +// +// 1.basically this plugin will auto crawl plants around, but it will calculate the priority first, high level plant has more priority, and if the plugin cant get the high priority +// plant, then it will choose a plant nearby and towards the high priority plant, you can change the priority calculate function. +// 2.the plugin allow multi crawl if you check the multi crawl button, which means the plugin will send energy to the plant even cant grap plant in a single transfer +// 3.in darkforest Round3, this plugin will crawl plants towards the center, which means plants near center has much higher priority. +const { + isMine, + isUnowned, + canHaveArtifact, + } = await import('https://plugins.zkga.me/utils/utils.js'); + + import { EMPTY_ADDRESS } from "https://cdn.skypack.dev/@darkforest_eth/constants"; + import { + PlanetType, + PlanetTypeNames, + PlanetLevel, + PlanetLevelNames, + } from "https://cdn.skypack.dev/@darkforest_eth/types"; + + + const planetTypes = { + 'Planet': 0, + 'Asteroid': 1, + 'Foundry': 2, + 'Spacetime_Rip': 3, + 'Quasar': 4, + }; + + const planetLevels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + const players = [ + EMPTY_ADDRESS + ]; + + const typeNames = Object.keys(planetTypes); + + const checkTypes = []; + + let poi = []; + class Plugin { + constructor() { + this.planetType = PlanetType.SILVER_MINE; + this.minimumEnergyAllowed = 15; + this.minPlanetLevel = 3; + this.maxEnergyPercent = 85; + + this.minPlantLevelToUse = 2; + this.maxPlantLevelToUse = 5; + this.autoSeconds = 30; + this.message = document.createElement('div'); + this.allowMultiCrawl = false; + + } + render(container) { + container.style.width = '300px'; + + let stepperLabel = document.createElement('label'); + stepperLabel.innerText = 'Max % energy to spend'; + stepperLabel.style.display = 'block'; + + let stepper = document.createElement('input'); + stepper.type = 'range'; + stepper.min = '0'; + stepper.max = '100'; + stepper.step = '5'; + stepper.value = `${this.maxEnergyPercent}`; + stepper.style.width = '80%'; + stepper.style.height = '24px'; + + let percent = document.createElement('span'); + percent.innerText = `${stepper.value}%`; + percent.style.float = 'right'; + + stepper.onchange = (evt) => { + percent.innerText = `${evt.target.value}%`; + try { + this.maxEnergyPercent = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse energy percent', e); + } + } + + + let minimumEnergyAllowedLabel = document.createElement('label'); + minimumEnergyAllowedLabel.innerText = '% energy to fill after capture'; + minimumEnergyAllowedLabel.style.display = 'block'; + + let minimumEnergyAllowedSelect = document.createElement('input'); + minimumEnergyAllowedSelect.type = 'range'; + minimumEnergyAllowedSelect.min = '0'; + minimumEnergyAllowedSelect.max = '100'; + minimumEnergyAllowedSelect.step = '1'; + minimumEnergyAllowedSelect.value = `${this.minimumEnergyAllowed}`; + minimumEnergyAllowedSelect.style.width = '80%'; + minimumEnergyAllowedSelect.style.height = '24px'; + + let percentminimumEnergyAllowed = document.createElement('span'); + percentminimumEnergyAllowed.innerText = `${minimumEnergyAllowedSelect.value}%`; + percentminimumEnergyAllowed.style.float = 'right'; + + minimumEnergyAllowedSelect.onchange = (evt) => { + if (parseInt(evt.target.value, 10) === 0) percentminimumEnergyAllowed.innerText = `1 energy`; + else + percentminimumEnergyAllowed.innerText = `${evt.target.value}%`; + try { + this.minimumEnergyAllowed = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse minimum energy allowed percent', e); + } + } + + let autoSecondsLabel = document.createElement('label'); + autoSecondsLabel.innerText = 'Every X seconds'; + autoSecondsLabel.style.display = 'block'; + + let autoSecondsStepper = document.createElement('input'); + autoSecondsStepper.type = 'range'; + autoSecondsStepper.min = '30'; + autoSecondsStepper.max = '6000'; + autoSecondsStepper.step = '30'; + autoSecondsStepper.value = `${this.autoSeconds}`; + autoSecondsStepper.style.width = '80%'; + autoSecondsStepper.style.height = '24px'; + + let autoSecondsInfo = document.createElement('span'); + autoSecondsInfo.innerText = `${autoSecondsStepper.value} secs`; + autoSecondsInfo.style.float = 'right'; + + autoSecondsStepper.onchange = (evt) => { + try { + this.autoSeconds = parseInt(evt.target.value, 10); + autoSecondsInfo.innerText = `${this.autoSeconds} secs`; + } catch (e) { + console.error('could not parse auto seconds', e); + } + } + + + + let levelLabel = document.createElement('label'); + levelLabel.innerText = 'Min. level to capture'; + levelLabel.style.display = 'block'; + + let level = document.createElement('select'); + level.style.background = 'rgb(8,8,8)'; + level.style.width = '100%'; + level.style.marginTop = '10px'; + level.style.marginBottom = '10px'; + planetLevels.forEach(lvl => { + let opt = document.createElement('option'); + opt.value = `${lvl}`; + opt.innerText = `Level ${lvl}`; + level.appendChild(opt); + }); + level.value = `${this.minPlanetLevel}`; + + level.onchange = (evt) => { + try { + this.minPlanetLevel = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse planet level', e); + } + } + + // minimum plant level used to capture new plant + let levelLabelMinUse = document.createElement('label'); + levelLabelMinUse.innerText = 'Min. level to Use'; + levelLabelMinUse.style.display = 'block'; + + let levelMinUse = document.createElement('select'); + levelMinUse.style.background = 'rgb(8,8,8)'; + levelMinUse.style.width = '100%'; + levelMinUse.style.marginTop = '10px'; + levelMinUse.style.marginBottom = '10px'; + planetLevels.forEach(lvl => { + let opt = document.createElement('option'); + opt.value = `${lvl}`; + opt.innerText = `Level ${lvl}`; + levelMinUse.appendChild(opt); + }); + levelMinUse.value = `${this.minPlantLevelToUse}`; + + levelMinUse.onchange = (evt) => { + try { + this.minPlantLevelToUse = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse planet level', e); + } + } + + // maxmum plant level used to capture new plant + let levelLabelMaxUse = document.createElement('label'); + levelLabelMaxUse.innerText = 'Max. level to Use'; + levelLabelMaxUse.style.display = 'block'; + + let levelMaxUse = document.createElement('select'); + levelMaxUse.style.background = 'rgb(8,8,8)'; + levelMaxUse.style.width = '100%'; + levelMaxUse.style.marginTop = '10px'; + levelMaxUse.style.marginBottom = '10px'; + planetLevels.forEach(lvl => { + let opt = document.createElement('option'); + opt.value = `${lvl}`; + opt.innerText = `Level ${lvl}`; + levelMaxUse.appendChild(opt); + }); + levelMaxUse.value = `${this.maxPlantLevelToUse}`; + + levelMaxUse.onchange = (evt) => { + try { + this.maxPlantLevelToUse = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse planet level', e); + } + } + + + let planetTypeLabel = document.createElement('label'); + planetTypeLabel.innerText = 'Select planetType: '; + planetTypeLabel.style.display = 'block'; + planetTypeLabel.style.paddingBottom = "6px"; + + // planet checkbox + let planetLabel = document.createElement('label'); + planetLabel.innerHTML = 'Planet'; + planetLabel.style.paddingRight = "10px"; + + let planetCheck = document.createElement('input'); + planetCheck.type = "checkbox"; + planetCheck.value = planetTypes.Planet; + planetCheck.style.marginRight = "10px"; + planetCheck.checked = false; + planetCheck.onchange = (evt) => { + if (evt.target.checked) { + // add to arr + checkTypes.push(planetCheck.value); + } else { + // delete from arr + let i = checkTypes.indexOf(planetCheck.value); + checkTypes.splice(i, 1); + } + }; + + // asteroid checkbox + let asteroidLabel = document.createElement('label'); + asteroidLabel.innerHTML = 'Asteroid'; + asteroidLabel.style.paddingRight = "10px"; + + let asteroidCheck = document.createElement('input'); + asteroidCheck.type = "checkbox"; + asteroidCheck.value = planetTypes.Asteroid; + asteroidCheck.style.marginRight = "10px"; + asteroidCheck.checked = false; + asteroidCheck.onchange = (evt) => { + if (evt.target.checked) { + checkTypes.push(asteroidCheck.value); + } else { + let i = checkTypes.indexOf(asteroidCheck.value); + checkTypes.splice(i, 1); + } + }; + + // Foundry checkbox + let foundryLabel = document.createElement('label'); + foundryLabel.innerHTML = 'Foundry'; + foundryLabel.style.paddingRight = "10px"; + + let foundryCheck = document.createElement('input'); + foundryCheck.type = "checkbox"; + foundryCheck.value = planetTypes.Foundry; + foundryCheck.style.marginRight = "10px"; + foundryCheck.checked = false; + foundryCheck.onchange = (evt) => { + if (evt.target.checked) { + checkTypes.push(foundryCheck.value); + } else { + let i = checkTypes.indexOf(foundryCheck.value); + checkTypes.splice(i, 1); + } + console.log(checkTypes); + }; + + // Spacetime Rip checkbox + let spaceRipLabel = document.createElement('label'); + spaceRipLabel.innerHTML = 'Spacetime Rip'; + spaceRipLabel.style.paddingRight = "10px"; + + let spaceRipCheck = document.createElement('input'); + spaceRipCheck.type = "checkbox"; + spaceRipCheck.value = planetTypes.Spacetime_Rip; + spaceRipCheck.style.marginRight = "10px"; + spaceRipCheck.checked = false; + spaceRipCheck.onchange = (evt) => { + if (evt.target.checked) { + checkTypes.push(spaceRipCheck.value); + } else { + let i = checkTypes.indexOf(spaceRipCheck.value); + checkTypes.splice(i, 1); + } + console.log(checkTypes); + }; + + // Quasar checkbox + let quasarLabel = document.createElement('label'); + quasarLabel.innerHTML = 'Quasar'; + quasarLabel.style.paddingRight = "10px"; + + let quasarCheck = document.createElement('input'); + quasarCheck.type = "checkbox"; + quasarCheck.value = planetTypes.Quasar; + quasarCheck.style.marginRight = "10px"; + quasarCheck.checked = false; + quasarCheck.onchange = (evt) => { + if (evt.target.checked) { + checkTypes.push(quasarCheck.value); + } else { + let i = checkTypes.indexOf(quasarCheck.value); + checkTypes.splice(i, 1); + } + console.log(checkTypes); + }; + + + + let message = document.createElement('div'); + + let button = document.createElement('button'); + button.style.width = '100%'; + button.style.marginTop = '10px'; + button.style.marginBottom = '10px'; + button.innerHTML = 'Crawl Plant!' + button.onclick = () => { + calculatePoi(this.minPlanetLevel, checkTypes); + crawlPlantForPoi(this.minPlanetLevel, this.maxEnergyPercent, this.minPlantLevelToUse, this.maxPlantLevelToUse, this.minimumEnergyAllowed, this.allowMultiCrawl); + } + + let autoCrwalLabel = document.createElement('label'); + autoCrwalLabel.innerHTML = 'Automatic CrawlPlant'; + autoCrwalLabel.style.paddingRight = "10px"; + + let autoCrawlPlantCheck = document.createElement('input'); + autoCrawlPlantCheck.type = "checkbox"; + autoCrawlPlantCheck.style.marginRight = "10px"; + autoCrawlPlantCheck.checked = false; + autoCrawlPlantCheck.onchange = (evt) => { + if (evt.target.checked) { + this.sendTimer = setInterval(() => { + this.message.innerText = 'Auto CrawlPlant...'; + + setTimeout(() => { + calculatePoi(this.minPlanetLevel, checkTypes); + crawlPlantForPoi(this.minPlanetLevel, this.maxEnergyPercent, this.minPlantLevelToUse, this.maxPlantLevelToUse, this.minimumEnergyAllowed, this.allowMultiCrawl); + }, 0); + }, 1000 * this.autoSeconds) + } else { + this.message.innerText = 'CrawlPlant by Hand'; + this.clearSendTimer(); + } + }; + + let allowMultiCrawlLabel = document.createElement('label'); + allowMultiCrawlLabel.innerHTML = 'Allow Multi Crawl _______'; + allowMultiCrawlLabel.style.paddingRight = "10px"; + + let allowMultiCrawlPlantCheck = document.createElement('input'); + allowMultiCrawlPlantCheck.type = "checkbox"; + allowMultiCrawlPlantCheck.style.marginRight = "10px"; + allowMultiCrawlPlantCheck.checked = false; + allowMultiCrawlPlantCheck.onchange = (evt) => { + if (evt.target.checked) { + this.allowMultiCrawl = true; + } else { + this.allowMultiCrawl = false; + } + }; + + container.appendChild(stepperLabel); + container.appendChild(stepper); + container.appendChild(percent); + container.appendChild(minimumEnergyAllowedLabel); + container.appendChild(minimumEnergyAllowedSelect); + container.appendChild(percentminimumEnergyAllowed); + + // Moves + container.appendChild(autoSecondsLabel); + container.appendChild(autoSecondsStepper); + container.appendChild(autoSecondsInfo); + + container.appendChild(levelLabel); + container.appendChild(level); + container.appendChild(levelLabelMinUse); + container.appendChild(levelMinUse); + container.appendChild(levelLabelMaxUse); + container.appendChild(levelMaxUse); + + container.appendChild(planetTypeLabel); + + // planet checkbox + container.appendChild(planetLabel); + container.appendChild(planetCheck); + + // asteroid checkbox + container.appendChild(asteroidLabel); + container.appendChild(asteroidCheck); + + // foundry checkbox + container.appendChild(foundryLabel); + container.appendChild(foundryCheck); + + // spacetime checkbox + container.appendChild(spaceRipLabel); + container.appendChild(spaceRipCheck); + + // quasar checkbox + container.appendChild(quasarLabel); + container.appendChild(quasarCheck); + + container.appendChild(button); + container.appendChild(message); + + //allowMultiCrawl + container.appendChild(allowMultiCrawlLabel); + container.appendChild(allowMultiCrawlPlantCheck); + + // Auto Crwal Plant + container.appendChild(autoCrwalLabel); + container.appendChild(autoCrawlPlantCheck); + container.appendChild(this.message); + } + clearSendTimer() { + if (this.sendTimer) { + clearInterval(this.sendTimer); + } + } + + destroy() { + this.clearSendTimer() + } + + } + + export default Plugin; + + function getArrivalsForPlanet(planetId) { + return df.getAllVoyages().filter(arrival => arrival.toPlanet === planetId).filter(p => p.arrivalTime > Date.now() / 1000); + } + + //returns tuples of [planet,distance] + 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); + } + + function calculatePoi(minCaptureLevel, checkTypes) { + debugger; + checkTypes = JSON.parse('[' + String(checkTypes) + ']') + + const candidatesOri = df.getPlanetMap(); + let candidates = []; + let keys = candidatesOri.keys() + for (let key of keys) { + candidates.push(candidatesOri.get(key)); + } + + + poi = candidates.filter(p => ( + p.owner !== df.account && + players.includes(p.owner) && + p.planetLevel >= minCaptureLevel && + checkTypes.includes(p.planetType) + )) + .map(to => { + return [to, priorityCalculate(to)] + }) + .sort((a, b) => a[1] - b[1]); + console.log("poi"); + } + + function priorityCalculate(planetObject) { + let priority = 0; + priority = Math.sqrt((planetObject.location.coords.x - 0) ** 2 + (planetObject.location.coords.y - 0) ** 2); + + return priority; + + } + + function priorityinlevelCalculate(planetObject) { + let priority = 0; + switch (planetObject.planetType) { + //fountry + case 2: + priority = planetObject.planetLevel * 3; + break; + //Asteroid + case 1: + priority = planetObject.planetLevel * 2.1; + break; + //spacetimerip + case 3: + priority = planetObject.planetLevel * 2; + break; + //plant + case 0: + priority = planetObject.planetLevel * 1.5; + break; + //Quasar + case 4: + priority = 0; + break; + default: + break; + } + + //priority = Math.sqrt((planetObject.coords.x - 0) ** 2 + (planetObject.coords.y - 0) ** 2); + + return priority; + + } + + + + function crawlPlantForPoi(minPlanetLevel, maxEnergyPercent, minPlantLevelToUse, maxPlantLevelToUse, minimumEnergyAllowed, allowMultiCrawl) { + debugger; + //for each plant in poi + for (let poiPlant in poi) { + let candidates_Ori; + try { + candidates_Ori = df.getPlanetsInRange(poi[poiPlant][0].locationId, 95); + } catch (error) { + continue; + } + + let candidates; + candidates = candidates_Ori.filter(p => ( + p.owner === df.account && + p.planetLevel >= minPlantLevelToUse && + p.planetLevel <= maxPlantLevelToUse && + !canHaveArtifact(p) + )).sort((a, b) => distance(poi[poiPlant][0], a) - distance(poi[poiPlant][0], b)); + + for (let candidatePlant in candidates) { + + crawlPlantMy(minPlanetLevel, maxEnergyPercent, poi[poiPlant][0], candidates[candidatePlant], checkTypes, minimumEnergyAllowed, allowMultiCrawl); + + } + } + + } + + function crawlPlantMy(minPlanetLevel, maxEnergyPercent, poiPlant, candidatePlant, checkTypes, minimumEnergyAllowed = 0, allowMultiCrawl = false) { + checkTypes = JSON.parse('[' + String(checkTypes) + ']') + + let candidateCapturePlants; + try { + candidateCapturePlants = df.getPlanetsInRange(candidatePlant.locationId, maxEnergyPercent) + .filter(p => (p.planetLevel >= minPlanetLevel && + p.owner !== df.account && + players.includes(p.owner) && + checkTypes.includes(p.planetType) + )); + } catch (error) { + return; + } + + let comboMap = candidateCapturePlants.map(p => { + return [p, priorityinlevelCalculate(p) + distance(poiPlant, candidatePlant) / distance(poiPlant, p)] + }).sort((a, b) => b[1] - a[1]); + + + + + const planet = candidatePlant; + const from = candidatePlant; + + const silverBudget = Math.floor(from.silver); + + // Rejected if has pending outbound moves + const energyUncomfired = df.getUnconfirmedMoves().filter(move => move.from === from.locationId) + let energyUncomfiredOnTheWay = 0; + for (let moves in energyUncomfired) { + energyUncomfiredOnTheWay = energyUncomfiredOnTheWay+ energyUncomfired[moves].forces; + } + if (energyUncomfired.length > 4 || (candidatePlant.energy - energyUncomfiredOnTheWay) <= candidatePlant.energyCap * (1 - maxEnergyPercent) * 0.01) { + return 0; + } + // if (unconfirmed.length > 4) { + // return 0; + // } + + + let i = 0; + const energyBudget = Math.floor((maxEnergyPercent / 100) * planet.energy); + + let energySpent = 0; + let moves = 0; + let silverNeed = 0; + let silverSpent = 0; + while (energyBudget - energySpent > 0 && i < comboMap.length) { + + const energyLeft = energyBudget - energySpent; + const silverLeft = silverBudget - silverSpent; + + // Remember its a tuple of candidates and their distance + const candidate = comboMap[i++][0]; + + // Rejected if has unconfirmed pending arrivals + const unconfirmed = df.getUnconfirmedMoves().filter(move => move.to === candidate.locationId) + let energyUncomfired = 0; + for (let moves in unconfirmed) { + energyUncomfired = energyUncomfired + unconfirmed[moves].forces; + } + if (unconfirmed.length > 4 || energyUncomfired >= candidate.energy * (candidate.defense / 100)) { + continue; + } + + // Rejected if has pending arrivals + const arrivals = getArrivalsForPlanet(candidate.locationId); + let energyOntheWay = 0; + for (let moves in arrivals) { + energyOntheWay = energyOntheWay + arrivals[moves].energyArriving; + } + if (arrivals.length + unconfirmed.length > 4 || energyOntheWay + energyUncomfired >= candidate.energy * (candidate.defense / 100)) { + continue; + } + + const energyUncomfiredfrom = df.getUnconfirmedMoves().filter(move => move.from === from.locationId); + let energyUncomfiredOnTheWay = 0; + for (let moves in energyUncomfiredfrom) { + energyUncomfiredOnTheWay = energyUncomfiredOnTheWay+ energyUncomfiredfrom[moves].forces; + } + if (energyUncomfired.length > 4 || (candidatePlant.energy - energyUncomfiredOnTheWay) <= candidatePlant.energyCap * (1 - maxEnergyPercent) * 0.01) { + continue; + } + + if (minimumEnergyAllowed === 0) minimumEnergyAllowed = 1 + else + minimumEnergyAllowed = candidate.energyCap * minimumEnergyAllowed / 100 + const energyArriving = minimumEnergyAllowed + (candidate.energy * (candidate.defense / 100)); + // needs to be a whole number for the contract + let energyNeeded = Math.ceil(df.getEnergyNeededForMove(candidatePlant.locationId, candidate.locationId, energyArriving)); + if (energyLeft - energyNeeded-energyUncomfiredOnTheWay < candidatePlant.energyCap * (100 - maxEnergyPercent) * 0.01) { + + if (allowMultiCrawl === true) { + if (energyLeft-energyUncomfiredOnTheWay <= energyNeeded * 0.35) + continue; + else { + energyNeeded = energyLeft-energyUncomfiredOnTheWay - candidatePlant.energyCap * (100 - maxEnergyPercent) * 0.01; + } + } + else + continue; + } + + + if (from.planetType === 1 && candidate.planetType === 0) { + silverNeed = candidate.silverCap > silverLeft ? silverLeft : candidate.silverCap; + silverSpent += silverNeed; + } + + df.move(candidatePlant.locationId, candidate.locationId, energyNeeded, silverNeed); + + energySpent += energyNeeded; + moves += 1; + } + return moves; + } \ No newline at end of file diff --git a/content/productivity/auto-crawl-planets/screenshot.png b/content/productivity/auto-crawl-planets/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..bbd7bb2da2a75cc668ce0e953ca0f68f8569ac2c GIT binary patch literal 21555 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 Date: Sat, 30 Oct 2021 13:56:07 +0800 Subject: [PATCH 2/2] Update plugin.js --- content/productivity/auto-crawl-planets/plugin.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/productivity/auto-crawl-planets/plugin.js b/content/productivity/auto-crawl-planets/plugin.js index 26bfeeae..3c7e4ad3 100644 --- a/content/productivity/auto-crawl-planets/plugin.js +++ b/content/productivity/auto-crawl-planets/plugin.js @@ -16,6 +16,9 @@ const { PlanetTypeNames, PlanetLevel, PlanetLevelNames, + ArtifactId, + Artifact, + ArtifactType, } from "https://cdn.skypack.dev/@darkforest_eth/types";