HyperScript
Docs

← All of the Docs Data and the outside

Files

effectcreate file <name> [at <folder>]since 1.3.0

Create an empty file, with any missing folders. An existing file is left untouched

create file "proplayer300data.txt" at "plugins/HyperScript/"
Try it
effectset file at <path> to <text>since 1.3.0

Replace the file's content, creating the file if needed. A list is written one element per line

set file at "plugins/HyperScript/coins.csv" to csv of {_rows}
Try it
effectappend <text> to file at <path>since 1.3.0

Add to the end of the file; write "%nl%..." to start a new line

append "\n%player.name% joined" to file at "plugins/HyperScript/log.txt"
Try it
expressionread file at <path>since 1.3.0

The file's whole text; unset if the file does not exist

set {_proplayer300data} to read file at "plugins/HyperScript/proplayer300data.txt"
Try it
expressionfile at <path> existssince 1.3.0

A condition: if file at {_path} exists:

if file at "plugins/HyperScript/notes.txt" exists:
    send read file at "plugins/HyperScript/notes.txt"
Try it
effectdelete file at <path>since 1.3.0

Remove the file; no error if it is not there

delete file at "plugins/HyperScript/notes/old.txt"
Try it
expressionlines of file at <path>since 1.7.31

The file's lines as a list, to loop over or count; unset if the file does not exist

set {_lines} to lines of file at {_path}
Try it
expressionsize of file at <path>since 1.7.31

How large the file is, in bytes; unset if it does not exist

add size of file at "%{_notes}%/%{_path}%" to {_bytes}
Try it
expressionlast modified of file at <path>since 1.7.31

When it was last written to, as a date; unset if it does not exist

set {_when} to last modified of file at {_path}
Try it
expressioncopy file at <path> to <path>since 1.7.31

A second copy under another name or in another folder. What is there already is replaced

copy file at "%{_notes}%/%{_path}%" to "%{_backup}%/%{_path}%"
Try it
expressionmove file at <path> to <path>since 1.7.31

The same file somewhere else, or under another name: this is how a file is renamed

move file at {_from} to "plugins/HyperScript/archive/%arg.1%.txt"
Try it
expressionfiles in <folder>since 1.7.31

The names of the files in a folder, as a list in the order of the alphabet

set {_names} to files in {_folder}
Try it
expressionfolders in <folder>since 1.7.31

The names of the folders in it

set {_groups} to folders in {_notes}
Try it
expressionall files in <folder>since 1.7.31

Every file in the folder and the folders inside it, each as its path from that folder: logs/monday.txt

for each {_path} in all files in {_notes}:
    copy file at "%{_notes}%/%{_path}%" to "%{_backup}%/%{_path}%"
    add size of file at "%{_notes}%/%{_path}%" to {_bytes}
Try it
expressionfolder at <path> existssince 1.7.31

A condition: if folder at "plugins/HyperScript/logs" exists:

if folder at {_backup} exists:
    delete folder at {_backup} with its files
Try it
effectcreate folder <path>since 1.7.31

Make a folder, with any missing folders around it. One that is there is left as it is

create folder {_backup}
Try it
effectdelete folder at <path>since 1.7.31

Remove an empty folder. Add with its files to remove one with everything in it

delete folder at {_backup} with its files
Try it
expressionyaml value <key> of file at <path>since 1.7.63

One value out of a YAML file, such as another plugin's config.yml, by its path written with dots: yaml value "shop.prices.diamond" of file at "plugins/Shop/config.yml". A number, text, true or false, a list, or for a section a table of what is in it; unset if there is nothing there. Read only, and within the folders scripts may read

command /shopprice:
    trigger:
        set {_price} to yaml value "prices.diamond" of file at "plugins/HyperScript/shop.yml"
        send "&7A diamond costs &f%{_price}%"
Try it
expressioncsv of file at <path>since 1.7.49

The rows of a .csv file as a list, each row a list of its cells: item 2 of item 1 of {_rows} is the second cell of the first row. Unset if the file does not exist

set {_rows} to csv of file at "plugins/HyperScript/prices.csv"
if {_rows} is not set:
    send "&cThere is no prices.csv."
    stop
send "&7The first cell is %item 1 of item 1 of {_rows}%."
Try it
expressioncsv of file at <path> with headerssince 1.7.49

The same with the first row as the names of the columns: each later row is a table, read as {_row.price}

set {_rows} to csv of file at "plugins/HyperScript/prices.csv" with headers
for each {_row} in {_rows}:
    send "&e%{_row.item}% &7costs &f%{_row.price}%"
Try it
expressioncolumn <which> of <rows>since 1.7.49

One column of such rows, top to bottom: by its number, or by its name for rows read with headers

set {_rows} to csv of file at "plugins/HyperScript/prices.csv" with headers
set {_prices} to column "price" of {_rows}
send "&7Prices: %{_prices}%"
Try it
expressioncsv of <rows>since 1.7.49

Rows as CSV text, to write with set file at. A list of lists is a line each; a list of tables gets a first line with the names

set {_rows} to [["player", "coins"], [player.name, {%player%.coins}]]
set file at "plugins/HyperScript/coins.csv" to csv of {_rows}
Try it
expressionparse <text> as csvsince 1.7.49

Text with commas in it as rows; add with headers as above

set {_rows} to parse "diamond,120%nl%stick,0.5" as csv
send "&7%size of {_rows}% rows; the first costs %item 2 of item 1 of {_rows}%"
Try it
expressionall scriptssince 1.7.32

The names of the files in the scripts folder, as a list: Kits.hs, games/Duels.hs

for each {_script} in all scripts:
    if {_script} is not this script:
        delete script {_script}
Try it
expressionthis scriptsince 1.7.32

The name of the file the line is in

if {_script} is not this script:
    delete script {_script}
Try it
expressionscript <name> existssince 1.7.32

A condition. The name may be written with or without .hs

if not script "Sidebar" exists:
    send "&cThere is no Sidebar.hs here."
    stop
Try it
expressionenabled scriptssince 1.7.70

The scripts that are switched on, as a list. disabled scripts for those that are not, by the names they have when they are on

command /loaded:
    trigger:
        send "&aOn: &f%enabled scripts%"
        send "&7Off: &f%disabled scripts%"
Try it
conditionscript <name> is enabledsince 1.7.70

A condition; is disabled for the other. A script that is not there is neither

if script "Kits" is enabled:
    send "&aKits are switched on."
Try it
expressionerror of script <name>since 1.7.70

What a script failed to load with, such as line 12: Expected 'to' but found 'too'; unset for one that loaded

command /why <script>:
    trigger:
        set {_error} to error of script arg.1
        if {_error} is set:
            send "&c%arg.1% did not load: &f%{_error}%"
        else:
            send "&a%arg.1% has no mistake in it."
Try it
expressiondisable script <name>since 1.7.70

Switch a script off, the way /hyperscript disable does: its file is kept, with disabled_ in front of its name, and the scripts are read again a moment later. enable script <name> switches it back on

command /events <state>:
    permission: "events.admin"
    trigger:
        if arg.1 is "off":
            disable script "Events"
        else:
            enable script "Events"
Try it
effectdelete script <name>since 1.7.32

Take a script out of the scripts folder. It is not destroyed: it is moved to plugins/HyperScript/removed-scripts, from where it can be put back

delete script {_script}
Try it
expressionoption <name> of script <name>since 1.7.32

What that script's options: block says for one option, without quotes; unset if it has no such option

set option "name" of script "Sidebar" to arg.1
Try it
effectset option <name> of script <name> to <value>since 1.7.32

Write another value into that script's options: block. The rest of the file, and a note after the value, stay as they are

set option "name" of script "Sidebar" to arg.1
Try it
Guide and examples

Scripts can keep plain text files inside the plugin folder.

create file "proplayer300data.txt" at "plugins/HyperScript/"
set file at "plugins/HyperScript/proplayer300data.txt" to "Coins:500"
set {_proplayer300data} to read file at "plugins/HyperScript/proplayer300data.txt"
set {_parts} to split {_proplayer300data} by ":"
SyntaxEffect
create file <name> [at <folder>]Create an empty file, with any missing folders. An existing file is left untouched
set file at <path> to <text>Replace the file's content, creating the file if needed. A list is written one element per line
append <text> to file at <path>Add to the end of the file; write "%nl%..." to start a new line
read file at <path>The file's whole text; unset if the file does not exist
file at <path> existsA condition: if file at {_path} exists:
delete file at <path>Remove the file; no error if it is not there
lines of file at <path>The file's lines as a list, to loop over or count; unset if the file does not exist
size of file at <path>How large the file is, in bytes; unset if it does not exist
last modified of file at <path>When it was last written to, as a date; unset if it does not exist
copy file at <path> to <path>A second copy under another name or in another folder. What is there already is replaced
move file at <path> to <path>The same file somewhere else, or under another name: this is how a file is renamed
files in <folder>The names of the files in a folder, as a list in the order of the alphabet
folders in <folder>The names of the folders in it
all files in <folder>Every file in the folder and the folders inside it, each as its path from that folder: logs/monday.txt
folder at <path> existsA condition: if folder at "plugins/HyperScript/logs" exists:
create folder <path>Make a folder, with any missing folders around it. One that is there is left as it is
delete folder at <path>Remove an empty folder. Add with its files to remove one with everything in it
yaml value <key> of file at <path>One value out of a YAML file, such as another plugin's config.yml, by its path written with dots: yaml value "shop.prices.diamond" of file at "plugins/Shop/config.yml". A number, text, true or false, a list, or for a section a table of what is in it; unset if there is nothing there. Read only, and within the folders scripts may read
csv of file at <path>The rows of a .csv file as a list, each row a list of its cells: item 2 of item 1 of {_rows} is the second cell of the first row. Unset if the file does not exist
csv of file at <path> with headersThe same with the first row as the names of the columns: each later row is a table, read as {_row.price}
column <which> of <rows>One column of such rows, top to bottom: by its number, or by its name for rows read with headers
csv of <rows>Rows as CSV text, to write with set file at. A list of lists is a line each; a list of tables gets a first line with the names
parse <text> as csvText with commas in it as rows; add with headers as above

CSV files. A .csv file is what a spreadsheet saves: a line for each row, commas between the cells. csv of file at reads one into rows, and the rows are lists inside a list, so every cell is reached with item:

command /prices:
    trigger:
        set {_rows} to csv of file at "plugins/HyperScript/prices.csv" with headers
        for each {_row} in {_rows}:
            send "&e%{_row.item}% &7costs &f%{_row.price}%"
        set {_prices} to column "price" of {_rows}
        send "&7All prices: %{_prices}%"

command /export:
    trigger:
        set {_rows} to [["player", "coins"]]
        for each {_name} in server.players:
            add [{_name}, {%{_name}%.coins}] to {_rows}
        set file at "plugins/HyperScript/coins.csv" to csv of {_rows}
        send "&aWritten."
  • A cell that is written as a number is a number, true and false are themselves, an empty cell is not set, and everything else is text. 007 stays text, so that ids keep their zeros.
  • With with headers, the names of the columns are taken in lower case: a column Price is {_row.price}.
  • A cell with a comma, a quote or a line break in it is written in quotes, as spreadsheets do, and read back the same. Files that use semicolons or tabs between the cells, as spreadsheets write where the comma is the decimal point, are read as well.
  • At most 100,000 rows are read from one file.

Paths are written relative to the server folder, with forward slashes, as in "plugins/HyperScript/notes.txt".

command /notes:
    permission: "notes.read"
    trigger:
        set {_folder} to "plugins/HyperScript/notes"
        set {_names} to files in {_folder}
        if size of {_names} == 0:
            send "&7There are no notes."
            stop
        send "&6%size of {_names}% notes:"
        for each {_name} in {_names}:
            set {_path} to "%{_folder}%/%{_name}%"
            set {_lines} to lines of file at {_path}
            set {_when} to last modified of file at {_path}
            set {_day} to {_when} formatted as "d MMM"
            send " &f%{_name}% &8- &7%size of {_lines}% lines, changed %{_day}%"

command /archive <text>:
    permission: "notes.admin"
    trigger:
        set {_from} to "plugins/HyperScript/notes/%arg.1%.txt"
        if not file at {_from} exists:
            send "&cThere is no note called %arg.1%."
            stop
        move file at {_from} to "plugins/HyperScript/archive/%arg.1%.txt"
        send "&aArchived."

command /backupnotes:
    permission: "notes.admin"
    trigger:
        set {_notes} to "plugins/HyperScript/notes"
        set {_backup} to "plugins/HyperScript/notes-backup"
        if folder at {_backup} exists:
            delete folder at {_backup} with its files
        create folder {_backup}
        set {_bytes} to 0
        for each {_path} in all files in {_notes}:
            copy file at "%{_notes}%/%{_path}%" to "%{_backup}%/%{_path}%"
            add size of file at "%{_notes}%/%{_path}%" to {_bytes}
        set {_groups} to folders in {_notes}
        send "&aCopied %{_bytes}% bytes from %size of {_groups}% folders of notes."

on load:
    # An empty folder left over from last time goes; one with something in it is left alone.
    if size of (files in "plugins/HyperScript/temp") == 0:
        delete folder at "plugins/HyperScript/temp"
  • A folder that is not there has no files in it: files in gives an empty list, not a mistake.
  • files in and folders in may be asked of "plugins/HyperScript" itself; HyperScript's own files and folders are left out of the answer. A listing has at most 1000 names.
  • move file and copy file make the folders the new place needs.

Scripts that look after scripts. The scripts folder is closed to the statements above, so that a path made from what a player typed can never reach it. A script that sets a server up can still see which scripts there are, take one out, and read and change another's options:

command /cleanup:
    permission: "hyperscript.admin"
    trigger:
        for each {_script} in all scripts:
            if {_script} is not this script:
                delete script {_script}
        send "&aEvery other script was taken out."

command /servername <text>:
    permission: "hyperscript.admin"
    trigger:
        if not script "Sidebar" exists:
            send "&cThere is no Sidebar.hs here."
            stop
        set {_old} to option "name" of script "Sidebar"
        set option "name" of script "Sidebar" to arg.1
        send "&aThe sidebar was called %{_old}% and is now called %arg.1%."
SyntaxEffect
all scriptsThe names of the files in the scripts folder, as a list: Kits.hs, games/Duels.hs
this scriptThe name of the file the line is in
script <name> existsA condition. The name may be written with or without .hs
enabled scriptsThe scripts that are switched on, as a list. disabled scripts for those that are not, by the names they have when they are on
script <name> is enabledA condition; is disabled for the other. A script that is not there is neither
error of script <name>What a script failed to load with, such as line 12: Expected 'to' but found 'too'; unset for one that loaded
disable script <name>Switch a script off, the way /hyperscript disable does: its file is kept, with disabled_ in front of its name, and the scripts are read again a moment later. enable script <name> switches it back on
delete script <name>Take a script out of the scripts folder. It is not destroyed: it is moved to plugins/HyperScript/removed-scripts, from where it can be put back
option <name> of script <name>What that script's options: block says for one option, without quotes; unset if it has no such option
set option <name> of script <name> to <value>Write another value into that script's options: block. The rest of the file, and a note after the value, stay as they are
  • With hot reloading on, a script that was changed or taken out is loaded again by itself; otherwise run /hyperscript reload, which a script can do with execute console command "hyperscript reload".
  • An option a script does not have is not added: set option stops the trigger and says so. Ask first with option ... of script ... is set.
  • These follow files.enabled like everything else here.
  • Scripts can only reach files inside plugins/HyperScript/. A path that leads anywhere else, including through .. or an absolute path, stops the trigger with a warning in the console.
  • Inside that folder, HyperScript's own files are off limits: config.yml, data.json, the database, and the scripts and backups folders.
  • These limits exist because paths are often built from what players type. Even so, prefer names you control, such as %player.uuid%, over raw player input in a path.
  • Files are read as UTF-8 text. read file refuses files larger than 1 MB.
  • File access happens immediately, on the thread the script is running on. That is fine for small files; put work on large ones inside async:.
  • For data that belongs to a player or to the server as a whole, variables are usually the better tool: they are saved, backed up and cached for you. Files are for things other programs read or write, such as logs and exports.
  • files.enabled: false in config.yml turns all of this off.