#script.name
The script's name: its file name without .lua.
The script's own folder, saved state, JSON and encodings, helpers - and, for trusted scripts, the network, the clipboard and raw memory.
This page covers everything a script does with data that is not the game: files it keeps, state it saves, text it parses, and - for scripts you have decided to trust - requests it sends and memory it reads.
script.nameThe script's name: its file name without .lua.
script.trustedtrue when the script has been switched to trusted. A script can check it to explain itself - or to stay away from features it cannot have.
script.folder() → stringThe script's own folder, C:/elysium/scripts/<name>, without a trailing slash. It is the one place a sandboxed script may read and write; it need not exist yet.
script.path( relative ) → stringAn absolute path to something inside the script's folder: script.path( "log/today.txt" ). Refuses .., drive letters and leading slashes, so a path built this way cannot leave the folder.
fs reads and writes files. Paths are relative to the script's own folder; .. and drive letters are refused, and an absolute path is accepted only from a trusted script. Write file names in ASCII - paths go through the system's code page, not UTF-8.
fs.read( path ) → text | nil, messageThe whole file as a string. nil and a message - that path is outside the script's folder, cannot open the file, the file is too large - when it cannot be read. Files over 64 MB are refused.
fs.write( path, data ) → booleanWrites data to the file, replacing it, and creates the folders on the way. false if the path is not allowed or the file could not be written.
fs.append( path, data ) → booleanAdds data to the end of the file, creating it if it is not there.
fs.exists( path ) → booleanfs.size( path ) → integer | nilThe file's size in bytes; nil if it does not exist or the path is not allowed.
fs.list( [directory] ) → list | nilThe names of the files and folders inside a folder - the script's own folder by default - sorted, at most 4096. nil if the path is not allowed.
fs.mkdir( path ) → booleanCreates a folder and the ones above it. true if it exists afterwards.
fs.remove( path ) → booleanDeletes a file or an empty folder.
fs.write( "log/session.txt", "started " .. os.date( "%H:%M" ) .. "\n" )
fs.append( "log/session.txt", "hello\n" )
print( fs.read( "log/session.txt" ) )store is a small table that survives reloads and restarts. Put things in it that the script should remember: a counter, a list of positions, the last thing the user typed.
store.set( key, value )Saves value under key. The value has to be something JSON can hold: nil (which removes the key), booleans, numbers, strings, and tables of those. A table whose keys are exactly 1, 2, ..., n is stored as a list; any other table as an object with text keys. Functions, userdata, tables that contain themselves and tables nested deeper than 24 levels raise store.set: the value cannot be saved.
store.get( key [, default] ) → valueThe saved value, or default (nil if omitted) when there is none. The value you get is a fresh copy: changing it does not change what is stored until you set it again.
store.keys() → listEvery key currently stored.
store.clear()Forgets everything.
The data is written to .data\<name>.store.json a moment after the last change - not on every call - and again when the script unloads, so setting a value every frame does not hammer the disk.
local runs = store.get( "runs", 0 ) + 1
store.set( "runs", runs )
print( "this script has been loaded " .. runs .. " times" )json.encode( value [, pretty] ) → text | nil, messageTurns a value into JSON text. Tables follow the same rule as in store.set: keys 1..n make a list, anything else an object. With pretty = true the text is indented by two spaces. nil and a message when the value holds something JSON cannot - a function, userdata, a cycle, nesting past 24 levels, or a number that is not finite.
json.decode( text ) → value | nil, messageParses JSON text into tables, strings, numbers and booleans. nil and a message - not valid JSON, the text is too large - when it cannot. JSON null becomes nil, so a list containing nulls has holes in it. Text over 16 MB is refused.
local text = json.encode( { name = "ak", shots = { 1, 2, 3 } } )
local again = json.decode( text )
print( again.shots[ 2 ] ) --> 2base64.encode( text ) → stringbase64.decode( text ) → string | nil, messageBase64 for arbitrary bytes. Decoding answers nil and not valid base64 for text that is not.
hash.fnv1a( text ) → integerThe 32-bit FNV-1a hash of the bytes - the same function the cheat hashes names with.
hash.murmur2( text [, seed] ) → integerThe 32-bit MurmurHash2, with an optional seed.
hash.crc32( text ) → integerThe standard CRC-32 of the bytes.
All three answer a number between 0 and 4294967295.
time.unix() → integerSeconds since 1 January 1970, UTC. For readable dates the standard os.date and os.time work as usual.
time.ms() → numberMilliseconds on a clock that only moves forward, with sub-millisecond precision. Good for measuring how long something took.
local started = time.ms( )
-- ... work ...
print( string.format( "took %.2f ms", time.ms( ) - started ) )util.random_hex( [bytes] ) → stringbytes random bytes from the system's random number source, as lowercase hex - twice as many characters. 1 to 256 bytes, 16 by default. For identifiers and nonces. For game logic math.random is the right tool.
Lua 5.4 has bit operators of its own - &, |, ~, <<, >> - and they work on every integer. bits adds the few calls that read better when you are dealing with masks and flags, such as the button set and entity flags.
bits.band( a, b, ... ) → integerbits.bor( a, b, ... ) → integerbits.bxor( a, b, ... ) → integerBitwise AND, OR and exclusive OR of any number of integers.
bits.bnot( a ) → integerEvery bit flipped.
bits.shl( a, n ), bits.shr( a, n ) → integerShift left or right by n bits. Both are logical - zeros are shifted in, also for negative numbers - and a count of 64 or more gives 0.
bits.has( value, mask ) → booleantrue when every bit of mask is set in value.
bits.any( value, mask ) → booleantrue when at least one bit of mask is set in value.
bits.set( value, mask ), bits.clear( value, mask ) → integervalue with the bits of mask switched on, or off.
bits.count( value ) → integerHow many bits are set.
if bits.has( me:flags( ), ents.flags.on_ground + ents.flags.ducking ) then
-- standing on the ground, crouched
endstring and tableSmall functions Lua's own libraries never had. They are plain Lua, defined for every script.
string.split( text, separator [, plain] ) → listCuts text at every separator. The separator is searched for as plain text unless plain is false, in which case it is a Lua pattern. An empty or missing separator splits into single characters.
local parts = string.split( "a,b,,c", "," ) --> { "a", "b", "", "c" }string.trim( text ) → stringRemoves whitespace from both ends.
string.starts_with( text, prefix ) → booleanstring.ends_with( text, suffix ) → booleantable.copy( source ) → tableA shallow copy: the same values under the same keys.
table.deep_copy( source ) → tableA copy that copies the tables inside too, keeps metatables, and copes with tables that refer to themselves.
table.contains( list, value ) → booleanWhether any value in the table equals value.
table.keys( source ) → list, table.values( source ) → listThe keys, or the values, as a list - in no particular order.
net.get( url [, options], handler ) → booleantrustedFetches an address without waiting: the call returns at once with true, and handler( response ) is called a frame or two later, on the render thread, when the answer is in. false and a message if the request could not be started - the options were bad, or four requests are already running.
response is a table:
| Field | Meaning |
|---|---|
ok | true for an HTTP status in the 200s. |
status | The HTTP status code; 0 if no answer arrived. |
body | The answer, as a string. Absent when save_to was used. |
path | With save_to: where the answer was written. |
headers | The raw response headers, as text. |
error | What went wrong, when the request failed at the network level. |
options is an optional table:
| Field | Meaning | Default |
|---|---|---|
headers | A table { Name = "value" } of request headers. Names are letters, digits, - and _; values must not contain line breaks. | none |
timeout | Seconds before giving up, 1 to 120. | 15 |
save_to | A file in the script's folder to write the answer to instead of returning it. | none |
max_bytes | The most the answer may be, 1 KB to 64 MB; larger is an error. | 8 MB |
user_agent | The User-Agent header. | script/1.0 |
net.get( "https://example.com/data.json", { timeout = 5 }, function( response )
if response.ok then
local data = json.decode( response.body )
-- ...
else
warn( "request failed: " .. ( response.error or response.status ) )
end
end )Only http and https addresses are accepted. At most four requests run at once. If the script is reloaded before an answer arrives, the answer is dropped.
net.post( url, body [, options], handler ) → booleantrustedThe same, sending body (a string, up to 8 MB) with a POST. Add a Content-Type header yourself when the server needs one.
clipboard.get() → string | niltrustedThe text on the clipboard; nil if there is none.
clipboard.set( text ) → booleantrustedPuts text on the clipboard.
util.open_url( url ) → booleantrustedOpens an address in the default browser. Only http:// and https:// addresses are accepted.
mem reads and writes the game's memory and calls code in it. Reads and writes are protected: an address that cannot be reached answers nil or false instead of crashing the game. Nothing else is checked - a wrong write, or a call with the wrong arguments, can crash the game or worse. This is for people who know what they are doing.
mem.module( name ) → integer | niltrustedThe base address of a loaded module: mem.module( "client.dll" ).
mem.module_size( base ) → integertrustedThe size of a loaded module in bytes.
mem.export( module_base, name ) → integer | niltrustedThe address of a function a module exports.
mem.pattern( module, pattern ) → integer | niltrustedFinds a byte pattern in a module and returns an address, using the cheat's own pattern syntax. The pattern is up to 128 bytes of hex pairs - spaces are allowed - with ? for a byte that can be anything:
local address = mem.pattern( "client.dll", "48 8B 05 ? ? ? ? 48 85 C0" )Markers say what to return instead of the place the pattern was found:
| Marker | Meaning |
|---|---|
* | The 4 bytes at this point are a relative offset: return the address they point at (for lea, mov and the like with a RIP-relative operand). |
> | Put before the opcode byte of a call or jmp: return the address it calls. |
^ | The bytes at this point are an absolute 8-byte address: return it. |
+n, -n | n in hex: added to the result afterwards. |
~ | Read the pointer stored at the result and return that. |
nil when the pattern is not found.
mem.vfunc( object, index ) → integer | niltrustedThe address of the function in a slot of an object's virtual table. object is the object's address - ent:address() for an entity.
mem.read( address, type ) → value | niltrustedReads a value. type is "bool", "i8", "u8", "i16", "u16", "i32" ("int"), "u32", "i64" ("ptr", "u64"), "f32" ("float"), "f64" ("double") or "vec3". nil if the memory cannot be read.
mem.write( address, type, value ) → booleantrustedWrites a value of the same types; false if the memory cannot be written.
mem.read_bytes( address, count ) → string | niltrustedcount bytes (up to 1 MB) as a string, or nil if any of them cannot be read.
mem.write_bytes( address, data ) → booleantrustedmem.string( address [, max] ) → stringtrustedThe zero-terminated string at an address, up to max bytes (256 by default).
mem.call( address, returns, ... ) → valuetrustedCalls native code at address with up to eight arguments, all of the integer kind: integers, booleans, pointers, and strings (passed as pointers that stay valid for the call; nil is 0). returns is "void", "int" (or "ptr"), "bool", "float" or "double". Floating-point arguments are not supported - passing one raises an error.
A fault inside the function does not take the game down: the answer is nil and the message the function faulted.
local get_tick = mem.pattern( "engine2.dll", "..." ) -- some function you found
local tick = get_tick and mem.call( get_tick, "int" )There is no checking of what is called: a wrong address, or the wrong number of arguments, is a crash - or worse.