2019-05-05 06:03:40 +02:00
import { Script } from "./Script" ;
2019-05-12 04:20:20 +02:00
import { RamCalculationErrorCode } from "./RamCalculationErrorCodes" ;
2019-05-05 06:03:40 +02:00
import { calculateRamUsage } from "./RamCalculations" ;
import { isScriptFilename } from "./ScriptHelpersTS" ;
import { CONSTANTS } from "../Constants" ;
import { Engine } from "../engine" ;
import { parseFconfSettings } from "../Fconf/Fconf" ;
import { FconfSettings } from "../Fconf/FconfSettings" ;
import {
iTutorialSteps ,
iTutorialNextStep ,
ITutorial
} from "../InteractiveTutorial" ;
import { Player } from "../Player" ;
import { AceEditor } from "../ScriptEditor/Ace" ;
import { CodeMirrorEditor } from "../ScriptEditor/CodeMirror" ;
2021-04-20 03:26:51 +02:00
import { CursorPositions } from "../ScriptEditor/CursorPositions" ;
2019-05-05 06:03:40 +02:00
import { AllServers } from "../Server/AllServers" ;
import { processSingleServerGrowth } from "../Server/ServerHelpers" ;
import { Settings } from "../Settings/Settings" ;
import { EditorSetting } from "../Settings/SettingEnums" ;
import { isValidFilePath } from "../Terminal/DirectoryHelpers" ;
import { TextFile } from "../TextFile" ;
import { Page , routing } from "../ui/navigationTracking" ;
import { numeralWrapper } from "../ui/numeralFormat" ;
import { dialogBoxCreate } from "../../utils/DialogBox" ;
import {
Reviver ,
Generic _toJSON ,
Generic _fromJSON
} from "../../utils/JSONReviver" ;
import { compareArrays } from "../../utils/helpers/compareArrays" ;
import { createElement } from "../../utils/uiHelpers/createElement" ;
2018-05-06 00:13:35 +02:00
2018-01-27 07:52:39 +01:00
var scriptEditorRamCheck = null , scriptEditorRamText = null ;
2019-03-05 02:40:28 +01:00
export function scriptEditorInit ( ) {
2019-01-27 23:08:45 +01:00
// Wrapper container that holds all the buttons below the script editor
const wrapper = document . getElementById ( "script-editor-buttons-wrapper" ) ;
2018-01-27 07:52:39 +01:00
if ( wrapper == null ) {
2019-01-27 23:08:45 +01:00
console . error ( "Could not find 'script-editor-buttons-wrapper'" ) ;
return false ;
2018-01-27 07:52:39 +01:00
}
2018-06-14 08:26:54 +02:00
2019-01-27 23:08:45 +01:00
// Beautify button
const beautifyButton = createElement ( "button" , {
class : "std-button" ,
display : "inline-block" ,
innerText : "Beautify" ,
2018-01-27 07:52:39 +01:00
clickListener : ( ) => {
2019-01-27 23:08:45 +01:00
let editor = getCurrentEditor ( ) ;
if ( editor != null ) {
editor . beautifyScript ( ) ;
}
2018-01-27 07:52:39 +01:00
return false ;
}
} ) ;
2019-01-27 23:08:45 +01:00
// Text that displays RAM calculation
2018-01-27 07:52:39 +01:00
scriptEditorRamText = createElement ( "p" , {
display : "inline-block" , margin : "10px" , id : "script-editor-status-text"
} ) ;
2017-07-25 16:39:56 +02:00
2019-01-27 23:08:45 +01:00
// Label for checkbox (defined below)
const checkboxLabel = createElement ( "label" , {
2018-01-27 07:52:39 +01:00
for : "script-editor-ram-check" , margin : "4px" , marginTop : "8px" ,
innerText : "Dynamic RAM Usage Checker" , color : "white" ,
tooltip : "Enable/Disable the dynamic RAM Usage display. You may " +
"want to disable it for very long scripts because there may be " +
"performance issues"
2017-05-03 06:38:58 +02:00
} ) ;
2017-07-25 16:39:56 +02:00
2019-01-27 23:08:45 +01:00
// Checkbox for enabling/disabling dynamic RAM calculation
2018-01-27 07:52:39 +01:00
scriptEditorRamCheck = createElement ( "input" , {
type : "checkbox" , name : "script-editor-ram-check" , id : "script-editor-ram-check" ,
margin : "4px" , marginTop : "8px" ,
} ) ;
scriptEditorRamCheck . checked = true ;
2019-01-27 23:08:45 +01:00
// Link to Netscript documentation
const documentationButton = createElement ( "a" , {
class : "std-button" ,
display : "inline-block" ,
2018-02-24 23:55:06 +01:00
href : "https://bitburner.readthedocs.io/en/latest/index.html" ,
2019-01-27 23:08:45 +01:00
innerText : "Netscript Documentation" ,
target : "_blank" ,
2018-01-27 07:52:39 +01:00
} ) ;
2019-01-27 23:08:45 +01:00
// Save and Close button
const closeButton = createElement ( "button" , {
class : "std-button" ,
display : "inline-block" ,
innerText : "Save & Close (Ctrl/Cmd + b)" ,
clickListener : ( ) => {
saveAndCloseScriptEditor ( ) ;
return false ;
}
} ) ;
// Add all buttons to the UI
2018-06-14 08:26:54 +02:00
wrapper . appendChild ( beautifyButton ) ;
2018-01-27 07:52:39 +01:00
wrapper . appendChild ( closeButton ) ;
wrapper . appendChild ( scriptEditorRamText ) ;
wrapper . appendChild ( scriptEditorRamCheck ) ;
wrapper . appendChild ( checkboxLabel ) ;
wrapper . appendChild ( documentationButton ) ;
2019-01-27 23:08:45 +01:00
// Initialize editors
const initParams = {
saveAndCloseFn : saveAndCloseScriptEditor ,
quitFn : Engine . loadTerminalContent ,
}
AceEditor . init ( initParams ) ;
CodeMirrorEditor . init ( initParams ) ;
// Setup the selector for which Editor to use
const editorSelector = document . getElementById ( "script-editor-option-editor" ) ;
if ( editorSelector == null ) {
console . error ( ` Could not find DOM Element for editor selector (id=script-editor-option-editor) ` ) ;
return false ;
}
for ( let i = 0 ; i < editorSelector . options . length ; ++ i ) {
if ( editorSelector . options [ i ] . value === Settings . Editor ) {
editorSelector . selectedIndex = i ;
break ;
2018-03-03 22:05:33 +01:00
}
}
2019-01-27 23:08:45 +01:00
editorSelector . onchange = ( ) => {
const opt = editorSelector . value ;
switch ( opt ) {
2019-05-05 06:03:40 +02:00
case EditorSetting . Ace : {
2019-01-27 23:08:45 +01:00
const codeMirrorCode = CodeMirrorEditor . getCode ( ) ;
const codeMirrorFn = CodeMirrorEditor . getFilename ( ) ;
AceEditor . create ( ) ;
CodeMirrorEditor . setInvisible ( ) ;
AceEditor . openScript ( codeMirrorFn , codeMirrorCode ) ;
2018-03-03 22:05:33 +01:00
break ;
2019-05-05 06:03:40 +02:00
}
case EditorSetting . CodeMirror : {
2019-01-27 23:08:45 +01:00
const aceCode = AceEditor . getCode ( ) ;
const aceFn = AceEditor . getFilename ( ) ;
CodeMirrorEditor . create ( ) ;
AceEditor . setInvisible ( ) ;
CodeMirrorEditor . openScript ( aceFn , aceCode ) ;
break ;
2019-05-05 06:03:40 +02:00
}
2019-01-27 23:08:45 +01:00
default :
console . error ( ` Unrecognized Editor Setting: ${ opt } ` ) ;
return ;
2018-03-03 22:05:33 +01:00
}
2019-01-27 23:08:45 +01:00
Settings . Editor = opt ;
2018-02-15 05:26:43 +01:00
}
2019-01-27 23:08:45 +01:00
editorSelector . onchange ( ) ; // Trigger the onchange event handler
}
2017-10-04 03:50:13 +02:00
2019-01-27 23:08:45 +01:00
export function getCurrentEditor ( ) {
switch ( Settings . Editor ) {
case EditorSetting . Ace :
return AceEditor ;
case EditorSetting . CodeMirror :
return CodeMirrorEditor ;
default :
throw new Error ( ` Invalid Editor Setting: ${ Settings . Editor } ` ) ;
return null ;
2017-10-04 03:50:13 +02:00
}
2017-09-19 20:38:03 +02:00
}
2017-05-03 06:38:58 +02:00
2018-01-27 07:52:39 +01:00
//Updates RAM usage in script
2019-01-27 23:08:45 +01:00
export async function updateScriptEditorContent ( ) {
2018-03-12 20:39:04 +01:00
var filename = document . getElementById ( "script-editor-filename" ) . value ;
2018-05-06 00:13:35 +02:00
if ( scriptEditorRamCheck == null || ! scriptEditorRamCheck . checked || ! isScriptFilename ( filename ) ) {
2018-01-27 07:52:39 +01:00
scriptEditorRamText . innerText = "N/A" ;
return ;
}
2019-01-27 23:08:45 +01:00
let code ;
try {
code = getCurrentEditor ( ) . getCode ( ) ;
} catch ( e ) {
scriptEditorRamText . innerText = "RAM: ERROR" ;
return ;
}
2017-07-13 18:54:29 +02:00
var codeCopy = code . repeat ( 1 ) ;
2019-05-07 03:01:06 +02:00
var ramUsage = await calculateRamUsage ( codeCopy , Player . getCurrentServer ( ) . scripts ) ;
2019-05-12 04:20:20 +02:00
if ( ramUsage > 0 ) {
2021-03-31 06:45:21 +02:00
scriptEditorRamText . innerText = "RAM: " + numeralWrapper . formatRAM ( ramUsage ) ;
2018-03-03 22:05:33 +01:00
} else {
2019-05-12 04:20:20 +02:00
switch ( ramUsage ) {
case RamCalculationErrorCode . ImportError :
scriptEditorRamText . innerText = "RAM: Import Error" ;
break ;
case RamCalculationErrorCode . URLImportError :
scriptEditorRamText . innerText = "RAM: HTTP Import Error" ;
break ;
case RamCalculationErrorCode . SyntaxError :
default :
scriptEditorRamText . innerText = "RAM: Syntax Error" ;
break ;
}
2018-01-27 07:52:39 +01:00
}
2017-07-13 18:54:29 +02:00
}
2017-05-03 06:38:58 +02:00
//Define key commands in script editor (ctrl o to save + close, etc.)
2016-11-24 23:30:33 +01:00
$ ( document ) . keydown ( function ( e ) {
2018-05-06 22:27:47 +02:00
if ( Settings . DisableHotkeys === true ) { return ; }
2018-07-20 03:51:18 +02:00
if ( routing . isOn ( Page . ScriptEditor ) ) {
2017-05-06 08:24:01 +02:00
//Ctrl + b
2018-05-05 22:23:57 +02:00
if ( e . keyCode == 66 && ( e . ctrlKey || e . metaKey ) ) {
2017-05-30 00:37:38 +02:00
e . preventDefault ( ) ;
2017-05-03 06:38:58 +02:00
saveAndCloseScriptEditor ( ) ;
2016-11-24 23:30:33 +01:00
}
}
} ) ;
2017-05-03 06:38:58 +02:00
function saveAndCloseScriptEditor ( ) {
var filename = document . getElementById ( "script-editor-filename" ) . value ;
2019-01-27 23:08:45 +01:00
2021-04-20 03:26:51 +02:00
let code , cursor ;
2019-01-27 23:08:45 +01:00
try {
2019-01-30 07:02:27 +01:00
code = getCurrentEditor ( ) . getCode ( ) ;
2021-04-20 03:26:51 +02:00
cursor = getCurrentEditor ( ) . getCursor ( ) ;
CursorPositions . saveCursor ( filename , cursor ) ;
2019-01-27 23:08:45 +01:00
} catch ( e ) {
2021-04-20 03:26:51 +02:00
dialogBoxCreate ( "Something went wrong when trying to save (getCurrentEditor().getCode() or getCurrentEditor().getCursor()). Please report to game developer with details" ) ;
2019-01-27 23:08:45 +01:00
return ;
}
2018-08-29 21:06:21 +02:00
if ( ITutorial . isRunning && ITutorial . currStep === iTutorialSteps . TerminalTypeScript ) {
//Make sure filename + code properly follow tutorial
if ( filename !== "foodnstuff.script" ) {
2017-05-06 08:24:01 +02:00
dialogBoxCreate ( "Leave the script name as 'foodnstuff'!" ) ;
return ;
}
2017-05-16 05:06:25 +02:00
code = code . replace ( /\s/g , "" ) ;
if ( code . indexOf ( "while(true){hack('foodnstuff');}" ) == - 1 ) {
2017-05-06 08:24:01 +02:00
dialogBoxCreate ( "Please copy and paste the code from the tutorial!" ) ;
return ;
}
2018-08-29 21:06:21 +02:00
//Save the script
let s = Player . getCurrentServer ( ) ;
for ( var i = 0 ; i < s . scripts . length ; i ++ ) {
if ( filename == s . scripts [ i ] . filename ) {
2019-05-07 03:01:06 +02:00
s . scripts [ i ] . saveScript ( getCurrentEditor ( ) . getCode ( ) , Player . currentServer , Player . getCurrentServer ( ) . scripts ) ;
2018-08-29 21:06:21 +02:00
Engine . loadTerminalContent ( ) ;
return iTutorialNextStep ( ) ;
}
}
2019-05-07 03:01:06 +02:00
// If the current script does NOT exist, create a new one
2018-08-29 21:06:21 +02:00
let script = new Script ( ) ;
2019-05-07 03:01:06 +02:00
script . saveScript ( getCurrentEditor ( ) . getCode ( ) , Player . currentServer , Player . getCurrentServer ( ) . scripts ) ;
2018-08-29 21:06:21 +02:00
s . scripts . push ( script ) ;
return iTutorialNextStep ( ) ;
2017-05-06 08:24:01 +02:00
}
2017-07-25 16:39:56 +02:00
2017-05-03 06:38:58 +02:00
if ( filename == "" ) {
2017-06-02 19:18:53 +02:00
dialogBoxCreate ( "You must specify a filename!" ) ;
2017-05-03 06:38:58 +02:00
return ;
}
2017-07-25 16:39:56 +02:00
2019-04-10 08:07:12 +02:00
if ( filename !== ".fconf" && ! isValidFilePath ( filename ) ) {
2017-05-03 06:38:58 +02:00
dialogBoxCreate ( "Script filename can contain only alphanumerics, hyphens, and underscores" ) ;
return ;
}
2017-07-25 16:39:56 +02:00
2018-03-12 20:39:04 +01:00
var s = Player . getCurrentServer ( ) ;
if ( filename === ".fconf" ) {
try {
parseFconfSettings ( code ) ;
} catch ( e ) {
2018-09-21 21:47:33 +02:00
dialogBoxCreate ( ` Invalid .fconf file: ${ e } ` ) ;
2017-05-03 06:38:58 +02:00
return ;
}
2018-05-06 00:13:35 +02:00
} else if ( isScriptFilename ( filename ) ) {
2018-03-12 20:39:04 +01:00
//If the current script already exists on the server, overwrite it
2021-04-20 03:26:51 +02:00
for ( let i = 0 ; i < s . scripts . length ; i ++ ) {
2018-03-12 20:39:04 +01:00
if ( filename == s . scripts [ i ] . filename ) {
2019-05-07 03:01:06 +02:00
s . scripts [ i ] . saveScript ( getCurrentEditor ( ) . getCode ( ) , Player . currentServer , Player . getCurrentServer ( ) . scripts ) ;
2018-03-12 20:39:04 +01:00
Engine . loadTerminalContent ( ) ;
return ;
}
}
2017-07-25 16:39:56 +02:00
2018-03-12 20:39:04 +01:00
//If the current script does NOT exist, create a new one
2019-03-15 10:37:06 +01:00
const script = new Script ( ) ;
2019-05-07 03:01:06 +02:00
script . saveScript ( getCurrentEditor ( ) . getCode ( ) , Player . currentServer , Player . getCurrentServer ( ) . scripts ) ;
2018-03-12 20:39:04 +01:00
s . scripts . push ( script ) ;
} else if ( filename . endsWith ( ".txt" ) ) {
2021-04-20 03:26:51 +02:00
for ( let i = 0 ; i < s . textFiles . length ; ++ i ) {
2018-03-12 20:39:04 +01:00
if ( s . textFiles [ i ] . fn === filename ) {
s . textFiles [ i ] . write ( code ) ;
Engine . loadTerminalContent ( ) ;
return ;
}
}
2021-04-20 03:26:51 +02:00
const textFile = new TextFile ( filename , code ) ;
2018-03-12 20:39:04 +01:00
s . textFiles . push ( textFile ) ;
} else {
dialogBoxCreate ( "Invalid filename. Must be either a script (.script) or " +
" or text file (.txt)" )
return ;
}
2017-05-03 06:38:58 +02:00
Engine . loadTerminalContent ( ) ;
}
2019-05-05 06:03:40 +02:00
export function scriptCalculateOfflineProduction ( runningScriptObj ) {
2016-12-19 21:59:13 +01:00
//The Player object stores the last update time from when we were online
var thisUpdate = new Date ( ) . getTime ( ) ;
var lastUpdate = Player . lastUpdate ;
var timePassed = ( thisUpdate - lastUpdate ) / 1000 ; //Seconds
2017-07-25 16:39:56 +02:00
2016-12-19 21:59:13 +01:00
//Calculate the "confidence" rating of the script's true production. This is based
//entirely off of time. We will arbitrarily say that if a script has been running for
2017-05-05 03:08:44 +02:00
//4 hours (14400 sec) then we are completely confident in its ability
2017-06-17 04:53:57 +02:00
var confidence = ( runningScriptObj . onlineRunningTime ) / 14400 ;
2016-12-19 21:59:13 +01:00
if ( confidence >= 1 ) { confidence = 1 ; }
2017-07-25 16:39:56 +02:00
2017-06-19 01:23:50 +02:00
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
2017-07-25 16:39:56 +02:00
2019-02-06 08:06:48 +01:00
// Grow
2017-06-19 01:23:50 +02:00
for ( var ip in runningScriptObj . dataMap ) {
if ( runningScriptObj . dataMap . hasOwnProperty ( ip ) ) {
if ( runningScriptObj . dataMap [ ip ] [ 2 ] == 0 || runningScriptObj . dataMap [ ip ] [ 2 ] == null ) { continue ; }
2017-06-13 17:58:31 +02:00
var serv = AllServers [ ip ] ;
if ( serv == null ) { continue ; }
2017-06-19 01:23:50 +02:00
var timesGrown = Math . round ( 0.5 * runningScriptObj . dataMap [ ip ] [ 2 ] / runningScriptObj . onlineRunningTime * timePassed ) ;
2017-06-17 04:53:57 +02:00
runningScriptObj . log ( "Called grow() on " + serv . hostname + " " + timesGrown + " times while offline" ) ;
2021-03-31 06:45:21 +02:00
var growth = processSingleServerGrowth ( serv , timesGrown , Player ) ;
2018-09-12 17:53:08 +02:00
runningScriptObj . log ( serv . hostname + " grown by " + numeralWrapper . format ( growth * 100 - 100 , '0.000000%' ) + " from grow() calls made while offline" ) ;
2017-06-13 17:58:31 +02:00
}
}
2017-07-25 16:39:56 +02:00
2019-02-06 08:06:48 +01:00
// Money from hacking
2017-05-10 19:42:46 +02:00
var totalOfflineProduction = 0 ;
2017-06-19 01:23:50 +02:00
for ( var ip in runningScriptObj . dataMap ) {
if ( runningScriptObj . dataMap . hasOwnProperty ( ip ) ) {
if ( runningScriptObj . dataMap [ ip ] [ 0 ] == 0 || runningScriptObj . dataMap [ ip ] [ 0 ] == null ) { continue ; }
2017-05-10 19:42:46 +02:00
var serv = AllServers [ ip ] ;
2017-05-10 22:21:15 +02:00
if ( serv == null ) { continue ; }
2017-06-19 01:23:50 +02:00
var production = 0.5 * runningScriptObj . dataMap [ ip ] [ 0 ] / runningScriptObj . onlineRunningTime * timePassed ;
2017-05-10 19:42:46 +02:00
production *= confidence ;
if ( production > serv . moneyAvailable ) {
production = serv . moneyAvailable ;
}
totalOfflineProduction += production ;
2017-07-25 16:39:56 +02:00
Player . gainMoney ( production ) ;
2019-02-22 03:26:28 +01:00
Player . recordMoneySource ( production , "hacking" ) ;
2017-06-17 04:53:57 +02:00
runningScriptObj . log ( runningScriptObj . filename + " generated $" + production + " while offline by hacking " + serv . hostname ) ;
2017-05-10 19:42:46 +02:00
serv . moneyAvailable -= production ;
if ( serv . moneyAvailable < 0 ) { serv . moneyAvailable = 0 ; }
2017-06-20 18:11:33 +02:00
if ( isNaN ( serv . moneyAvailable ) ) { serv . moneyAvailable = 0 ; }
2017-05-10 19:42:46 +02:00
}
}
2019-02-06 08:06:48 +01:00
// Offline EXP gain
// A script's offline production will always be at most half of its online production.
2017-06-17 04:53:57 +02:00
var expGain = 0.5 * ( runningScriptObj . onlineExpGained / runningScriptObj . onlineRunningTime ) * timePassed ;
2016-12-19 21:59:13 +01:00
expGain *= confidence ;
2017-07-25 16:39:56 +02:00
2017-05-05 03:08:44 +02:00
Player . gainHackingExp ( expGain ) ;
2017-07-25 16:39:56 +02:00
2019-02-06 08:06:48 +01:00
// Update script stats
2017-06-17 04:53:57 +02:00
runningScriptObj . offlineMoneyMade += totalOfflineProduction ;
runningScriptObj . offlineRunningTime += timePassed ;
runningScriptObj . offlineExpGained += expGain ;
2017-07-25 16:39:56 +02:00
2019-02-06 08:06:48 +01:00
// Fortify a server's security based on how many times it was hacked
2017-06-19 01:23:50 +02:00
for ( var ip in runningScriptObj . dataMap ) {
if ( runningScriptObj . dataMap . hasOwnProperty ( ip ) ) {
if ( runningScriptObj . dataMap [ ip ] [ 1 ] == 0 || runningScriptObj . dataMap [ ip ] [ 1 ] == null ) { continue ; }
2017-06-01 03:57:49 +02:00
var serv = AllServers [ ip ] ;
if ( serv == null ) { continue ; }
2017-06-19 01:23:50 +02:00
var timesHacked = Math . round ( 0.5 * runningScriptObj . dataMap [ ip ] [ 1 ] / runningScriptObj . onlineRunningTime * timePassed ) ;
2017-06-17 04:53:57 +02:00
runningScriptObj . log ( "Hacked " + serv . hostname + " " + timesHacked + " times while offline" ) ;
2017-06-01 03:57:49 +02:00
serv . fortify ( CONSTANTS . ServerFortifyAmount * timesHacked ) ;
}
}
2017-07-25 16:39:56 +02:00
2019-02-06 08:06:48 +01:00
// Weaken
2017-06-19 01:23:50 +02:00
for ( var ip in runningScriptObj . dataMap ) {
if ( runningScriptObj . dataMap . hasOwnProperty ( ip ) ) {
if ( runningScriptObj . dataMap [ ip ] [ 3 ] == 0 || runningScriptObj . dataMap [ ip ] [ 3 ] == null ) { continue ; }
2017-06-01 03:57:49 +02:00
var serv = AllServers [ ip ] ;
if ( serv == null ) { continue ; }
2017-06-19 01:23:50 +02:00
var timesWeakened = Math . round ( 0.5 * runningScriptObj . dataMap [ ip ] [ 3 ] / runningScriptObj . onlineRunningTime * timePassed ) ;
2017-06-17 04:53:57 +02:00
runningScriptObj . log ( "Called weaken() on " + serv . hostname + " " + timesWeakened + " times while offline" ) ;
2017-06-01 03:57:49 +02:00
serv . weaken ( CONSTANTS . ServerWeakenAmount * timesWeakened ) ;
}
}
2017-07-25 16:39:56 +02:00
2017-05-20 11:27:42 +02:00
return totalOfflineProduction ;
2017-05-10 19:42:46 +02:00
}
2017-06-17 04:53:57 +02:00
//Returns a RunningScript object matching the filename and arguments on the
//designated server, and false otherwise
2019-03-05 02:40:28 +01:00
export function findRunningScript ( filename , args , server ) {
2017-06-17 04:53:57 +02:00
for ( var i = 0 ; i < server . runningScripts . length ; ++ i ) {
2019-05-02 00:20:14 +02:00
if ( server . runningScripts [ i ] . filename === filename &&
2017-06-17 04:53:57 +02:00
compareArrays ( server . runningScripts [ i ] . args , args ) ) {
return server . runningScripts [ i ] ;
}
}
return null ;
}