Table of Contents
The file extension allows you to create, read, and modify files locally stored on your computer. Because files are stored locally by you, this means they must be sent to the server using fileLoad
before they can be accessed. Files cannot be modified without a similar network transaction back using fileWrite
. file also contains fileList
to query what files exist in a directory.
File locations
Files are by default saved into e2files
in your Garry's Mod data directory, but can also be redirected using >
into these select directories:
>e2files
->e2files
>e2shared
->expression2/e2shared
>cpushared
->cpuchip/e2shared
>gpushared
->gpuchip/e2shared
>spushared
->spuchip/e2shared
An example usage would be fileWrite(">e2shared/test.txt", "Hello, World!")
, which would then write a file which you could access in the Expression 2 file browser under e2shared
.
Important
It is impossible in Garry's Mod to write to a file outside of the
garrysmod/data
folder. On top of this, the file extension can only read and write to the above directories. The extension cannot read files from the server.
Requirements of a file
Files can fail to load, create, or otherwise fail if these rules are not followed;
- Filename must end with
.txt
- File must be inside one of the above directories
- Files must be under the size limit (default 300KiB)
Basic File Operations
Warning
The examples here will write files to your
e2files
directory. Make sure you're not overwriting anything important before trying these!
To show what a typical usage of file operations looks like, let's try writing to a file on the chip start and reading it back after it's written. fileWrite(string path, string data)
allows you to write to a file. If the file exists, it will be overwritten. There are no safeguards for file overwriting, so make sure you're not replacing important data when doing this!
@name File Write and Read
@trigger none
@strict
fileWrite("test.txt", "Hello, World! " + curtime())
Just to show that the file we're writing is being overwritten, we'll also add curtime()
to the end of its message, which will give it a "timestamp" every time this code is ran. Next, we'll add events to read the file once it finishes writing. We can use the event fileWritten
, which triggers right after a file finishes writing. The first parameter of fileWritten
is the path of the written file. We'll use that here to demonstrate its usage. The second parameter is the data that we just wrote, which we'll discard in this example. We'll then use fileLoad
on this path, which will load up test.txt
and trigger the fileLoaded
event when finished.
event fileWritten(Path:string, _:string) {
fileLoad(Path)
}
In the fileLoaded
event, the first parameter is the path to the file as a string, and the second is the contents of the file, also as a string. We'll just print out both with some simple formatting. We'll also print out curtime()
to see how much time has progressed between writing and loading.
event fileLoaded(Path:string, Data:string) {
print(format("%s: %s \nTime: %f", Path, Data, curtime()))
}
After running our code, we should see an output like this:
test.txt: Hello, World! 6030.6748046875
Time: 6031.094727
Full example code
@name File Write and Read
@trigger none
@strict
fileWrite("test.txt", "Hello, World! " + curtime())
event fileWritten(Path:string, _:string) {
fileLoad(Path)
}
event fileLoaded(Path:string, Data:string) {
print(format("%s: %s \nTime: %f", Path, Data, curtime()))
}
File queuing
Important
These examples contain E2 functions that are only available on the Github release currently
Warning
The examples here will write files to your
e2files
directory. Make sure you're not overwriting anything important before trying these!
You can queue multiple file operations at once and they will be processed sequentially. By default, you can queue 5 operations of loading, writing, and listing each. Exceeding the limit will throw a runtime error. To demonstrate the queue, let's try creating a lot of files, listing them, and then opening them all.
We'll start by programmatically creating all the files in a directory for this example. We'll name the files as manyfiles/<number>.txt
and contain a simple generic message. We'll also use fileCanWrite
to see if we can still write files, and break early if we can't.
@name File Queues
@persist List:array
@trigger none
@strict
for(I = 1, 10) {
if(fileCanWrite()) {
fileWrite(format("manyfiles/%d.txt", I), format("This is file #%d!", I))
} else { break }
}
With that out of the way, let's get onto the events. The first one we'll register is the fileWritten
event. We'll use this to make sure we're done writing everything before listing. We can ignore the parameters for this and instead use fileWriteQueued()
, which returns the number of elements in the corresponding queue. We'll check if it's 0 to confirm the queue is empty, and then use fileList
on "manyfiles/"
to get all the files inside that directory. Note that the slash is mandatory.
event fileWritten(_:string, _:string) {
if(fileWriteQueued() == 0) {
fileList("manyfiles/")
}
}
After that, we'll register the fileList
event, which triggers when a list is received. Like files, lists are also networked, so they don't happen instantly. The first parameter is the directory path. The second parameter is an array of strings of all the files and subdirectories in the directory. We'll loop over this array and read each file inside the directory, making sure to not run into any queue errors. Note that the filenames in the array are relative, so we'll concatenate them to the directory path to get the full path.
Note that we naively assume there are no subdirectories here.
event fileList(Path:string, Contents:array) {
foreach(_:number, Name:string = Contents) {
if(fileCanLoad()) {
fileLoad(Path + Name)
} else { break }
}
}
Finally, we'll copy the code in the previous example using event fileLoaded
to print the contents of the file and its path, except modified to not include time.
event fileLoaded(Path:string, Data:string) {
print(format("%s: %s", Path, Data))
}
After running our code, you should see an output like this:
manyfiles/1.txt: This is file #1!
manyfiles/2.txt: This is file #2!
manyfiles/3.txt: This is file #3!
manyfiles/4.txt: This is file #4!
manyfiles/5.txt: This is file #5!
Note that the queue is not asynchronous, so the queue will always execute in the order that you loaded files.
Full example code
@name File Queues
@trigger none
@strict
for(I = 1, 10) {
if(fileCanWrite()) {
fileWrite(format("manyfiles/%d.txt", I), format("This is file #%d!", I))
} else { break }
}
event fileWritten(_:string, _:string) {
if(fileWriteQueued() == 0) {
fileList("manyfiles/")
}
}
event fileList(Path:string, Contents:array) {
foreach(_:number, Name:string = Contents) {
if(fileCanLoad()) {
fileLoad(Path + Name)
} else { break }
}
}
event fileLoaded(Path:string, Data:string) {
print(format("%s: %s", Path, Data))
}
Expression 2 ⚙️
Getting Started 🕊
- Syntax 🔣
- Directives 🎛️
- Editor 🖥️
- Ops 📊
Guides (In learning order) 🎓
- Learning & Getting Help 📚
- Triggers ⏲️
- Events 🎬
- Find Functions 🔍
- Physics 🚀
- EGP Basics 📈
- Lambdas λ
- Lambda Timers λ⏲️
- Tips & Tricks 📘
Tools 🛠️
Click To Expand
Advanced
- 🟥 SPU
- 🟥 Address Bus
- 🟥 Extended Bus
- 🟥 Plug/Socket
- 🟥 Port
- 🟥 Transfer Bus
- 🟩 GPU
- 🟥 Dynamic Memory
- 🟥 Flash EEPROM
- 🟥 ROM
Beacon 💡
- 🟧 Beacon Sensor
- 🟧 Locator
- 🟧 Target Finder
- 🟧 Waypoint
- 🟥 XYZ Beacon
Control 🎛️
- 🟩 CPU
- 🟩 Expression 2
- 🟩 Gates
- 🟥 PID
Data 💿
- 🟧 CD Disk
- 🟥 CD Ray
- 🟧 DHDD
- 🟥 Keycard
- 🟥 RAM-card
- 🟧 Satellite Dish
- 🟧 Store
- 🟧 Transferer
- 🟥 Wired Wirer
Detection 👀
- 🟧 Adv Entity Marker
- 🟧 Damage Detector
- 🟧 Entity Marker
- 🟧 GPS
- 🟧 Gyroscope
- 🟥 HighSpeed Ranger
- 🟧 Laser Pointer Receiver
- 🟥 Microphone
- 🟧 Ranger
- 🟧 Speedometer
- 🟧 Water Sensor
Display 💻
- 🟧 7 Segment Display
- 🟥 Adv. Hud Indicator
- 🟧 Console Screen
- 🟧 Control Panel
- 🟧 Digital Screen
- 🟧 EGP v3
- 🟧 Fix RenderTargets
- 🟥 GPULib Switcher
- 🟧 Hud Indicator
- 🟧 Indicator
- 🟧 Lamp
- 🟧 Light
- 🟧 Oscilloscope
- 🟧 Pixel
- 🟧 Screen
- 🟧 Sound Emitter
- 🟧 Text Screen
Render 🖌
- 🟩 Cam Controller
- 🟧 Colorer
- 🟧 FX Emitter
- 🟧 HighSpeed Holoemitter
- 🟧 HoloEmitter
- 🟧 HoloGrid
- 🟥 Interactable Holography Emitter
- 🟥 Materializer
- 🟥 Painter
I/O 🔌
- 🟧 Adv. Input
- 🟧 Button
- 🟧 Constant Value
- 🟥 Door Controller
- 🟧 Dual Input
- 🟧 Dynamic Button
- 🟧 Eye Pod
- 🟧 Graphics Tablet
- 🟧 Keyboard
- 🟥 Lever
- 🟧 Numpad
- 🟧 Numpad Input
- 🟧 Numpad Output
- 🟧 Plug
- 🟧 Pod Controller
- 🟧 Radio
- 🟧 Relay
- 🟧 Text Receiver
- 🟧 Two-way Radio
- 🟧 Vehicle Controller
Physics 🚀
- 🟥 Door
- 🟥 Adv. Dupe. Teleporter
- 🟥 Buoyancy
- 🟧 Clutch
- 🟧 Detonator
- 🟧 Explosives
- 🟧 Explosives (Simple)
- 🟥 Forcer
- 🟩 Freezer
- 🟧 Gimbal (Facer)
- 🟧 Grabber
- 🟧 Hoverball
- 🟧 Hoverdrive Controller
- 🟥 Hydraulic
- 🟧 Igniter
- 🟧 Nailer
- 🟩 Prop Spawner
- 🟥 Servo
- 🟥 Simple Servo
- 🟧 Thruster
- 🟥 Touchplate
- 🟥 Trail
- 🟩 Turret
- 🟩 User
- 🟥 Vector Thruster
- 🟥 Vehicle Exit Point
- 🟧 Weight (Adjustable)
- 🟧 Weld/Constraint Latch
- 🟥 Wheel
- 🟥 Wire Magnet
- 🟥 Wired Npc Controller
Utilities 🛠️
- 🟧 Debugger
- 🟥 GUI Wiring
- 🟥 Multi Wire
- 🟧 Namer
- 🟥 Simulate Data
- 🟩 Wiring
RFID 💳
- 🟥 Beam Reader
- 🟥 Implanter
- 🟥 Reader
- 🟥 Target Filter
- 🟥 User Reader
Wireless 🛜
Gates 🚥
Click To Expand
TBD
Extras 🔭
Please do not alter the e2 docs ...
pages manually.
They are autogenerated from the E2Helper. In the future, this will hopefully be its own dedicated website or tool.
Default Extensions
Basic Features: core, debug, number, selfaware,
string, timer
🌎 World: angle, color, find, ranger, sound,
🔣 Math: bitwise, complex, matrix, quaternion, vector, vector2/4
📦 Entities: bone, constraint, egp, entity, hologram, npc
👨 Players: chat, console, player, weapon
📊 Data storage: array, files, globalvars, serialization, table
💬 Communication: datasignal, http, signal, wirelink,
❓ Informational: gametick, serverinfo, steamidconv, unitconv
Additional Extensions
Disabled by default: constraintcore, effects, propcore, remoteupload, wiring
Wire-Extras (repo): camera, ftrace, holoanim, light, stcontrol, tracesystem