From 07b2a2ce72a075f8b536466044d6f14c2b94f740 Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 09:54:46 +0800 Subject: [PATCH 01/20] feat: mining - unload all res on dock when mining (may be save 1 res on ship with who use 1res setting) --- SLY_Assistant.user.js | 51 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 99d1609..164000f 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace http://tampermonkey.net/ -// @version 0.7.0 +// @version 0.7.0.22 // @description try to take over the world! // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ @@ -5188,13 +5188,46 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee await execDock(userFleets[i], userFleets[i].starbaseCoord); cLog(1,`${FleetTimeStamp(userFleets[i].label)} Unloading resource`); updateFleetState(userFleets[i], `Unloading`); - //if (currentResourceCnt > 0) { - let unloadAmount = currentResourceCnt; - if(globalSettings.minerKeep1 && unloadAmount > 0) { unloadAmount -= 1; } - if (unloadAmount > 0) { - await execCargoFromFleetToStarbase(userFleets[i], userFleets[i].cargoHold, userFleets[i].mineResource, userFleets[i].starbaseCoord, unloadAmount); - //await wait(2000); - } + + // let unloadAmount = currentResourceCnt; + // if(globalSettings.minerKeep1 && unloadAmount > 0) { unloadAmount -= 1; } + // if (unloadAmount > 0) { + // await execCargoFromFleetToStarbase(userFleets[i], userFleets[i].cargoHold, userFleets[i].mineResource, userFleets[i].starbaseCoord, unloadAmount); + // //await wait(2000); + // } + + //Unload all token except food (author: zihan) + const unloadQueue = [] + // console.log('mining fleetCurrentCargo', fleetCurrentCargo) + fleetCurrentCargo.value.forEach(async (item) => { + if (item.account.data.parsed.info.tokenAmount.uiAmount > 1 && + item.account.data.parsed.info.mint !== sageGameAcct.account.mints.food.toString()) { + // console.log('mining fleetCurrentCargo item', item.account.data.parsed.info) + unloadQueue.push( + execCargoFromFleetToStarbase( + userFleets[i], + userFleets[i].cargoHold, + item.account.data.parsed.info.mint, + userFleets[i].starbaseCoord, + item.account.data.parsed.info.tokenAmount.uiAmount - (globalSettings.minerKeep1 ? 1 : 0)) + ) + } + // if there is too much food, unload part of food + else if (item.account.data.parsed.info.tokenAmount.uiAmount > foodForDuration * 2 && + item.account.data.parsed.info.mint === sageGameAcct.account.mints.food.toString()) { + // console.log('mining fleetCurrentCargo food item', item.account.data.parsed.info) + unloadQueue.push( + execCargoFromFleetToStarbase( + userFleets[i], + userFleets[i].cargoHold, + item.account.data.parsed.info.mint, + userFleets[i].starbaseCoord, + item.account.data.parsed.info.tokenAmount.uiAmount - foodForDuration * 2) + ) + } + }) + await Promise.all(unloadQueue) + await wait(500); //if (currentFuelCnt < userFleets[i].fuelCapacity) { if (currentFuelCnt < fuelNeeded) { @@ -5259,7 +5292,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee //At mining area? else if (fleetCoords[0] == destX && fleetCoords[1] == destY) { - if(userFleets[i].stopping) return; + if (userFleets[i].stopping) return; fleetCurrentCargo = await solanaReadConnection.getParsedTokenAccountsByOwner(userFleets[i].cargoHold, {programId: tokenProgramPK}); cargoCnt = fleetCurrentCargo.value.reduce((n, {account}) => n + account.data.parsed.info.tokenAmount.uiAmount, 0); currentFood = fleetCurrentCargo.value.find(item => item.account.data.parsed.info.mint === sageGameAcct.account.mints.food.toString()); From 6ab82738639501c77456468b698219bf0fa7416b Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:03:58 +0800 Subject: [PATCH 02/20] feat: add smart movement When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs. --- SLY_Assistant.user.js | 92 +++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 99d1609..adcd8e9 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace http://tampermonkey.net/ -// @version 0.7.0 +// @version 0.7.0.31 // @description try to take over the world! // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ @@ -187,6 +187,9 @@ //Subwarp when the distance is 1 diagonal sector or less subwarpShortDist: parseBoolDefault(globalSettings.subwarpShortDist, true), + //How many fleet max distance rate to subwarp when is wrap cd (higher number = 2, 0 = none) + smartWarpRemainingDistanceRate: parseIntDefault(globalSettings.smartWarpRemainingDistanceRate, 0), + //Determines if your transports should use their ammo banks to move ammo (in addition to their cargo holds) transportUseAmmoBank: parseBoolDefault(globalSettings.transportUseAmmoBank, true), @@ -4246,6 +4249,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee debugLogLevel: parseIntDefault(document.querySelector('#debugLogLevel').value, 3), craftingJobs: parseIntDefault(document.querySelector('#craftingJobs').value, 4), subwarpShortDist: document.querySelector('#subwarpShortDist').checked, + smartWarpRemainingDistanceRate: parseIntDefault(document.querySelector('#smartWarpRemainingDistanceRate').value, 0), transportUseAmmoBank: document.querySelector('#transportUseAmmoBank').checked, transportStopOnError: document.querySelector('#transportStopOnError').checked, transportFuel100: document.querySelector('#transportFuel100').checked, @@ -4311,6 +4315,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee document.querySelector('#debugLogLevel').value = globalSettings.debugLogLevel; document.querySelector('#craftingJobs').value = globalSettings.craftingJobs; document.querySelector('#subwarpShortDist').checked = globalSettings.subwarpShortDist; + document.querySelector('#smartWarpRemainingDistanceRate').value = globalSettings.smartWarpRemainingDistanceRate; document.querySelector('#transportUseAmmoBank').checked = globalSettings.transportUseAmmoBank; document.querySelector('#transportStopOnError').checked = globalSettings.transportStopOnError; document.querySelector('#transportFuel100').checked = globalSettings.transportFuel100; @@ -4614,47 +4619,67 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let currentCargoFuel = fleetCurrentCargo.value.find(item => item.account.data.parsed.info.mint === sageGameAcct.account.mints.fuel.toString()); let currentCargoFuelCnt = currentCargoFuel ? currentCargoFuel.account.data.parsed.info.tokenAmount.uiAmount : 0; - let shortSubwarp = moveDist < 1.5 && globalSettings.subwarpShortDist ? true : false; + let shortSubwarp = moveDist < 1.5 && globalSettings.subwarpShortDist ? true : false; //Should a warp be attempted? if (userFleets[i].moveType == 'warp' && (currentFuelCnt + currentCargoFuelCnt) >= warpCost && !shortSubwarp) { let fleetAcctData = sageProgram.coder.accounts.decode('fleet', fleetAcctInfo.data); let warpCooldownExpiresAt = fleetAcctData.warpCooldownExpiresAt.toNumber() * 1000; - //Wait for cooldown - while (Date.now() < warpCooldownExpiresAt) { - if (!userFleets[i].state.includes('Warp C/D')) { - const warpCDExpireTimeStr = `[${TimeToStr(new Date(warpCooldownExpiresAt))}]`; - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Awaiting Warp C/D ${warpCDExpireTimeStr}`); - updateFleetState(userFleets[i], `Warp C/D ${warpCDExpireTimeStr}`); + // smart movement (author: zihan) + const maxWarpDistance = userFleets[i].maxWarpDistance / 100 + if (smartWarpRemainingDistanceRate > 0 && + ( + moveDist > maxWarpDistance && (warpCooldownExpiresAt - Date.now() > userFleets[i].warpCooldown * 1000 * 0.3) + || moveDist <= maxWarpDistance * smartWarpRemainingDistanceRate + ) + ) { + let moveDistNew = moveDist; + if (moveDist > maxWarpDistance) { + // if moveDist is too long distance, just subwarp half maxWarpDistance + moveDistNew = max(moveDist - maxWarpDistance, smartWarpRemainingDistanceRate * maxWarpDistance); + moveDistNew = min(moveDist, moveDistNew) + [moveX, moveY] = calcNextWarpPoint(moveDistNew, extra, [moveX, moveY]); } + moveTime = calculateSubwarpTime(userFleets[i], moveDistNew); + await execSubwarp(userFleets[i], moveX, moveY, moveTime); + } else { + //Wait for cooldown + while (Date.now() < warpCooldownExpiresAt) { + if (!userFleets[i].state.includes('Warp C/D')) { + const warpCDExpireTimeStr = `[${TimeToStr(new Date(warpCooldownExpiresAt))}]`; + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Awaiting Warp C/D ${warpCDExpireTimeStr}`); + updateFleetState(userFleets[i], `Warp C/D ${warpCDExpireTimeStr}`); + } - //await wait(Math.max(1000, warpCooldownExpiresAt - Date.now())); - if(warpCooldownExpiresAt - Date.now() < 5000) await wait(Math.max(1000, warpCooldownExpiresAt - Date.now())); - else await wait(5000); - if(userFleets[i].stopping) return; - } - await wait(2000); //Extra wait to ensure accuracy - - //Calculate next warp point if more than 1 is needed to arrive at final destination - if (moveDist > userFleets[i].maxWarpDistance / 100) { - [moveX, moveY] = calcNextWarpPoint(userFleets[i].maxWarpDistance, extra, [moveX, moveY]); - - //Saves temporary waypoints for transports in case the page is refreshed mid-journey while using warp - const fleetPK = userFleets[i].publicKey.toString(); - const fleetSavedData = await GM.getValue(fleetPK, '{}'); - const fleetParsedData = JSON.parse(fleetSavedData); - //cLog(3, `${FleetTimeStamp(userFleets[i].label)} moveTargets`, fleetParsedData.moveTarget, userFleets[i].moveTarget); - fleetParsedData.moveTarget = userFleets[i].moveTarget; - await GM.setValue(fleetPK, JSON.stringify(fleetParsedData)); + //await wait(Math.max(1000, warpCooldownExpiresAt - Date.now())); + if (warpCooldownExpiresAt - Date.now() < 5000) await wait(Math.max(1000, warpCooldownExpiresAt - Date.now())); + else await wait(5000); + if (userFleets[i].stopping) return; + } + await wait(2000); //Extra wait to ensure accuracy + + //Calculate next warp point if more than 1 is needed to arrive at final destination + if (moveDist > userFleets[i].maxWarpDistance / 100) { + [moveX, moveY] = calcNextWarpPoint(userFleets[i].maxWarpDistance, extra, [moveX, moveY]); + + //Saves temporary waypoints for transports in case the page is refreshed mid-journey while using warp + const fleetPK = userFleets[i].publicKey.toString(); + const fleetSavedData = await GM.getValue(fleetPK, '{}'); + const fleetParsedData = JSON.parse(fleetSavedData); + //cLog(3, `${FleetTimeStamp(userFleets[i].label)} moveTargets`, fleetParsedData.moveTarget, userFleets[i].moveTarget); + fleetParsedData.moveTarget = userFleets[i].moveTarget; + await GM.setValue(fleetPK, JSON.stringify(fleetParsedData)); + + //Update distance based on new warp target + moveDist = calculateMovementDistance(extra, [moveX,moveY]); + } - //Update distance based on new warp target - moveDist = calculateMovementDistance(extra, [moveX,moveY]); + moveTime = calculateWarpTime(userFleets[i], moveDist); + const warpResult = await execWarp(userFleets[i], moveX, moveY, moveTime); + warpCooldownFinished = warpResult.warpCooldownFinished; } - - moveTime = calculateWarpTime(userFleets[i], moveDist); - const warpResult = await execWarp(userFleets[i], moveX, moveY, moveTime); - warpCooldownFinished = warpResult.warpCooldownFinished; - } else if (currentFuelCnt + currentCargoFuelCnt >= subwarpCost) { + } + else if (currentFuelCnt + currentCargoFuelCnt >= subwarpCost) { moveTime = calculateSubwarpTime(userFleets[i], moveDist); await execSubwarp(userFleets[i], moveX, moveY, moveTime); } else { @@ -7151,6 +7176,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee settingsModalContentString += ''; settingsModalContentString += '
  • '; settingsModalContentString += '
    Subwarp for short distances?
    Should fleets subwarp when travel distance is 1 diagonal square or less?
    '; + settingsModalContentString += '
    Smart Warp, Remaining distance: fleet Max Warp Distance
    When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs.
    '; settingsModalContentString += '
    Use Ammo Banks for Transport?
    Should transports also use their ammo banks to help move ammo?
    '; settingsModalContentString += '
    Stop Transports On Error
    Should transport fleet stop completely if there is an error (example: not enough resource/fuel/etc.)?
    '; settingsModalContentString += '
    Fuel to 100% for transports
    If a refuel is needed at the source, should transport fleets fill fuel to 100%? Can save a lot of transactions (depends on the tank size of the fleet).
    '; From c5fef62ae8cd5b9e4513cc098e31210581c6ee3c Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:18:13 +0800 Subject: [PATCH 03/20] feat: use multiple food for mining Using multiple times the amount of food for mining can reduce the frequency of food supply --- SLY_Assistant.user.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 164000f..88fd750 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -187,6 +187,9 @@ //Subwarp when the distance is 1 diagonal sector or less subwarpShortDist: parseBoolDefault(globalSettings.subwarpShortDist, true), + //How much multiple food for mining (max: 2, default: 1) + multipleFoodMining: parseIntDefault(globalSettings.multipleFoodMining, 1), + //Determines if your transports should use their ammo banks to move ammo (in addition to their cargo holds) transportUseAmmoBank: parseBoolDefault(globalSettings.transportUseAmmoBank, true), @@ -4246,6 +4249,8 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee debugLogLevel: parseIntDefault(document.querySelector('#debugLogLevel').value, 3), craftingJobs: parseIntDefault(document.querySelector('#craftingJobs').value, 4), subwarpShortDist: document.querySelector('#subwarpShortDist').checked, + + multipleFoodMining: parseIntDefault(document.querySelector('#multipleFoodMining').value, 1), transportUseAmmoBank: document.querySelector('#transportUseAmmoBank').checked, transportStopOnError: document.querySelector('#transportStopOnError').checked, transportFuel100: document.querySelector('#transportFuel100').checked, @@ -4311,6 +4316,8 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee document.querySelector('#debugLogLevel').value = globalSettings.debugLogLevel; document.querySelector('#craftingJobs').value = globalSettings.craftingJobs; document.querySelector('#subwarpShortDist').checked = globalSettings.subwarpShortDist; + + document.querySelector('#multipleFoodMining').value = globalSettings.multipleFoodMining; document.querySelector('#transportUseAmmoBank').checked = globalSettings.transportUseAmmoBank; document.querySelector('#transportStopOnError').checked = globalSettings.transportStopOnError; document.querySelector('#transportFuel100').checked = globalSettings.transportFuel100; @@ -5265,10 +5272,20 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loading food`); updateFleetState(userFleets[i], `Loading`); let foodCargoTypeAcct = cargoTypes.find(item => item.account.mint.toString() == sageGameAcct.account.mints.food); - let foodResp = await execCargoFromStarbaseToFleet(userFleets[i], userFleets[i].cargoHold, fleetFoodAcct, sageGameAcct.account.mints.food.toString(), foodCargoTypeAcct, userFleets[i].starbaseCoord, foodForDuration - currentFoodCnt); + + // use multiple food for mining (authoer: zihan) + function respFoodfn(amount) { + return execCargoFromStarbaseToFleet(userFleets[i], userFleets[i].cargoHold, fleetFoodAcct, sageGameAcct.account.mints.food.toString(), foodCargoTypeAcct, userFleets[i].starbaseCoord, amount); + } + let foodResp = await respFoodfn(foodForDuration * multipleFoodMining - currentFoodCnt); if (foodResp && foodResp.name == 'NotEnoughResource') { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Not enough food`); - errorResource.push('food'); + // try load food little again + cLog(1, 'try load food little again'); + foodResp = await respFoodfn(foodForDuration - currentFoodCnt); + if (foodResp && foodResp.name == 'NotEnoughResource') { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Not enough food`); + errorResource.push('food'); + } } //await wait(2000); } else { cLog(1,`${FleetTimeStamp(userFleets[i].label)} Food loading skipped: ${currentFoodCnt} / ${foodForDuration}`); } @@ -7184,6 +7201,8 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee settingsModalContentString += '
  • '; settingsModalContentString += '
  • '; settingsModalContentString += '
    Subwarp for short distances?
    Should fleets subwarp when travel distance is 1 diagonal square or less?
    '; + + settingsModalContentString += '
    Use multiple food for mining?
    Using multiple times the amount of food for mining can reduce the frequency of food supply
    '; settingsModalContentString += '
    Use Ammo Banks for Transport?
    Should transports also use their ammo banks to help move ammo?
    '; settingsModalContentString += '
    Stop Transports On Error
    Should transport fleet stop completely if there is an error (example: not enough resource/fuel/etc.)?
    '; settingsModalContentString += '
    Fuel to 100% for transports
    If a refuel is needed at the source, should transport fleets fill fuel to 100%? Can save a lot of transactions (depends on the tank size of the fleet).
    '; From 0ddfcc0928f49a39e3ffc0d934305c5534fb0a92 Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:27:06 +0800 Subject: [PATCH 04/20] update: desc for Smart Warp --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index adcd8e9..1da5dc8 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -7176,7 +7176,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee settingsModalContentString += '
  • '; settingsModalContentString += '
  • '; settingsModalContentString += '
    Subwarp for short distances?
    Should fleets subwarp when travel distance is 1 diagonal square or less?
    '; - settingsModalContentString += '
    Smart Warp, Remaining distance: fleet Max Warp Distance
    When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs.
    '; + settingsModalContentString += '
    Smart Warp, Remaining distance: multiple fleet Max Warp Distance
    Suggestion 0.5 (=50% max warp distance).
    When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs.
    '; settingsModalContentString += '
    Use Ammo Banks for Transport?
    Should transports also use their ammo banks to help move ammo?
    '; settingsModalContentString += '
    Stop Transports On Error
    Should transport fleet stop completely if there is an error (example: not enough resource/fuel/etc.)?
    '; settingsModalContentString += '
    Fuel to 100% for transports
    If a refuel is needed at the source, should transport fleets fill fuel to 100%? Can save a lot of transactions (depends on the tank size of the fleet).
    '; From 3823445070a33a3897c3f099283581891d4b8457 Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:28:20 +0800 Subject: [PATCH 05/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 0efc73f..f158652 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace http://tampermonkey.net/ -// @version 0.7.0.31 +// @version 0.7.0.32 // @description try to take over the world! // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ From b9e1100b679477787d281a699c036296c4fd27a6 Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:35:26 +0800 Subject: [PATCH 06/20] fix: smart movement --- SLY_Assistant.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 1da5dc8..d6ba3ea 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -4630,13 +4630,13 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee if (smartWarpRemainingDistanceRate > 0 && ( moveDist > maxWarpDistance && (warpCooldownExpiresAt - Date.now() > userFleets[i].warpCooldown * 1000 * 0.3) - || moveDist <= maxWarpDistance * smartWarpRemainingDistanceRate + || moveDist <= maxWarpDistance * smartWarpRemainingDistanceRate * 0.01 ) ) { let moveDistNew = moveDist; if (moveDist > maxWarpDistance) { // if moveDist is too long distance, just subwarp half maxWarpDistance - moveDistNew = max(moveDist - maxWarpDistance, smartWarpRemainingDistanceRate * maxWarpDistance); + moveDistNew = max(moveDist - maxWarpDistance, smartWarpRemainingDistanceRate * 0.01 * maxWarpDistance); moveDistNew = min(moveDist, moveDistNew) [moveX, moveY] = calcNextWarpPoint(moveDistNew, extra, [moveX, moveY]); } @@ -7176,7 +7176,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee settingsModalContentString += '
  • '; settingsModalContentString += '
  • '; settingsModalContentString += '
    Subwarp for short distances?
    Should fleets subwarp when travel distance is 1 diagonal square or less?
    '; - settingsModalContentString += '
    Smart Warp, Remaining distance: multiple fleet Max Warp Distance
    Suggestion 0.5 (=50% max warp distance).
    When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs.
    '; + settingsModalContentString += '
    Smart Warp, Remaining distance: % fleet Max Warp Distance
    Suggestion 50 (=50% max warp distance).
    When warp CD, if there is not much remaining distance, using subwarp directly can better utilize time and control costs.
    '; settingsModalContentString += '
    Use Ammo Banks for Transport?
    Should transports also use their ammo banks to help move ammo?
    '; settingsModalContentString += '
    Stop Transports On Error
    Should transport fleet stop completely if there is an error (example: not enough resource/fuel/etc.)?
    '; settingsModalContentString += '
    Fuel to 100% for transports
    If a refuel is needed at the source, should transport fleets fill fuel to 100%? Can save a lot of transactions (depends on the tank size of the fleet).
    '; From 2f0369eb135195a5dfbc6f1a3eb6bd07c99081c4 Mon Sep 17 00:00:00 2001 From: zihan Date: Sun, 23 Mar 2025 14:38:44 +0800 Subject: [PATCH 07/20] chore: update icon form staratlas link --- SLY_Assistant.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 786082b..22a3f8e 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,15 +1,15 @@ // ==UserScript== // @name SLY Assistant -// @namespace http://tampermonkey.net/ +// @namespace https://github.com/ImGroovin/SLY-Assistant // @version 0.7.0.32 -// @description try to take over the world! +// @description Base http://tampermonkey.net/ // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ // @require https://unpkg.com/@solana/web3.js@1.95.8/lib/index.iife.min.js#sha256=a759deca1b65df140e8dda5ad8645c19579536bf822e5c0c7e4adb7793a5bd08 // @require https://raw.githubusercontent.com/ImGroovin/SAGE-Lab-Assistant/main/anchor-browserified.js#sha256=f29ef75915bcf59221279f809eefc55074dbebf94cf16c968e783558e7ae3f0a // @require https://raw.githubusercontent.com/ImGroovin/SAGE-Lab-Assistant/main/buffer-browserified.js#sha256=4fa88e735f9f1fdbff85f4f92520e8874f2fec4e882b15633fad28a200693392 // @require https://raw.githubusercontent.com/ImGroovin/SAGE-Lab-Assistant/main/bs58-browserified.js#sha256=87095371ec192e5a0e50c6576f327eb02532a7c29f1ed86700a2f8fb5018d947 -// @icon https://www.google.com/s2/favicons?sz=64&domain=staratlas.com +// @icon https://cdn.staratlas.com/sage-labs/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue From e76f04a11167f4f8e25e83b11a5cf7c7c0c7f38f Mon Sep 17 00:00:00 2001 From: zihan Date: Tue, 25 Mar 2025 23:49:34 +0800 Subject: [PATCH 08/20] fix: smart movement rate value --- SLY_Assistant.user.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index d6ba3ea..cf14465 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace http://tampermonkey.net/ -// @version 0.7.0.31 +// @version 0.7.0.32 // @description try to take over the world! // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ @@ -4627,16 +4627,16 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee // smart movement (author: zihan) const maxWarpDistance = userFleets[i].maxWarpDistance / 100 - if (smartWarpRemainingDistanceRate > 0 && + if (globalSettings.smartWarpRemainingDistanceRate > 0 && ( moveDist > maxWarpDistance && (warpCooldownExpiresAt - Date.now() > userFleets[i].warpCooldown * 1000 * 0.3) - || moveDist <= maxWarpDistance * smartWarpRemainingDistanceRate * 0.01 + || moveDist <= maxWarpDistance * globalSettings.smartWarpRemainingDistanceRate * 0.01 ) ) { let moveDistNew = moveDist; if (moveDist > maxWarpDistance) { // if moveDist is too long distance, just subwarp half maxWarpDistance - moveDistNew = max(moveDist - maxWarpDistance, smartWarpRemainingDistanceRate * 0.01 * maxWarpDistance); + moveDistNew = max(moveDist - maxWarpDistance, globalSettings.smartWarpRemainingDistanceRate * 0.01 * maxWarpDistance); moveDistNew = min(moveDist, moveDistNew) [moveX, moveY] = calcNextWarpPoint(moveDistNew, extra, [moveX, moveY]); } From 8db62a2ec1889ac8077842a22f927d43cb8aecde Mon Sep 17 00:00:00 2001 From: zihan Date: Tue, 25 Mar 2025 23:53:07 +0800 Subject: [PATCH 09/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index c6db928..e569139 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -509,8 +509,8 @@ cLog(0,'getALTs()'); await getALTs(); - console.log('craftRecipes: ', craftRecipes); - console.log('upgradeRecipes: ', upgradeRecipes); + cLog(1, `craftRecipes: ${craftRecipes}`); + cLog(1, `upgradeRecipes: ${upgradeRecipes}`); let sduItem = cargoItems.find(item => item.name === 'Survey Data Unit'); let fuelItem = cargoItems.find(item => item.token === sageGameAcct.account.mints.fuel.toString()); From 0af85d77dbc692907f5e00726ebe8e67d97e3682 Mon Sep 17 00:00:00 2001 From: zihan Date: Tue, 25 Mar 2025 23:53:25 +0800 Subject: [PATCH 10/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index e569139..0280c42 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -500,13 +500,13 @@ }, ]); - cLog(0,'getResourceTokens()'); + cLog(1,'getResourceTokens()'); await getResourceTokens(); - cLog(0,'getCraftRecipes()'); + cLog(1,'getCraftRecipes()'); await getCraftRecipes(); - cLog(0,'getALTs()'); + cLog(1,'getALTs()'); await getALTs(); cLog(1, `craftRecipes: ${craftRecipes}`); From 4e735ffed1568e834e767854ae0a735d842d74f8 Mon Sep 17 00:00:00 2001 From: zihan Date: Tue, 25 Mar 2025 23:55:53 +0800 Subject: [PATCH 11/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 0280c42..1239434 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -6834,7 +6834,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee validMRZTargets.sort((a, b) => { if (a.name < b.name) { return -1; } if (a.name > b.name) { return 1; } return 0; }); validTargets = validMainTargets.concat(validMRZTargets); - console.log('validTargets:',validTargets); + cLog(1, `validTargets: ${validTargets}`); resolve(); }); From 934adceb20cfdd58d7ab9575120d821aa6272068 Mon Sep 17 00:00:00 2001 From: zihan Date: Tue, 25 Mar 2025 23:58:15 +0800 Subject: [PATCH 12/20] chore: add clog for smart movement debug --- SLY_Assistant.user.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index cf14465..7135538 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -4626,6 +4626,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let warpCooldownExpiresAt = fleetAcctData.warpCooldownExpiresAt.toNumber() * 1000; // smart movement (author: zihan) + cLog(2, `smart movement ready? moveDist:${moveDist}, maxWarpDistance:${maxWarpDistance}, Setting:${globalSettings.smartWarpRemainingDistanceRate}`) const maxWarpDistance = userFleets[i].maxWarpDistance / 100 if (globalSettings.smartWarpRemainingDistanceRate > 0 && ( @@ -4635,6 +4636,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee ) { let moveDistNew = moveDist; if (moveDist > maxWarpDistance) { + cLog(2, `smart movement going`) // if moveDist is too long distance, just subwarp half maxWarpDistance moveDistNew = max(moveDist - maxWarpDistance, globalSettings.smartWarpRemainingDistanceRate * 0.01 * maxWarpDistance); moveDistNew = min(moveDist, moveDistNew) From cba77c2b427ee1df2a144381f8a9c1099e490c3c Mon Sep 17 00:00:00 2001 From: zihan Date: Wed, 26 Mar 2025 00:05:08 +0800 Subject: [PATCH 13/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 844f52d..1398028 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -509,8 +509,8 @@ cLog(1,'getALTs()'); await getALTs(); - cLog(1, `craftRecipes: ${craftRecipes}`); - cLog(1, `upgradeRecipes: ${upgradeRecipes}`); + cLog(1, 'craftRecipes: ', craftRecipes); + cLog(1, 'upgradeRecipes: ', upgradeRecipes); let sduItem = cargoItems.find(item => item.name === 'Survey Data Unit'); let fuelItem = cargoItems.find(item => item.token === sageGameAcct.account.mints.fuel.toString()); From b12362a0221273d9c34f63b1957036e40fe2d2e8 Mon Sep 17 00:00:00 2001 From: zihan Date: Wed, 26 Mar 2025 05:15:28 +0800 Subject: [PATCH 14/20] fix: use multiple food for mining no globalSettings bug --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 88fd750..40674ed 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -5277,7 +5277,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee function respFoodfn(amount) { return execCargoFromStarbaseToFleet(userFleets[i], userFleets[i].cargoHold, fleetFoodAcct, sageGameAcct.account.mints.food.toString(), foodCargoTypeAcct, userFleets[i].starbaseCoord, amount); } - let foodResp = await respFoodfn(foodForDuration * multipleFoodMining - currentFoodCnt); + let foodResp = await respFoodfn(foodForDuration * globalSettings.multipleFoodMining - currentFoodCnt); if (foodResp && foodResp.name == 'NotEnoughResource') { // try load food little again cLog(1, 'try load food little again'); From 33911b36b5c2a254395d739c889cbdb38bf0cbc9 Mon Sep 17 00:00:00 2001 From: zihan Date: Wed, 26 Mar 2025 05:16:10 +0800 Subject: [PATCH 15/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index f945a8a..127e680 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace https://github.com/ImGroovin/SLY-Assistant -// @version 0.7.0.32 +// @version 0.7.0.33 // @description Base http://tampermonkey.net/ // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ From 2cf8ea81839492811073ab8afc6915e77b92a846 Mon Sep 17 00:00:00 2001 From: zihan Date: Wed, 26 Mar 2025 05:18:26 +0800 Subject: [PATCH 16/20] feat: more setting for use multiple food for mining --- SLY_Assistant.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 40674ed..8043254 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace http://tampermonkey.net/ -// @version 0.7.0.22 +// @version 0.7.0.34 // @description try to take over the world! // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ @@ -7202,7 +7202,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee settingsModalContentString += '
  • '; settingsModalContentString += '
    Subwarp for short distances?
    Should fleets subwarp when travel distance is 1 diagonal square or less?
    '; - settingsModalContentString += '
    Use multiple food for mining?
    Using multiple times the amount of food for mining can reduce the frequency of food supply
    '; + settingsModalContentString += '
    Use multiple food for mining?
    Using multiple times the amount of food for mining can reduce the frequency of food supply
    '; settingsModalContentString += '
    Use Ammo Banks for Transport?
    Should transports also use their ammo banks to help move ammo?
    '; settingsModalContentString += '
    Stop Transports On Error
    Should transport fleet stop completely if there is an error (example: not enough resource/fuel/etc.)?
    '; settingsModalContentString += '
    Fuel to 100% for transports
    If a refuel is needed at the source, should transport fleets fill fuel to 100%? Can save a lot of transactions (depends on the tank size of the fleet).
    '; From aa9537be4a706f2f06047253c90acf7a6d8997e6 Mon Sep 17 00:00:00 2001 From: zihan Date: Fri, 28 Mar 2025 00:14:17 +0800 Subject: [PATCH 17/20] fix: smart movement maxWarpDistance stupid mistakes --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index cfd3790..810f6b8 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -4633,8 +4633,8 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let warpCooldownExpiresAt = fleetAcctData.warpCooldownExpiresAt.toNumber() * 1000; // smart movement (author: zihan) - cLog(2, `smart movement ready? moveDist:${moveDist}, maxWarpDistance:${maxWarpDistance}, Setting:${globalSettings.smartWarpRemainingDistanceRate}`) const maxWarpDistance = userFleets[i].maxWarpDistance / 100 + cLog(2, `smart movement ready? moveDist:${moveDist}, maxWarpDistance:${maxWarpDistance}, Setting:${globalSettings.smartWarpRemainingDistanceRate}`) if (globalSettings.smartWarpRemainingDistanceRate > 0 && ( moveDist > maxWarpDistance && (warpCooldownExpiresAt - Date.now() > userFleets[i].warpCooldown * 1000 * 0.3) From 4b77388298699a0593c991277f69c2226c81dc4f Mon Sep 17 00:00:00 2001 From: zihan Date: Fri, 28 Mar 2025 00:14:33 +0800 Subject: [PATCH 18/20] Update SLY_Assistant.user.js --- SLY_Assistant.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index 810f6b8..f436251 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace https://github.com/ImGroovin/SLY-Assistant -// @version 0.7.0.34 +// @version 0.7.0.35 // @description Base http://tampermonkey.net/ // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ From 314fb62e25d0198d52a27eda493cd21928be5fb4 Mon Sep 17 00:00:00 2001 From: zihan Date: Mon, 14 Apr 2025 10:40:17 +0800 Subject: [PATCH 19/20] update format -> space to tab indent --- SLY_Assistant.user.js | 368 +++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 184 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index f436251..e8367bb 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -5519,212 +5519,212 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee } async function handleTransport(i, fleetState, fleetCoords) { - const [destX, destY] = ConvertCoords(userFleets[i].destCoord); - const [starbaseX, starbaseY] = ConvertCoords(userFleets[i].starbaseCoord); - - const fleetParsedData = JSON.parse(await GM.getValue(userFleets[i].publicKey.toString(), '{}')); - let targetCargoManifest = [ - {res: fleetParsedData.transportResource1, amt: fleetParsedData.transportResource1Perc, crew: fleetParsedData.transportResource1Crew }, - {res: fleetParsedData.transportResource2, amt: fleetParsedData.transportResource2Perc,}, - {res: fleetParsedData.transportResource3, amt: fleetParsedData.transportResource3Perc,}, - {res: fleetParsedData.transportResource4, amt: fleetParsedData.transportResource4Perc,}, - ]; - let starbaseCargoManifest = [ - {res: fleetParsedData.transportSBResource1, amt: fleetParsedData.transportSBResource1Perc, crew: fleetParsedData.transportSBResource1Crew}, - {res: fleetParsedData.transportSBResource2, amt: fleetParsedData.transportSBResource2Perc,}, - {res: fleetParsedData.transportSBResource3, amt: fleetParsedData.transportSBResource3Perc,}, - {res: fleetParsedData.transportSBResource4, amt: fleetParsedData.transportSBResource4Perc,}, - ]; - const hasTargetManifest = hasTransportManifest(targetCargoManifest); - const hasStarbaseManifest = hasTransportManifest(starbaseCargoManifest); - - //let moveDist = calculateMovementDistance([starbaseX,starbaseY], [destX,destY]); - if (fleetState === 'Idle') { - // Fleet at starbase? - if (fleetCoords[0] == starbaseX && fleetCoords[1] == starbaseY) { - userFleets[i].resupplying = true; - - let checkCargoResult = await checkCargo(starbaseCargoManifest, targetCargoManifest, userFleets[i]); - starbaseCargoManifest = checkCargoResult.currentManifest; - targetCargoManifest = checkCargoResult.destinationManifest; - - let needToUnloadCrew = 0; - if((starbaseCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && (userFleets[i].crewCount - userFleets[i].requiredCrew > 0)) { - needToUnloadCrew = userFleets[i].crewCount - userFleets[i].requiredCrew; - } - let needToLoadCrew = 0; - if((targetCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && ((userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount - needToUnloadCrew) > 0)) { - needToLoadCrew = Math.min(userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount, targetCargoManifest[0].crew); - } - if(starbaseCargoManifest[0].crew > 0 || targetCargoManifest[0].crew > 0) cLog(3, `${FleetTimeStamp(userFleets[i].label)} crew:`, userFleets[i].crewCount, 'passengerCapacity:', userFleets[i].passengerCapacity, 'required crew:', userFleets[i].requiredCrew, 'load:', needToLoadCrew, 'unload:', needToUnloadCrew); - - const fuelData = await getFleetFuelData(userFleets[i], [starbaseX, starbaseY], [destX, destY], true); - //previously we only checked for "fuelData.fuelNeeded > 0" below, but fuelNeeded is always greater than 0 - it is just the fuel needed for the warp/subwarp. - //this broke the check if the fleet needs to do the dock/undock sequence and the sequence was always executed - //We need to explicitly calculate the needed fuel minus the available fuel, just like in handleTransportRefueling() - const fuelEntry = targetCargoManifest.find(e => e.res === sageGameAcct.account.mints.fuel.toString()) || {amt: 0}; - const totalFuel = fuelData.fuelNeeded + fuelEntry.amt; - let fuelToAdd = Math.min(fuelData.capacity, totalFuel) - fuelData.amount; - - cLog(3,`${FleetTimeStamp(userFleets[i].label)} Fuel needed`, fuelData.fuelNeeded, '/ fuel found', fuelData.amount, '/ fuel to add', fuelToAdd, '/ needToLoad', checkCargoResult.needToLoad, '/ needToUnload', checkCargoResult.needToUnload, '/ needToLoadCrew', needToLoadCrew, '/ needToUnloadCrew', needToUnloadCrew); - - //if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelData.fuelNeeded > 0 || needToLoadCrew || needToUnloadCrew) { - if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelToAdd > 0 || needToLoadCrew > 0 || needToUnloadCrew > 0) { - await execDock(userFleets[i], userFleets[i].starbaseCoord); + const [destX, destY] = ConvertCoords(userFleets[i].destCoord); + const [starbaseX, starbaseY] = ConvertCoords(userFleets[i].starbaseCoord); + + const fleetParsedData = JSON.parse(await GM.getValue(userFleets[i].publicKey.toString(), '{}')); + let targetCargoManifest = [ + {res: fleetParsedData.transportResource1, amt: fleetParsedData.transportResource1Perc, crew: fleetParsedData.transportResource1Crew }, + {res: fleetParsedData.transportResource2, amt: fleetParsedData.transportResource2Perc,}, + {res: fleetParsedData.transportResource3, amt: fleetParsedData.transportResource3Perc,}, + {res: fleetParsedData.transportResource4, amt: fleetParsedData.transportResource4Perc,}, + ]; + let starbaseCargoManifest = [ + {res: fleetParsedData.transportSBResource1, amt: fleetParsedData.transportSBResource1Perc, crew: fleetParsedData.transportSBResource1Crew}, + {res: fleetParsedData.transportSBResource2, amt: fleetParsedData.transportSBResource2Perc,}, + {res: fleetParsedData.transportSBResource3, amt: fleetParsedData.transportSBResource3Perc,}, + {res: fleetParsedData.transportSBResource4, amt: fleetParsedData.transportSBResource4Perc,}, + ]; + const hasTargetManifest = hasTransportManifest(targetCargoManifest); + const hasStarbaseManifest = hasTransportManifest(starbaseCargoManifest); + + //let moveDist = calculateMovementDistance([starbaseX,starbaseY], [destX,destY]); + if (fleetState === 'Idle') { + // Fleet at starbase? + if (fleetCoords[0] == starbaseX && fleetCoords[1] == starbaseY) { + userFleets[i].resupplying = true; - if (hasStarbaseManifest || checkCargoResult.needToUnload) { - await handleTransportUnloading(userFleets[i], userFleets[i].starbaseCoord, starbaseCargoManifest); - } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Unloading skipped - No resources specified`); + let checkCargoResult = await checkCargo(starbaseCargoManifest, targetCargoManifest, userFleets[i]); + starbaseCargoManifest = checkCargoResult.currentManifest; + targetCargoManifest = checkCargoResult.destinationManifest; - if(needToUnloadCrew) { - await handleCrewUnloading(userFleets[i], userFleets[i].starbaseCoord, needToUnloadCrew); - } - if(needToLoadCrew) { - let crewResp = await handleCrewLoading(userFleets[i], userFleets[i].starbaseCoord, needToLoadCrew); - if (crewResp && crewResp.name == 'NotEnoughCrew') { - if(globalSettings.transportStopOnError) { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Not enough crew`); - updateFleetState(userFleets[i], 'ERROR: Not enough crew'); - return; - } else { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Not enough crew`); + let needToUnloadCrew = 0; + if((starbaseCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && (userFleets[i].crewCount - userFleets[i].requiredCrew > 0)) { + needToUnloadCrew = userFleets[i].crewCount - userFleets[i].requiredCrew; } - } - } + let needToLoadCrew = 0; + if((targetCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && ((userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount - needToUnloadCrew) > 0)) { + needToLoadCrew = Math.min(userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount, targetCargoManifest[0].crew); + } + if(starbaseCargoManifest[0].crew > 0 || targetCargoManifest[0].crew > 0) cLog(3, `${FleetTimeStamp(userFleets[i].label)} crew:`, userFleets[i].crewCount, 'passengerCapacity:', userFleets[i].passengerCapacity, 'required crew:', userFleets[i].requiredCrew, 'load:', needToLoadCrew, 'unload:', needToUnloadCrew); - //Refueling at Starbase - let refuelResp = await handleTransportRefueling(userFleets[i], userFleets[i].starbaseCoord, [starbaseX, starbaseY], [destX, destY], true, 0, targetCargoManifest); - if (refuelResp.status === 0) { - userFleets[i].state = refuelResp.detail; - return; - } + const fuelData = await getFleetFuelData(userFleets[i], [starbaseX, starbaseY], [destX, destY], true); + //previously we only checked for "fuelData.fuelNeeded > 0" below, but fuelNeeded is always greater than 0 - it is just the fuel needed for the warp/subwarp. + //this broke the check if the fleet needs to do the dock/undock sequence and the sequence was always executed + //We need to explicitly calculate the needed fuel minus the available fuel, just like in handleTransportRefueling() + const fuelEntry = targetCargoManifest.find(e => e.res === sageGameAcct.account.mints.fuel.toString()) || {amt: 0}; + const totalFuel = fuelData.fuelNeeded + fuelEntry.amt; + let fuelToAdd = Math.min(fuelData.capacity, totalFuel) - fuelData.amount; - let fuelIndex = targetCargoManifest.findIndex(e => e.res === sageGameAcct.account.mints.fuel.toString()); - if (fuelIndex > -1) { - targetCargoManifest[fuelIndex].amt = targetCargoManifest[fuelIndex].amt - refuelResp.amount; - } + cLog(3,`${FleetTimeStamp(userFleets[i].label)} Fuel needed`, fuelData.fuelNeeded, '/ fuel found', fuelData.amount, '/ fuel to add', fuelToAdd, '/ needToLoad', checkCargoResult.needToLoad, '/ needToUnload', checkCargoResult.needToUnload, '/ needToLoadCrew', needToLoadCrew, '/ needToUnloadCrew', needToUnloadCrew); - //Loading at Starbase - if (hasTargetManifest) { - const loadedCargo = await handleTransportLoading(i, userFleets[i].starbaseCoord, targetCargoManifest); - cLog(4,`${FleetTimeStamp(userFleets[i].label)} loadedCargo: `, loadedCargo); - if(!loadedCargo && globalSettings.transportStopOnError) { - //const newFleetState = `ERROR: No more cargo to load`; - //cLog(1,`${FleetTimeStamp(userFleets[i].label)} ${newFleetState}`); - //userFleets[i].state = newFleetState; - cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Unexpected error on cargo load.`); - return; - } - } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loading skipped - No resources specified`); + //if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelData.fuelNeeded > 0 || needToLoadCrew || needToUnloadCrew) { + if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelToAdd > 0 || needToLoadCrew > 0 || needToUnloadCrew > 0) { + await execDock(userFleets[i], userFleets[i].starbaseCoord); - let undockResult = await execUndock(userFleets[i], userFleets[i].starbaseCoord); - cLog(4,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, undockResult); - let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); - } - userFleets[i].moveTarget = userFleets[i].destCoord; - userFleets[i].resupplying = false; - cLog(3,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, userFleets[i]); - } + if (hasStarbaseManifest || checkCargoResult.needToUnload) { + await handleTransportUnloading(userFleets[i], userFleets[i].starbaseCoord, starbaseCargoManifest); + } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Unloading skipped - No resources specified`); - // Fleet at target? - else if (fleetCoords[0] == destX && fleetCoords[1] == destY) { - userFleets[i].resupplying = true; + if(needToUnloadCrew) { + await handleCrewUnloading(userFleets[i], userFleets[i].starbaseCoord, needToUnloadCrew); + } + if(needToLoadCrew) { + let crewResp = await handleCrewLoading(userFleets[i], userFleets[i].starbaseCoord, needToLoadCrew); + if (crewResp && crewResp.name == 'NotEnoughCrew') { + if(globalSettings.transportStopOnError) { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Not enough crew`); + updateFleetState(userFleets[i], 'ERROR: Not enough crew'); + return; + } else { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Not enough crew`); + } + } + } - let checkCargoResult = await checkCargo(targetCargoManifest, starbaseCargoManifest, userFleets[i]); - targetCargoManifest = checkCargoResult.currentManifest; - starbaseCargoManifest = checkCargoResult.destinationManifest; + //Refueling at Starbase + let refuelResp = await handleTransportRefueling(userFleets[i], userFleets[i].starbaseCoord, [starbaseX, starbaseY], [destX, destY], true, 0, targetCargoManifest); + if (refuelResp.status === 0) { + userFleets[i].state = refuelResp.detail; + return; + } - let needToUnloadCrew = 0; - if((targetCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && (userFleets[i].crewCount - userFleets[i].requiredCrew > 0)) { - needToUnloadCrew = userFleets[i].crewCount - userFleets[i].requiredCrew; - } - let needToLoadCrew = 0; - if((starbaseCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && ((userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount - needToUnloadCrew) > 0)) { - needToLoadCrew = Math.min(userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount, starbaseCargoManifest[0].crew); - } - if(starbaseCargoManifest[0].crew > 0 || targetCargoManifest[0].crew > 0) cLog(3, `${FleetTimeStamp(userFleets[i].label)} crew:`, userFleets[i].crewCount, 'passengerCapacity:', userFleets[i].passengerCapacity, 'required crew:', userFleets[i].requiredCrew, 'load:', needToLoadCrew, 'unload:', needToUnloadCrew); + let fuelIndex = targetCargoManifest.findIndex(e => e.res === sageGameAcct.account.mints.fuel.toString()); + if (fuelIndex > -1) { + targetCargoManifest[fuelIndex].amt = targetCargoManifest[fuelIndex].amt - refuelResp.amount; + } - const fuelData = await getFleetFuelData(userFleets[i], [destX, destY], [starbaseX, starbaseY], false); - //previously we only checked for "fuelData.fuelNeeded > 0" below, but fuelNeeded is always greater than 0 - it is just the fuel needed for the warp/subwarp. - //We need to explicitly calculate the needed fuel minus the available fuel, just like in handleTransportRefueling() - const fuelEntry = starbaseCargoManifest.find(e => e.res === sageGameAcct.account.mints.fuel.toString()) || {amt: 0}; - const totalFuel = fuelData.fuelNeeded + fuelEntry.amt; - let fuelToAdd = Math.min(fuelData.capacity, totalFuel) - fuelData.amount; + //Loading at Starbase + if (hasTargetManifest) { + const loadedCargo = await handleTransportLoading(i, userFleets[i].starbaseCoord, targetCargoManifest); + cLog(4,`${FleetTimeStamp(userFleets[i].label)} loadedCargo: `, loadedCargo); + if(!loadedCargo && globalSettings.transportStopOnError) { + //const newFleetState = `ERROR: No more cargo to load`; + //cLog(1,`${FleetTimeStamp(userFleets[i].label)} ${newFleetState}`); + //userFleets[i].state = newFleetState; + cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Unexpected error on cargo load.`); + return; + } + } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loading skipped - No resources specified`); - cLog(3,`${FleetTimeStamp(userFleets[i].label)} Fuel needed`, fuelData.fuelNeeded, '/ fuel found', fuelData.amount, '/ fuel to add', fuelToAdd, '/ needToLoad', checkCargoResult.needToLoad, '/ needToUnload', checkCargoResult.needToUnload, '/ needToLoadCrew', needToLoadCrew, '/ needToUnloadCrew', needToUnloadCrew); + let undockResult = await execUndock(userFleets[i], userFleets[i].starbaseCoord); + cLog(4,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, undockResult); + let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); + } + userFleets[i].moveTarget = userFleets[i].destCoord; + userFleets[i].resupplying = false; + cLog(3,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, userFleets[i]); + } - if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelToAdd > 0 || needToLoadCrew > 0 || needToUnloadCrew > 0) { - await execDock(userFleets[i], userFleets[i].destCoord); + // Fleet at target? + else if (fleetCoords[0] == destX && fleetCoords[1] == destY) { + userFleets[i].resupplying = true; - //Unloading at Target - let fuelUnloadDeficit = 0; //How far short of the manifest was the amount of fuel unloaded? - if (hasTargetManifest || checkCargoResult.needToUnload) { - const unloadResult = await handleTransportUnloading(userFleets[i], userFleets[i].destCoord, targetCargoManifest); - fuelUnloadDeficit = unloadResult.fuelUnloadDeficit; - } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Unloading skipped - No resources specified`); + let checkCargoResult = await checkCargo(targetCargoManifest, starbaseCargoManifest, userFleets[i]); + targetCargoManifest = checkCargoResult.currentManifest; + starbaseCargoManifest = checkCargoResult.destinationManifest; - if(needToUnloadCrew) { - await handleCrewUnloading(userFleets[i], userFleets[i].destCoord, needToUnloadCrew); - } - if(needToLoadCrew) { - let crewResp = await handleCrewLoading(userFleets[i], userFleets[i].destCoord, needToLoadCrew); - if (crewResp && crewResp.name == 'NotEnoughCrew') { - if(globalSettings.transportStopOnError) { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Not enough crew`); - updateFleetState(userFleets[i], 'ERROR: Not enough crew'); - return; - } else { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Not enough crew`); + let needToUnloadCrew = 0; + if((targetCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && (userFleets[i].crewCount - userFleets[i].requiredCrew > 0)) { + needToUnloadCrew = userFleets[i].crewCount - userFleets[i].requiredCrew; } - } - } + let needToLoadCrew = 0; + if((starbaseCargoManifest[0].crew > 0) && (userFleets[i].passengerCapacity > 0) && ((userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount - needToUnloadCrew) > 0)) { + needToLoadCrew = Math.min(userFleets[i].requiredCrew + userFleets[i].passengerCapacity - userFleets[i].crewCount, starbaseCargoManifest[0].crew); + } + if(starbaseCargoManifest[0].crew > 0 || targetCargoManifest[0].crew > 0) cLog(3, `${FleetTimeStamp(userFleets[i].label)} crew:`, userFleets[i].crewCount, 'passengerCapacity:', userFleets[i].passengerCapacity, 'required crew:', userFleets[i].requiredCrew, 'load:', needToLoadCrew, 'unload:', needToUnloadCrew); - //Refueling at Target - let refuelResp = await handleTransportRefueling(userFleets[i], userFleets[i].destCoord, [destX, destY], [starbaseX, starbaseY], false, fuelUnloadDeficit, starbaseCargoManifest); - if (refuelResp.status === 0) { - userFleets[i].state = refuelResp.detail; - return; - } + const fuelData = await getFleetFuelData(userFleets[i], [destX, destY], [starbaseX, starbaseY], false); + //previously we only checked for "fuelData.fuelNeeded > 0" below, but fuelNeeded is always greater than 0 - it is just the fuel needed for the warp/subwarp. + //We need to explicitly calculate the needed fuel minus the available fuel, just like in handleTransportRefueling() + const fuelEntry = starbaseCargoManifest.find(e => e.res === sageGameAcct.account.mints.fuel.toString()) || {amt: 0}; + const totalFuel = fuelData.fuelNeeded + fuelEntry.amt; + let fuelToAdd = Math.min(fuelData.capacity, totalFuel) - fuelData.amount; - let fuelIndex = starbaseCargoManifest.findIndex(e => e.res === sageGameAcct.account.mints.fuel.toString()); - if (fuelIndex > -1) { - starbaseCargoManifest[fuelIndex].amt = starbaseCargoManifest[fuelIndex].amt - refuelResp.amount; - } + cLog(3,`${FleetTimeStamp(userFleets[i].label)} Fuel needed`, fuelData.fuelNeeded, '/ fuel found', fuelData.amount, '/ fuel to add', fuelToAdd, '/ needToLoad', checkCargoResult.needToLoad, '/ needToUnload', checkCargoResult.needToUnload, '/ needToLoadCrew', needToLoadCrew, '/ needToUnloadCrew', needToUnloadCrew); - //Loading at Target - if(hasStarbaseManifest) { - const loadedCargo = await handleTransportLoading(i, userFleets[i].destCoord, starbaseCargoManifest); - cLog(4,`${FleetTimeStamp(userFleets[i].label)} loadedCargo: `, loadedCargo); - if(!loadedCargo && globalSettings.transportStopOnError) { - //const newFleetState = `ERROR: No more cargo to load`; - //cLog(1,`${FleetTimeStamp(userFleets[i].label)} ${newFleetState}`); - //userFleets[i].state = newFleetState; - cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Unexpected error on cargo load.`); - return; - } - } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loading skipped - No resources specified`); + if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelToAdd > 0 || needToLoadCrew > 0 || needToUnloadCrew > 0) { + await execDock(userFleets[i], userFleets[i].destCoord); - let undockResult = await execUndock(userFleets[i], userFleets[i].destCoord); - cLog(4,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, undockResult); - let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); - } - userFleets[i].moveTarget = userFleets[i].starbaseCoord; - userFleets[i].resupplying = false; - cLog(3,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, userFleets[i]); - } + //Unloading at Target + let fuelUnloadDeficit = 0; //How far short of the manifest was the amount of fuel unloaded? + if (hasTargetManifest || checkCargoResult.needToUnload) { + const unloadResult = await handleTransportUnloading(userFleets[i], userFleets[i].destCoord, targetCargoManifest); + fuelUnloadDeficit = unloadResult.fuelUnloadDeficit; + } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Unloading skipped - No resources specified`); - if(userFleets[i].stopping) return; + if(needToUnloadCrew) { + await handleCrewUnloading(userFleets[i], userFleets[i].destCoord, needToUnloadCrew); + } + if(needToLoadCrew) { + let crewResp = await handleCrewLoading(userFleets[i], userFleets[i].destCoord, needToLoadCrew); + if (crewResp && crewResp.name == 'NotEnoughCrew') { + if(globalSettings.transportStopOnError) { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Not enough crew`); + updateFleetState(userFleets[i], 'ERROR: Not enough crew'); + return; + } else { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Not enough crew`); + } + } + } - if (userFleets[i].moveTarget !== '') { - const targetX = userFleets[i].moveTarget.split(',').length > 1 ? userFleets[i].moveTarget.split(',')[0].trim() : ''; - const targetY = userFleets[i].moveTarget.split(',').length > 1 ? userFleets[i].moveTarget.split(',')[1].trim() : ''; - const moveDist = calculateMovementDistance(fleetCoords, [targetX,targetY]); - await handleMovement(i, moveDist, targetX, targetY); - } else { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Fleet must start at Target or Starbase`); - updateFleetState(userFleets[i], 'ERROR: Fleet must start at Target or Starbase'); - } - } + //Refueling at Target + let refuelResp = await handleTransportRefueling(userFleets[i], userFleets[i].destCoord, [destX, destY], [starbaseX, starbaseY], false, fuelUnloadDeficit, starbaseCargoManifest); + if (refuelResp.status === 0) { + userFleets[i].state = refuelResp.detail; + return; + } + + let fuelIndex = starbaseCargoManifest.findIndex(e => e.res === sageGameAcct.account.mints.fuel.toString()); + if (fuelIndex > -1) { + starbaseCargoManifest[fuelIndex].amt = starbaseCargoManifest[fuelIndex].amt - refuelResp.amount; + } + + //Loading at Target + if(hasStarbaseManifest) { + const loadedCargo = await handleTransportLoading(i, userFleets[i].destCoord, starbaseCargoManifest); + cLog(4,`${FleetTimeStamp(userFleets[i].label)} loadedCargo: `, loadedCargo); + if(!loadedCargo && globalSettings.transportStopOnError) { + //const newFleetState = `ERROR: No more cargo to load`; + //cLog(1,`${FleetTimeStamp(userFleets[i].label)} ${newFleetState}`); + //userFleets[i].state = newFleetState; + cLog(1,`${FleetTimeStamp(userFleets[i].label)} ERROR: Unexpected error on cargo load.`); + return; + } + } else cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loading skipped - No resources specified`); + + let undockResult = await execUndock(userFleets[i], userFleets[i].destCoord); + cLog(4,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, undockResult); + let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); + } + userFleets[i].moveTarget = userFleets[i].starbaseCoord; + userFleets[i].resupplying = false; + cLog(3,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, userFleets[i]); + } + + if(userFleets[i].stopping) return; + + if (userFleets[i].moveTarget !== '') { + const targetX = userFleets[i].moveTarget.split(',').length > 1 ? userFleets[i].moveTarget.split(',')[0].trim() : ''; + const targetY = userFleets[i].moveTarget.split(',').length > 1 ? userFleets[i].moveTarget.split(',')[1].trim() : ''; + const moveDist = calculateMovementDistance(fleetCoords, [targetX,targetY]); + await handleMovement(i, moveDist, targetX, targetY); + } else { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Transporting - ERROR: Fleet must start at Target or Starbase`); + updateFleetState(userFleets[i], 'ERROR: Fleet must start at Target or Starbase'); + } + } } async function getFleetFuelData(fleet, currentPos, targetPos, roundTrip = true) { From 1fcea5a613fe5f6bd7380fa2cb99a8a990adc239 Mon Sep 17 00:00:00 2001 From: zihanoo Date: Wed, 30 Jul 2025 23:42:49 +0800 Subject: [PATCH 20/20] feat Automatically uninstall resources other than those set for transportation --- SLY_Assistant.user.js | 311 ++++++++++++++++++++++++------------------ 1 file changed, 181 insertions(+), 130 deletions(-) diff --git a/SLY_Assistant.user.js b/SLY_Assistant.user.js index e8367bb..9b5f77a 100644 --- a/SLY_Assistant.user.js +++ b/SLY_Assistant.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name SLY Assistant // @namespace https://github.com/ImGroovin/SLY-Assistant -// @version 0.7.0.35 +// @version 0.7.0.38 // @description Base http://tampermonkey.net/ // @author SLY w/ Contributions by niofox, SkyLove512, anthonyra, [AEP] Valkynen, Risingson, Swift42 // @match https://*.based.staratlas.com/ @@ -1519,7 +1519,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee updateFleetState(fleet, 'ERROR: Ix Error'); cLog(2,`${FleetTimeStamp(fleetName)} <${opName}> ERROR ❌ The instruction resulted in an error.`); let ixError = txResult && txResult.meta && txResult.meta.logMessages ? txResult.meta.logMessages : 'Unknown'; - console.log(FleetTimeStamp(fleetName), ' txResult.logMessages: ', ixError); + // console.log(FleetTimeStamp(fleetName), ' txResult.logMessages: ', ixError); logError('ix error: ' + ixError, fleetName); if(fleet.publicKey) { if(globalSettings.emailFleetIxErrors) await sendEMail(fleetName + ' ix error', ixError); @@ -2098,85 +2098,85 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee } async function execCargoFromFleetToStarbase(fleet, fleetCargoPod, tokenMint, dockCoords, amount, returnTx) { - return new Promise(async resolve => { - let starbaseX = dockCoords.split(',')[0].trim(); - let starbaseY = dockCoords.split(',')[1].trim(); - let starbase = await getStarbaseFromCoords(starbaseX, starbaseY); - let starbasePlayer = await getStarbasePlayer(userProfileAcct,starbase.publicKey); - let starbasePlayerCargoHolds = await cargoProgram.account.cargoPod.all([ - { - memcmp: { - offset: 41, - bytes: starbasePlayer.publicKey.toBase58(), - }, - }, - ]); - - let starbasePlayerCargoHold = starbasePlayerCargoHolds.find(item => item.account.openTokenAccounts > 0); - starbasePlayerCargoHold = starbasePlayerCargoHold ? starbasePlayerCargoHold.publicKey : starbasePlayerCargoHolds.length > 0 ? starbasePlayerCargoHolds[0].publicKey : await execCreateCargoPod(fleet, dockCoords); - - let [starbaseCargoToken] = await BrowserAnchor.anchor.web3.PublicKey.findProgramAddressSync( - [ - starbasePlayerCargoHold.toBuffer(), - tokenProgramPK.toBuffer(), - new solanaWeb3.PublicKey(tokenMint).toBuffer() - ], - programPK - ); - let [fleetResourceToken] = await BrowserAnchor.anchor.web3.PublicKey.findProgramAddressSync( - [ - fleetCargoPod.toBuffer(), - tokenProgramPK.toBuffer(), - new solanaWeb3.PublicKey(tokenMint).toBuffer() - ], - programPK - ); - let fleetCurrentPod = await solanaReadConnection.getParsedTokenAccountsByOwner(fleetCargoPod, {programId: tokenProgramPK}); - let currentResource = fleetCurrentPod.value.find(item => item.account.data.parsed.info.mint === tokenMint); - let fleetResourceAcct = currentResource ? currentResource.pubkey : fleetResourceToken; - let resourceCargoTypeAcct = cargoTypes.find(item => item.account.mint.toString() == tokenMint); - await getAccountInfo(fleet.label, 'Starbase cargo token', starbaseCargoToken) || await createPDA(starbaseCargoToken, starbasePlayerCargoHold, new solanaWeb3.PublicKey(tokenMint), fleet); - let tx = { instruction: await sageProgram.methods.withdrawCargoFromFleet({ amount: new BrowserAnchor.anchor.BN(amount), keyIndex: new BrowserAnchor.anchor.BN(userProfileKeyIdx) }).accountsStrict({ - gameAccountsFleetAndOwner: { - gameFleetAndOwner: { - fleetAndOwner: { - fleet: fleet.publicKey, - owningProfile: userProfileAcct, - owningProfileFaction: userProfileFactionAcct.publicKey, - key: userPublicKey - }, - gameId: sageGameAcct.publicKey - }, - gameState: sageGameAcct.account.gameState - }, - starbaseAndStarbasePlayer: { - starbase: starbase.publicKey, - starbasePlayer: starbasePlayer.publicKey - }, - cargoPodFrom: fleetCargoPod, // fleet.cargoHold, - cargoPodTo: starbasePlayerCargoHold, - cargoType: resourceCargoTypeAcct.publicKey, - cargoStatsDefinition: sageGameAcct.account.cargo.statsDefinition, - tokenFrom: fleetResourceAcct, - tokenTo: starbaseCargoToken, - tokenMint: tokenMint, - fundsTo: userPublicKey, - cargoProgram: cargoProgramPK, - tokenProgram: tokenProgAddy - }).remainingAccounts([{ - pubkey: starbase.publicKey, - isSigner: false, - isWritable: false - }]).instruction()} - //let txResult = await txSignAndSend(tx, fleet, 'UNLOAD', 100); - let txResult; - if(returnTx) { - txResult = tx; - } else { - txResult = await txSignAndSend(tx, fleet, 'UNLOAD', 100); - } - resolve(txResult); - }); + return new Promise(async resolve => { + let starbaseX = dockCoords.split(',')[0].trim(); + let starbaseY = dockCoords.split(',')[1].trim(); + let starbase = await getStarbaseFromCoords(starbaseX, starbaseY); + let starbasePlayer = await getStarbasePlayer(userProfileAcct,starbase.publicKey); + let starbasePlayerCargoHolds = await cargoProgram.account.cargoPod.all([ + { + memcmp: { + offset: 41, + bytes: starbasePlayer.publicKey.toBase58(), + }, + }, + ]); + + let starbasePlayerCargoHold = starbasePlayerCargoHolds.find(item => item.account.openTokenAccounts > 0); + starbasePlayerCargoHold = starbasePlayerCargoHold ? starbasePlayerCargoHold.publicKey : starbasePlayerCargoHolds.length > 0 ? starbasePlayerCargoHolds[0].publicKey : await execCreateCargoPod(fleet, dockCoords); + + let [starbaseCargoToken] = await BrowserAnchor.anchor.web3.PublicKey.findProgramAddressSync( + [ + starbasePlayerCargoHold.toBuffer(), + tokenProgramPK.toBuffer(), + new solanaWeb3.PublicKey(tokenMint).toBuffer() + ], + programPK + ); + let [fleetResourceToken] = await BrowserAnchor.anchor.web3.PublicKey.findProgramAddressSync( + [ + fleetCargoPod.toBuffer(), + tokenProgramPK.toBuffer(), + new solanaWeb3.PublicKey(tokenMint).toBuffer() + ], + programPK + ); + let fleetCurrentPod = await solanaReadConnection.getParsedTokenAccountsByOwner(fleetCargoPod, {programId: tokenProgramPK}); + let currentResource = fleetCurrentPod.value.find(item => item.account.data.parsed.info.mint === tokenMint); + let fleetResourceAcct = currentResource ? currentResource.pubkey : fleetResourceToken; + let resourceCargoTypeAcct = cargoTypes.find(item => item.account.mint.toString() == tokenMint); + await getAccountInfo(fleet.label, 'Starbase cargo token', starbaseCargoToken) || await createPDA(starbaseCargoToken, starbasePlayerCargoHold, new solanaWeb3.PublicKey(tokenMint), fleet); + let tx = { instruction: await sageProgram.methods.withdrawCargoFromFleet({ amount: new BrowserAnchor.anchor.BN(amount), keyIndex: new BrowserAnchor.anchor.BN(userProfileKeyIdx) }).accountsStrict({ + gameAccountsFleetAndOwner: { + gameFleetAndOwner: { + fleetAndOwner: { + fleet: fleet.publicKey, + owningProfile: userProfileAcct, + owningProfileFaction: userProfileFactionAcct.publicKey, + key: userPublicKey + }, + gameId: sageGameAcct.publicKey + }, + gameState: sageGameAcct.account.gameState + }, + starbaseAndStarbasePlayer: { + starbase: starbase.publicKey, + starbasePlayer: starbasePlayer.publicKey + }, + cargoPodFrom: fleetCargoPod, // fleet.cargoHold, + cargoPodTo: starbasePlayerCargoHold, + cargoType: resourceCargoTypeAcct.publicKey, + cargoStatsDefinition: sageGameAcct.account.cargo.statsDefinition, + tokenFrom: fleetResourceAcct, + tokenTo: starbaseCargoToken, + tokenMint: tokenMint, + fundsTo: userPublicKey, + cargoProgram: cargoProgramPK, + tokenProgram: tokenProgAddy + }).remainingAccounts([{ + pubkey: starbase.publicKey, + isSigner: false, + isWritable: false + }]).instruction()} + //let txResult = await txSignAndSend(tx, fleet, 'UNLOAD', 100); + let txResult; + if(returnTx) { + txResult = tx; + } else { + txResult = await txSignAndSend(tx, fleet, 'UNLOAD', 100); + } + resolve(txResult); + }); } async function createScannerPDAs(fleet) { @@ -4097,7 +4097,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee craftingCoords: craftingCoords, craftingId: craftingId } - console.log('craft: ', craft); + // console.log('craft: ', craft); await GM.setValue(craftPK, JSON.stringify(craft)); } @@ -4166,7 +4166,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee //Guard against clicking the wrong button if(importText.value.includes('sector_target')) { - console.log('switching to fleet targets import...'); + // console.log('switching to fleet targets import...'); await saveTargetsImport(); return; } @@ -4186,7 +4186,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee //Guard against clicking the wrong button if(!importText.value.includes('sector_target')) { - console.log('switching to full fleet import...'); + // console.log('switching to full fleet import...'); await saveConfigImport(); return; } @@ -4378,9 +4378,9 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee async function calcMiningFleet() { // EXPERIMENTAL - console.log('userFleets: ', userFleets); + // console.log('userFleets: ', userFleets); for (let userFleet of userFleets) { - console.log('-----', userFleet.label, '-----'); + // console.log('-----', userFleet.label, '-----'); let fleetSavedData = await GM.getValue(userFleet.publicKey.toString(), '{}'); let fleetParsedData = JSON.parse(fleetSavedData); @@ -4393,10 +4393,10 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee // testing // --------------------------------- let starbase = await getStarbaseFromCoords(destX, destY); - console.log('starbase: ', starbase); + // console.log('starbase: ', starbase); let starbasePlayer = await getStarbasePlayer(userProfileAcct, starbase.publicKey); - console.log('starbasePlayer: ', starbasePlayer); + // console.log('starbasePlayer: ', starbasePlayer); let ships = []; let starbasePlayerAcctInfo = await solanaReadConnection.getAccountInfo(starbasePlayer.publicKey); @@ -4409,12 +4409,12 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee shipData = shipData.subarray(48); shipIter += 1; } - console.log('ships: ', ships); + // console.log('ships: ', ships); for (let ship of ships) { let shipDecoded = await sageProgram.account.ship.fetch(ship.publicKey); - console.log('shipDecoded: ', shipDecoded); + // console.log('shipDecoded: ', shipDecoded); let shipName = (new TextDecoder("utf-8").decode(new Uint8Array(shipDecoded.name))).replace(/\0/g, ''); - console.log(shipName); + // console.log(shipName); } // --------------------------------- let [mineItem] = await sageProgram.account.mineItem.all([ @@ -4454,7 +4454,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee systemRichness = sageResource.account.systemRichness; } else { let resShort = cargoItems.find(r => r.token == userFleet.mineResource).name; - console.log(`[${userFleet.label}] ERROR: ${resShort} not found at mining location`); + // console.log(`[${userFleet.label}] ERROR: ${resShort} not found at mining location`); //userFleet.state = `ERROR: ${resShort} not found at mining location`; //updateAssistStatus(userFleet); updateFleetState(userFleet, `ERROR: ${resShort} not found at mining location`); @@ -4544,27 +4544,27 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee async function assistProfileToggle(profiles) { return new Promise(async resolve => { - let targetElem = document.querySelector('#profileModal'); - if (targetElem.style.display === 'none' && profiles) { - targetElem.style.display = 'block'; - let contentElem = document.querySelector('#profileDiv'); - let transportOptStr = ''; - profiles.forEach( function(profile) {transportOptStr += '';}); - let profileSelect = document.createElement('select'); - profileSelect.size = profiles.length + 1; - profileSelect.style.padding = '2px 10px'; - profileSelect.innerHTML = transportOptStr; - contentElem.append(profileSelect); - profileSelect.onchange = function() { - cLog(2, 'assistProfileToggle: profileSelect.value', profileSelect.value); - let selected = profiles.find(o => o.profile === profileSelect.value); - assistProfileToggle(null); - resolve(selected); - } - } else { - targetElem.style.display = 'none'; - resolve(null); + let targetElem = document.querySelector('#profileModal'); + if (targetElem.style.display === 'none' && profiles) { + targetElem.style.display = 'block'; + let contentElem = document.querySelector('#profileDiv'); + let transportOptStr = ''; + profiles.forEach( function(profile) {transportOptStr += '';}); + let profileSelect = document.createElement('select'); + profileSelect.size = profiles.length + 1; + profileSelect.style.padding = '2px 10px'; + profileSelect.innerHTML = transportOptStr; + contentElem.append(profileSelect); + profileSelect.onchange = function() { + cLog(2, 'assistProfileToggle: profileSelect.value', profileSelect.value); + let selected = profiles.find(o => o.profile === profileSelect.value); + assistProfileToggle(null); + resolve(selected); } + } else { + targetElem.style.display = 'none'; + resolve(null); + } }); } @@ -5540,8 +5540,51 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee //let moveDist = calculateMovementDistance([starbaseX,starbaseY], [destX,destY]); if (fleetState === 'Idle') { + + async function unloadOtherRes() { + const transportLoadUnloadSingleTx = globalSettings.transportLoadUnloadSingleTx; //we read the setting once to prevent a race condition + const transactions = [] + let fleetCurrentCargo = await solanaReadConnection.getParsedTokenAccountsByOwner(userFleets[i].cargoHold, {programId: tokenProgramPK}); + //Unload all token except transport token (author: zihan) + // console.log('Transport fleetCurrentCargo', fleetCurrentCargo) + fleetCurrentCargo.value.forEach(async (item) => { + var itemInfo = item.account.data.parsed.info + if (itemInfo.tokenAmount.uiAmount <= globalSettings.minerKeep1 ? 1 : 0) { + return + } + // if find transport setting, return, or unload + for (let i = 0; i < targetCargoManifest.length; i ++) { + const entry = targetCargoManifest[i] + if (entry.amt > 0 && entry.res === itemInfo.mint) { + return + } + } + // console.log('Transport itemInfo ', itemInfo) + let resp = await execCargoFromFleetToStarbase( + userFleets[i], + userFleets[i].cargoHold, + itemInfo.mint, + userFleets[i].starbaseCoord, + itemInfo.tokenAmount.uiAmount - (globalSettings.minerKeep1 ? 1 : 0), + transportLoadUnloadSingleTx + ) + if (transportLoadUnloadSingleTx && resp) { + transactions.push(resp); + } + }) + + if (transactions.length > 0) { + //when "transportUnloadsUnknownRSS is enabled, it is possible that we need to unload more than 4 rss, so we need to split the instructions + await txSliceAndSend(transactions, fleet, 'UNLOAD', 100, 4); + } + } + // Fleet at starbase? if (fleetCoords[0] == starbaseX && fleetCoords[1] == starbaseY) { + + await unloadOtherRes(); + await wait(500); + userFleets[i].resupplying = true; let checkCargoResult = await checkCargo(starbaseCargoManifest, targetCargoManifest, userFleets[i]); @@ -5568,6 +5611,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee cLog(3,`${FleetTimeStamp(userFleets[i].label)} Fuel needed`, fuelData.fuelNeeded, '/ fuel found', fuelData.amount, '/ fuel to add', fuelToAdd, '/ needToLoad', checkCargoResult.needToLoad, '/ needToUnload', checkCargoResult.needToUnload, '/ needToLoadCrew', needToLoadCrew, '/ needToUnloadCrew', needToUnloadCrew); + //if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelData.fuelNeeded > 0 || needToLoadCrew || needToUnloadCrew) { if (checkCargoResult.needToLoad || checkCargoResult.needToUnload || fuelToAdd > 0 || needToLoadCrew > 0 || needToUnloadCrew > 0) { await execDock(userFleets[i], userFleets[i].starbaseCoord); @@ -5579,7 +5623,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee if(needToUnloadCrew) { await handleCrewUnloading(userFleets[i], userFleets[i].starbaseCoord, needToUnloadCrew); } - if(needToLoadCrew) { + if (needToLoadCrew) { let crewResp = await handleCrewLoading(userFleets[i], userFleets[i].starbaseCoord, needToLoadCrew); if (crewResp && crewResp.name == 'NotEnoughCrew') { if(globalSettings.transportStopOnError) { @@ -5619,7 +5663,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let undockResult = await execUndock(userFleets[i], userFleets[i].starbaseCoord); cLog(4,`${FleetTimeStamp(userFleets[i].label)} userFleets[i]: `, undockResult); - let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); + // let fleetState = await solanaReadConnection.getAccountInfoAndContext(userFleets[i].publicKey, {minContextSlot: undockResult.slot}); } userFleets[i].moveTarget = userFleets[i].destCoord; userFleets[i].resupplying = false; @@ -5628,6 +5672,10 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee // Fleet at target? else if (fleetCoords[0] == destX && fleetCoords[1] == destY) { + + await unloadOtherRes(); + await wait(500); + userFleets[i].resupplying = true; let checkCargoResult = await checkCargo(targetCargoManifest, starbaseCargoManifest, userFleets[i]); @@ -5931,6 +5979,7 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee cLog(2,`${FleetTimeStamp(userFleets[i].label)} Calculating cargoSpace ...`); const fleetCurrentCargo = await solanaReadConnection.getParsedTokenAccountsByOwner(userFleets[i].cargoHold, {programId: tokenProgramPK}); const cargoCnt = fleetCurrentCargo.value.reduce((n, {account}) => n + account.data.parsed.info.tokenAmount.uiAmount * cargoItems.find(r => r.token == account.data.parsed.info.mint).size, 0); + // console.log("cargoCnt ", cargoCnt, userFleets[i].cargoCapacity) let cargoSpace = userFleets[i].cargoCapacity - cargoCnt; const startingCargoSpace = cargoSpace; let expectedCnt = 0; @@ -5940,12 +5989,12 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let transactions = []; const transportLoadUnloadSingleTx = globalSettings.transportLoadUnloadSingleTx; //we read the setting once to prevent a race condition for (const entry of transportManifest) { - if (entry.res && entry.amt > 0) { - if(cargoSpace < 1) { - cLog(1,`${FleetTimeStamp(userFleets[i].label)} Cargo full - remaining loading process skipped`); - break; - } + if (cargoSpace < 1) { + cLog(1,`${FleetTimeStamp(userFleets[i].label)} Cargo full - remaining loading process skipped`); + break; + } + if (entry.res && entry.amt > 0) { const [fleetResourceToken] = await BrowserAnchor.anchor.web3.PublicKey.findProgramAddressSync( [ userFleets[i].cargoHold.toBuffer(), @@ -5958,12 +6007,14 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee const fleetResAcct = currentRes ? currentRes.pubkey : fleetResourceToken; const resCargoTypeAcct = cargoTypes.find(item => item.account.mint.toString() == entry.res); const currentResAmt = currentRes ? currentRes.account.data.parsed.info.tokenAmount.uiAmount : 0; + const targetItem = cargoItems.find(r => r.token == entry.res) //Deduct ammo already loaded into ammobank if applicable const isAmmo = entry.res === sageGameAcct.account.mints.ammo.toString(); //For ammo SLYA didn't check the ammo in the cargo room, added - const resMax = Math.floor(Math.min(cargoSpace / cargoItems.find(r => r.token == entry.res).size, isAmmo ? entry.amt - ammoLoadingIntoAmmoBank - currentResAmt : entry.amt - currentResAmt)); + const resMax = Math.floor(Math.min(cargoSpace / targetItem.size, isAmmo ? entry.amt - ammoLoadingIntoAmmoBank - currentResAmt : entry.amt - currentResAmt)); expectedCnt += resMax; + if (resMax > 0) { cLog(1,`${FleetTimeStamp(userFleets[i].label)} Attempting to load ${resMax} ${entry.res} from ${starbaseCoords}`); const resp = await execCargoFromStarbaseToFleet( @@ -5977,10 +6028,10 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee transportLoadUnloadSingleTx ); cLog(1,`${FleetTimeStamp(userFleets[i].label)} Loaded ${resp.amount} ${entry.res}: `, resp); - cargoSpace -= resp && resp.amount ? cargoItems.find(r => r.token == entry.res).size * resp.amount : 0; + cargoSpace -= resp && resp.amount ? targetItem.size * resp.amount : 0; if (resp && resp.name == 'NotEnoughResource') { - const resShort = cargoItems.find(r => r.token == entry.res).name; + const resShort = targetItem.name; cLog(1,`${FleetTimeStamp(userFleets[i].label)} Not enough ${resShort}`); notEnoughInfo += 'Not enough ' + resShort + '\n'; } @@ -5997,11 +6048,11 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee //cLog(3,`${FleetTimeStamp(userFleets[i].label)} Loading finished with ${cargoCnt} total cargo loaded`); - if (startingCargoSpace == cargoSpace && expectedCnt > 0) { - updateFleetState(userFleets[i], 'ERROR: No cargo loaded'); - cLog(2,`${FleetTimeStamp(userFleets[i].label)} ERROR: No cargo loaded`); - if(globalSettings.emailNoCargoLoaded) await sendEMail(userFleets[i].label + ' no cargo loaded', notEnoughInfo); - } + if (startingCargoSpace == cargoSpace && expectedCnt > 0) { + updateFleetState(userFleets[i], 'ERROR: No cargo loaded'); + cLog(2,`${FleetTimeStamp(userFleets[i].label)} ERROR: No cargo loaded`); + if(globalSettings.emailNoCargoLoaded) await sendEMail(userFleets[i].label + ' no cargo loaded', notEnoughInfo); + } else if(transactions.length > 0) { await txSliceAndSend(transactions, userFleets[i], 'LOAD', 100, 4); } @@ -6236,11 +6287,11 @@ async function sendAndConfirmTx(txSerialized, lastValidBlockHeight, txHash, flee let limitingIngredient = starbasePlayerIngredientCargoHolds.reduce((prev, curr) => prev && prev.amountCraftable < curr.amountCraftable ? prev : curr); - console.log('DEBUG limitingIngredient: ', limitingIngredient); - console.log('DEBUG targetAmount: ', targetAmount); + // console.log('DEBUG limitingIngredient: ', limitingIngredient); + // console.log('DEBUG targetAmount: ', targetAmount); if (limitingIngredient.amountCraftable < targetAmount) { for (let ingredient of starbasePlayerIngredientCargoHolds) { - console.log('DEBUG ingredient: ', ingredient); + // console.log('DEBUG ingredient: ', ingredient); if (ingredient.craftAmount > 0) { let filterData = ['SDU']; if(special.includes('f2')) filterData.push('Framework','Framework 3');