Last active
January 6, 2022 07:24
-
-
Save earthiverse/1bb14ef2071f8fe92f63249c4d6649d9 to your computer and use it in GitHub Desktop.
pattack tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-unused-vars */ | |
/* eslint-disable no-undef */ | |
const MPOT0_RECOVERY = G.items.mpot0.gives[0][1] | |
const MPOT1_RECOVERY = G.items.mpot1.gives[0][1] | |
const HPOT0_RECOVERY = G.items.hpot0.gives[0][1] | |
const HPOT1_RECOVERY = G.items.hpot1.gives[0][1] | |
function ms_to_next_skill(skill) { | |
const next_skill = parent.next_skill[skill] | |
if (next_skill == undefined) return 0 | |
const ms = parent.next_skill[skill].getTime() - Date.now() | |
return ms < 0 ? 0 : ms | |
} | |
async function moveLoop() { | |
try { | |
let nearest = get_nearest_monster() | |
if (!is_in_range(nearest)) { | |
// Move closer | |
move( | |
character.x + (nearest.x - character.x) / 2, | |
character.y + (nearest.y - character.y) / 2 | |
) | |
} | |
} catch (e) { | |
console.error(e) | |
} | |
setTimeout(async () => { moveLoop() }, 250) | |
} | |
moveLoop() | |
async function lootLoop() { | |
try { | |
// The built in loot() does pretty much all of the work for us! | |
loot() | |
} catch (e) { | |
console.error(e) | |
} | |
setTimeout(async () => { lootLoop() }, 250) | |
} | |
lootLoop() | |
async function regenLoop() { | |
try { | |
const hpRatio = character.hp / character.max_hp | |
const hpMissing = character.max_hp - character.hp | |
const mpRatio = character.mp / character.max_mp | |
const mpMissing = character.max_mp - character.mp | |
const minPing = Math.min(...parent.pings) | |
if (character.rip) { | |
// Don't heal if we're dead | |
setTimeout(async () => { regenLoop() }, Math.max(100, ms_to_next_skill("use_hp"))) | |
return | |
} | |
if (mpRatio < hpRatio) { | |
// We want to heal MP | |
const mpot0 = locate_item("mpot0") | |
const mpot1 = locate_item("mpot1") | |
if (mpot1 !== -1 && mpMissing >= MPOT1_RECOVERY) { | |
equip(mpot1) | |
// Equip doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} else if (mpot0 !== -1 && mpMissing >= MPOT0_RECOVERY) { | |
equip(mpot0) | |
// Equip doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} else { | |
use_skill("regen_mp") | |
// Use Skill doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} | |
} else if (character.hp !== character.max_hp) { | |
// We want to heal HP | |
const hpot0 = locate_item("hpot0") | |
const hpot1 = locate_item("hpot1") | |
if (hpot1 !== -1 && hpMissing >= HPOT1_RECOVERY) { | |
equip(hpot1) | |
// Equip doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} else if (hpot0 !== -1 && hpMissing >= HPOT0_RECOVERY) { | |
equip(hpot0) | |
// Equip doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} else { | |
use_skill("regen_hp") | |
// Use Skill doesn't return a promise yet. When it does, remove the setTimeout to just the function inside of it | |
setTimeout(() => { reduce_cooldown("use_hp", minPing) }, 2 * minPing) | |
} | |
} | |
} catch (e) { | |
console.error(e) | |
} | |
setTimeout(async () => { regenLoop() }, Math.max(500, ms_to_next_skill("use_hp"))) | |
} | |
regenLoop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-undef */ | |
load_code("base") | |
load_code("pattack10") | |
const TenMinutesInMs = 10 * 60 * 1000 | |
let started | |
let numKilled = 0 | |
let numCalls = 0 | |
character.on("target_hit", (data) => { if (data.kill) numKilled += 1 }) | |
async function attackLoop() { | |
/** NOTE: We're now using a try/catch so setTimeout will still be called if our code fails for whatever reason */ | |
try { | |
numCalls += 1 | |
if (started == undefined) started = Date.now() | |
if (Date.now() > started + TenMinutesInMs) { | |
show_json({ | |
script: "pattack10", | |
numKilled: numKilled, | |
numCalls: numCalls, | |
pings: parent.pings, | |
level: character.level, | |
server: server | |
}) | |
started = Date.now() | |
numKilled = 0 | |
numCalls = 0 | |
} | |
const nearest = get_nearest_monster() | |
if (!nearest) { | |
set_message("No Monsters") | |
return | |
} | |
set_message("Attacking") | |
/** NOTE: We're now awaiting the attack */ | |
newAttack(nearest) | |
} catch (e) { | |
console.error(e) | |
} | |
// NOTE: We are now using setTimeout instead of setInterval, so our next attack will dynamically adjust when it runs | |
// NOTE: ms_to_next_skill is from base.js | |
setTimeout(async () => { attackLoop() }, 50) | |
} | |
attackLoop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"script": "beg_pattack", | |
"numKilled": 643, | |
"numCalls": 11542, | |
"pings": [ | |
343, | |
292, | |
290, | |
340, | |
289, | |
293, | |
284, | |
287, | |
333, | |
415, | |
283, | |
298, | |
317, | |
454, | |
285, | |
295, | |
564, | |
296, | |
293, | |
302, | |
449, | |
294, | |
284, | |
290, | |
292, | |
315, | |
289, | |
285, | |
286, | |
284, | |
285, | |
286, | |
300, | |
287, | |
286, | |
618, | |
290, | |
285, | |
415, | |
300 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} | |
{ | |
"script": "beg_pattack", | |
"numKilled": 640, | |
"numCalls": 11404, | |
"pings": [ | |
291, | |
305, | |
286, | |
332, | |
290, | |
293, | |
290, | |
301, | |
382, | |
302, | |
388, | |
388, | |
468, | |
499, | |
466, | |
474, | |
542, | |
316, | |
288, | |
284, | |
304, | |
283, | |
292, | |
378, | |
293, | |
293, | |
290, | |
296, | |
285, | |
292, | |
299, | |
287, | |
284, | |
471, | |
584, | |
371, | |
456, | |
401, | |
292, | |
355 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-undef */ | |
load_code("base") | |
| |
const TenMinutesInMs = 10 * 60 * 1000 | |
let started | |
let numKilled = 0 | |
let numCalls = 0 | |
character.on("target_hit", (data) => { if (data.kill) numKilled += 1 }) | |
| |
async function attackLoop() { | |
/** NOTE: We're now using a try/catch so setTimeout will still be called if our code fails for whatever reason */ | |
try { | |
numCalls += 1 | |
if (started == undefined) started = Date.now() | |
if (Date.now() > started + TenMinutesInMs) { | |
show_json({ | |
script: "next_skill", | |
numKilled: numKilled, | |
numCalls: numCalls, | |
pings: parent.pings, | |
level: character.level, | |
server: server | |
}) | |
started = Date.now() | |
numKilled = 0 | |
numCalls = 0 | |
} | |
| |
const nearest = get_nearest_monster() | |
if (!nearest) { | |
set_message("No Monsters") | |
return | |
} | |
| |
if (can_attack(nearest)) { | |
set_message("Attacking") | |
/** NOTE: We're now awaiting the attack */ | |
await attack(nearest) | |
} | |
} catch (e) { | |
console.error(e) | |
} | |
// NOTE: We are now using setTimeout instead of setInterval, so our next attack will dynamically adjust when it runs | |
// NOTE: ms_to_next_skill is from base.js | |
setTimeout(async () => { attackLoop() }, Math.max(1, ms_to_next_skill("attack"))) | |
} | |
attackLoop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"script": "next_skill", | |
"numKilled": 650, | |
"numCalls": 651, | |
"pings": [ | |
291, | |
284, | |
287, | |
284, | |
285, | |
285, | |
285, | |
284, | |
298, | |
291, | |
293, | |
283, | |
290, | |
289, | |
286, | |
293, | |
300, | |
286, | |
285, | |
285, | |
284, | |
285, | |
284, | |
284, | |
290, | |
291, | |
288, | |
289, | |
286, | |
406, | |
283, | |
284, | |
284, | |
284, | |
296, | |
285, | |
290, | |
290, | |
292, | |
283 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//settings | |
const DEBUGLOG=true; | |
const reset=false | |
const safeCoefficient = 2 // recommended value: 1-2.5 - should be higher for low std, and lower for high std. low std= <15, high std >15 | |
const limits = {attack:10} //recommended value: 5-10 - Sends Y attacks within a interval. Should be safe up to 15, but should revise if you have a high attack speed. | |
const samples = 50 // recommended value: 50-100 - the higher the value, the more rigid to lag spikes. Should be safe with both 15-500. | |
game_log("pattack loaded") | |
const timingsForAttacks = {}; | |
const savedNeedle = get('pattackNeedle' + character.id); | |
var needle = savedNeedle || 0 | |
const savedSample = get('pattack' + character.id) | |
var samplesTimes = savedSample | |
if (samplesTimes) { | |
for(var i=0; i<samplesTimes.length;i++){ | |
if (typeof samplesTimes[i] !== 'number') { | |
samplesTimes=undefined; | |
/*cleanup if savedSample is corrupt*/ | |
break; | |
} | |
} | |
} | |
if (reset || !samplesTimes) { | |
samplesTimes = new Array(samples) //the lower this number, the more responsive | |
const spans = [-1*60, -1*30] | |
const interval = spans[1] - spans[0] | |
for(let i = 0; i < 100; i++) { | |
samplesTimes[i] = Math.floor(Math.random() * interval) + spans[0] | |
} | |
} | |
//attack = newAttack | |
const targets = {}; //enable target switching to last second | |
function newAttack(target) { | |
return _use("attack",target) | |
} | |
function newUse_skill(skill,target,extra_args) { | |
return _use(skill,target,extra_args) | |
} | |
function getCD(skill) { | |
if (!G.skills[skill]) return parent.next_skill[skill] | |
const { share } = G.skills[skill] | |
if (share) { | |
return parent.next_skill[share] | |
} else { | |
return parent.next_skill[skill] | |
} | |
} | |
function getCDName(skill) { | |
return G.skills[skill].share || skill | |
} | |
function _use(skill,target,extra_args) { | |
/*enable target switching to last second*/targets[skill]=target; | |
if (!parent.next_skill) { | |
return Promise.reject("Something is strange - Wait for parent.next_skill to init") | |
} | |
const cooldownTime = getCD(skill) | |
if (!cooldownTime) { | |
oldUse_skill(skill,target,extra_args); return Promise.reject("No timer on this spell?") | |
} | |
if (!!cooldownTime && | |
timingsForAttacks[getCDName(skill)] === cooldownTime && | |
mssince(cooldownTime) < 0) | |
return Promise.reject("cooldown: "+skill+ " "+mssince(cooldownTime)) //if we already timed on the attack time | |
if (mssince(cooldownTime) < -700) { | |
return Promise.reject("cooldown: "+skill+ " "+mssince(cooldownTime)) | |
}//if more than 100ms left say it's on cooldown | |
timingsForAttacks[getCDName(skill)] = cooldownTime //lock function until attack changes, also remeber the timer which is what we compare with | |
return _pTiming(skill,target,extra_args) | |
} | |
!window.oldAttack && (window.oldAttack = attack) //save old attack | |
!window.oldUse_skill && (window.oldUse_skill = use_skill) //save old attack | |
function _pTiming(skill,target,extra_args) { | |
const nowTime = new Date().getTime() | |
const cooldownTime = getCD(skill).getTime() | |
const av = avg(samplesTimes) | |
const st = std(samplesTimes) | |
const min = av - st; | |
const max = av + st | |
const amin = Math.min(0, Math.max(-300, (min - (safeCoefficient*st)))) //make sure it's between good pings, -300 and 0, things get wierd when ping > attackspeed | |
const amax = Math.min(0, (max + (safeCoefficient*st))) | |
const spamTimeStart = cooldownTime + amin | |
const spamTimeEnd = cooldownTime + amax | |
const attemptLimit = limits[skill] || 5 | |
const targetMS = 2 | |
const interval = (st*2*safeCoefficient) | |
const attempts = Math.round(Math.min(interval/targetMS,attemptLimit)) | |
const spanPiece = interval / attempts | |
if (nowTime > cooldownTime) { | |
DEBUGLOG && console.log(`Instant skip queue - ${skill}: \tmin ${Math.floor(min)} \tmax ${Math.floor(max)} \tav${Math.floor(av)} \tstd${Math.floor(st)}`) | |
return _use_skill(skill,targets[skill],extra_args) | |
} | |
var results = new Array(attempts) | |
return new Promise((resolve,reject) => { | |
for (let i = 0; i < results.length; i++) { | |
const inc = i * spanPiece | |
const timing = (spamTimeStart + inc) | |
const value = (cooldownTime-timing) * -1 | |
const timeout = timing-nowTime | |
const cb = async () => { | |
try { | |
results[i] = await _use_skill(skill,targets[skill],extra_args) | |
resolve(); | |
DEBUGLOG && console.log(`Success ${skill}: \tattempt ${i} out of ${results.length} sent. Maximum allowed attempts: ${limits[skill]} \tvalue ${Math.floor(value)} \t(ADJUSTED FROM ${Math.floor(timeout)}) \t${Math.floor(inc)} MS:${spanPiece} \tDiff ${Math.floor(max - min)} \tmin ${Math.floor(min)} \tmax ${Math.floor(max)} \tav${Math.floor(av)} \tstd${Math.floor(st)}`) | |
record(value) | |
results[i] = true | |
} catch (e) { | |
results[i] = false | |
if (i === attempts - 1) { //if last attempt | |
if (results.findIndex(v => !!v) === -1) {//and no attempt succeeded | |
if (e.reason === 'cooldown') { | |
reject(); | |
record(value) | |
} | |
timingsForAttacks[skill] = new Date(0); | |
} | |
} | |
} | |
} | |
setTimeout(cb,timeout) | |
results[i]=cb | |
} | |
}) | |
} | |
function _use_skill(skill,target,extra_args) { | |
if (skill === "attack") | |
return oldAttack(target); | |
return oldUse_skill(skill,target,extra_args) | |
} | |
function record(v) { | |
samplesTimes[needle++ % samplesTimes.length] = v | |
if (needle % 10 === 0) { | |
set('pattack' + character.id, samplesTimes) | |
set('pattackNeedle' + character.id, needle) | |
} | |
} | |
function std(array) { | |
return Math.sqrt(avg(array.map(value => (value - avg(array)) ** 2))) | |
} | |
function avg(array) { | |
return array.reduce((sum, value) => sum + value) / array.length | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-undef */ | |
load_code("base") | |
const TenMinutesInMs = 10 * 60 * 1000 | |
let started | |
let numKilled = 0 | |
let numCalls = 0 | |
character.on("target_hit", (data) => { if (data.kill) numKilled += 1 }) | |
async function attackLoop() { | |
try { | |
numCalls += 1 | |
if (started == undefined) started = Date.now() | |
if (Date.now() > started + TenMinutesInMs) { | |
show_json({ | |
script: "reduce_cooldown", | |
numKilled: numKilled, | |
numCalls: numCalls, | |
pings: parent.pings, | |
level: character.level, | |
server: server | |
}) | |
started = Date.now() | |
numKilled = 0 | |
numCalls = 0 | |
} | |
const nearest = get_nearest_monster() | |
if (!nearest) { | |
set_message("No Monsters") | |
} else if (can_attack(nearest)) { | |
set_message("Attacking") | |
await attack(nearest) | |
/** NOTE: We're now reducing the cooldown based on the ping */ | |
reduce_cooldown("attack", Math.min(...parent.pings)) | |
} | |
} catch (e) { | |
console.error(e) | |
} | |
setTimeout(async () => { attackLoop() }, Math.max(1, ms_to_next_skill("attack"))) | |
} | |
attackLoop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"script": "reduce_cooldown", | |
"numKilled": 978, | |
"numCalls": 983, | |
"pings": [ | |
289, | |
289, | |
391, | |
290, | |
289, | |
307, | |
290, | |
291, | |
289, | |
289, | |
288, | |
290, | |
290, | |
282, | |
288, | |
292, | |
285, | |
301, | |
286, | |
285, | |
288, | |
284, | |
283, | |
285, | |
296, | |
285, | |
289, | |
289, | |
297, | |
288, | |
290, | |
292, | |
289, | |
293, | |
289, | |
288, | |
290, | |
290, | |
298, | |
292 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} | |
{ | |
"script": "reduce_cooldown", | |
"numKilled": 977, | |
"numCalls": 982, | |
"pings": [ | |
296, | |
314, | |
285, | |
286, | |
288, | |
286, | |
285, | |
285, | |
285, | |
290, | |
291, | |
292, | |
305, | |
285, | |
315, | |
287, | |
290, | |
372, | |
288, | |
289, | |
286, | |
289, | |
291, | |
302, | |
288, | |
313, | |
290, | |
288, | |
286, | |
301, | |
312, | |
286, | |
293, | |
286, | |
285, | |
292, | |
292, | |
291, | |
294, | |
290 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} | |
{ | |
"script": "reduce_cooldown", | |
"numKilled": 971, | |
"numCalls": 988, | |
"pings": [ | |
309, | |
291, | |
292, | |
659, | |
292, | |
285, | |
291, | |
298, | |
284, | |
300, | |
299, | |
310, | |
307, | |
317, | |
294, | |
289, | |
288, | |
284, | |
301, | |
287, | |
286, | |
287, | |
320, | |
292, | |
290, | |
287, | |
779, | |
289, | |
298, | |
285, | |
295, | |
286, | |
284, | |
291, | |
317, | |
294, | |
293, | |
300, | |
283, | |
332 | |
], | |
"level": 76, | |
"server": { | |
"mode": "normal", | |
"pvp": false, | |
"region": "EU", | |
"id": "II" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment