// ==UserScript== // @name Advanced Command Scheduler // @version 1.0.4 // @description Schedule attacks and supports, optimized for maximum precision. Uses browser serviceWorkers. // @author joaovperin // @icon https://i.imgur.com/7WgHTT8.gif // @include https://**.tribalwars.*/game.php?**&screen=place*&try=confirm* // @downloadURL https://raw.githubusercontent.com/joaovperin/TribalWars/master/UserScripts/AdvancedCommandScheduler.user.js // @updateURL https://raw.githubusercontent.com/joaovperin/TribalWars/master/UserScripts/AdvancedCommandScheduler.user.js // ==/UserScript== (async (ModuleLoader) => { 'use strict'; //****************************** Configuration ******************************// const defaultInternetDelay = 30; const worldBackwardDelay = 50; const loopStartTime = 1500; //*************************** End Configuration ***************************// // Dependency loading await ModuleLoader.loadModule('utils/notify-utils'); // Controls the window title TwFramework.setIdleTitlePreffix('SENDING_COMMAND', document.title); const CommandSender = { confirmButton: null, duration: null, dateNow: null, internetDelay: null, init: function () { // Create some Html $($('#command-data-form').find('tbody')[0]).append( ` Chegada: Delay da internet: ` ); this.confirmButton = $('#troop_confirm_submit'); this.duration = $('#command-data-form').find('td:contains("Duração:")').next().text().split(':').map(Number); this.internetDelay = localStorage.getItem('ACS.internetDelay') || defaultInternetDelay; this.dateNow = this.convertToInput((() => { var d = new Date(); d.setSeconds(d.getSeconds() + 10); d.setMilliseconds(501); return d; })()); $('#ACSInternetDelay').val(this.internetDelay); $('#ACStime').val(this.dateNow); $('#ACSbutton').click(function () { const attackTime = CommandSender.getAttackTime(); CommandSender.internetDelay = parseInt($('#ACSInternetDelay').val()); localStorage.setItem('ACS.internetDelay', CommandSender.internetDelay); CommandSender.confirmButton.addClass('btn-disabled'); // Exec asynchronous setTimeout(function () { console.log('Starting loop at = ', new Date().toISOString()); ((day, hour, minute, second, millisecond) => { console.log('ACS.param.second = ', second); console.log('ACS.param.millisecond = ', millisecond); var _interval = 0; console.log('ACS.internetDelay = ', CommandSender.internetDelay); console.log('ACS.offsetFromServer = ', Timing.offset_from_server); var _nextFn = () => { const realOffset = parseInt(CommandSender.internetDelay) - worldBackwardDelay; console.log('ACS.realOffset = ', realOffset); if (CommandSender.createServerDate(realOffset).getSeconds() >= second) { console.log('ACS.second = ', second, '. Waiting for command...'); // Calculate the real Offset _nextFn = () => { const realDate = CommandSender.createServerDate(realOffset); if (realDate.getMilliseconds() >= millisecond) { // To avoid multiple threads if (CommandSender.sent === true) { return true; } CommandSender.sent = true; CommandSender.confirmButton.click(); console.log('Command SENT at ', realDate.toISOString(), '.'); window.clearInterval(_interval); return true; } return false; }; } return false; }; // RUN, Barry, Run! (() => { console.log('LOOP STARING AT = ', new Date(Timing.getCurrentServerTime()).toISOString()); const blob = new Blob([` setInterval(() => postMessage('')); `]); const worker = new Worker(window.URL.createObjectURL(blob)); let _is_Done = false; worker.onmessage = function () { if (_is_Done) { UI.Notification.show("https://dsbr.innogamescdn.com/asset/c092731a/graphic/unit/recruit/axe.png", 'Parabéns!', 'Seu comando foi enviado com sucesso!'); return worker.terminate(); } _is_Done = _nextFn(); } })(); })( /* Day, Hour, Minute, Second, ms */ attackTime.getDay(), attackTime.getHours(), attackTime.getMinutes(), attackTime.getSeconds(), attackTime.getMilliseconds() ); // Delay to start the loop }, (attackTime - Timing.getCurrentServerTime()) - loopStartTime); this.disabled = true; }); }, getAttackTime: function () { var d = new Date($('#ACStime').val().replace('T', ' ')); d.setHours(d.getHours() - this.duration[0]); d.setMinutes(d.getMinutes() - this.duration[1]); d.setSeconds(d.getSeconds() - this.duration[2]); return d; }, createServerDate: function (delay) { return new Date(Timing.getCurrentServerTime() + (delay || 0)); }, convertToInput: function (t) { t.setHours(t.getHours() + this.duration[0]); t.setMinutes(t.getMinutes() + this.duration[1]); t.setSeconds(t.getSeconds() + this.duration[2]); const a = { y: t.getFullYear(), m: t.getMonth() + 1, d: t.getDate(), time: t.toTimeString().split(' ')[0], ms: t.getMilliseconds() }; if (a.m < 10) { a.m = '0' + a.m; } if (a.d < 10) { a.d = '0' + a.d; } if (a.ms < 100) { a.ms = '0' + a.ms; if (a.ms < 10) { a.ms = '0' + a.ms; } } return a.y + '-' + a.m + '-' + a.d + 'T' + a.time + '.' + a.ms; }, addGlobalStyle: function (css) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); } }; CommandSender.addGlobalStyle('#ACStime, #ACSInternetDelay {font-size: 9pt;font-family: Verdana,Arial;}#ACSbutton {float:right;}'); // Start in a loop for faster loading const _temporaryLoop = setInterval(function () { if (document.getElementById('command-data-form') && jQuery) { CommandSender.init(); clearInterval(_temporaryLoop); } }, 1); })({ // ModuleLoader functions loadModule: moduleName => { return new Promise((resolve, reject) => { const modulePath = moduleName.replace('.', '/'); const moduleUrl = `https://raw.githubusercontent.com/joaovperin/TribalWars/master/Modules/${modulePath}.js`; console.debug('[TwScripts] Loading ', modulePath, ' from URL ', moduleUrl, '...'); return $.ajax({ method: "GET", url: moduleUrl, dataType: "text" }).done(res => resolve(eval(res))) .fail(req => reject(console.error("[TwScripts] Fail loading module '", moduleName, "'."))); }) } });