Scripting reference (Markdown)
Full documentation in Markdown format. Use the formatted guide on Scripting for easier reading in the browser.
# Wsamiaw Scripting — Complete Guide
Wsamiaw includes a **Java-based** scripting system you can author and compile from inside the game. Each script appears as its own module under the ClickGUI **Scripts** category: you can toggle it, add settings, and subscribe to client events.
This guide covers the full API, file layout, compiler, Script Writer, and practical examples.
---
## Table of contents
1. [Requirements](#requirements)
2. [Where scripts live](#where-scripts-live)
3. [Quick start](#quick-start)
4. [Two authoring modes](#two-authoring-modes)
5. [Lifecycle](#lifecycle)
6. [Event hooks](#event-hooks)
7. [`host` API](#host-api)
8. [Settings (ClickGUI)](#settings-clickgui)
9. [Packets](#packets)
10. [Rendering (2D)](#rendering-2d)
11. [Utilities (`util`)](#utilities-util)
12. [Modules API](#modules-api)
13. [Commands](#commands)
14. [Script Writer](#script-writer)
15. [Compilation and errors](#compilation-and-errors)
16. [Example scripts](#example-scripts)
17. [Limits and security](#limits-and-security)
18. [Tips](#tips)
---
## Requirements
| Requirement | Details |
|-------------|---------|
| **Java compiler** | Scripts are compiled at runtime with `javac`. A full **JDK** (not JRE-only) is recommended. If the platform compiler is missing, the client falls back to bundled **ECJ** in the mod jar. |
| **Minecraft 1.8.9 + Forge** | The script API is tied to this client version. |
| **Trust** | Scripts are fully privileged: they can send packets, toggle modules, and use the full classpath. Only run code you trust. |
If no compiler is available, chat shows `Compiler error, JDK not found` and `.script load` will not compile scripts.
---
## Where scripts live
All scripts are stored here:
```text
.minecraft/config/Wsamiaw/scripts/
```
Each script is a **`.java`** file. The file name (without extension) becomes the script name and ClickGUI module name.
Example:
```text
config/Wsamiaw/scripts/PluginList.java
config/Wsamiaw/scripts/AutoGG.java
```
Compiled `.class` files are written to a temp folder (no manual edits needed):
```text
<java.io.tmpdir>/wsamiaw-scripts/
```
---
## Quick start
1. Join a world or server.
2. Chat: `.script create PluginList` — creates a template file.
3. Open **Script Writer** from ClickGUI (top-right **Script**) or `.script writer`.
4. Edit → **Save** (Ctrl+S) → **Compile / Reload** (Ctrl+R).
5. ClickGUI → **Scripts** → enable `PluginList`.
Default template:
```java
void onEnable() {
host.log("&aScript enabled");
}
void onDisable() {
host.log("&cScript disabled");
}
void onUpdate(UpdateEvent e) {
// per-update logic
}
```
Color codes use Minecraft chat formatting (`&a` green, `&c` red, `&7` gray, `&b` aqua).
---
## Two authoring modes
### 1) Snippet (recommended)
If the file does **not** contain `extends ScriptBase`, the engine wraps your code automatically:
- Generated class name: `sc_<fileName>_<hash>`
- Adds `host` and standard imports
- You only write method bodies (`void onEnable() { ... }`)
Auto-imports in snippet mode:
- `java.util.*`, `java.util.concurrent.*`, `java.awt.Color`
- `wsamiaw.script.ScriptBase`
- `wsamiaw.script.api.*`
- `wsamiaw.script.api.model.*`
- `wsamiaw.script.api.packet.*`
- `wsamiaw.events.*`
- `wsamiaw.event.types.EventType`
### 2) Full class
If the source contains `extends ScriptBase`, it is compiled as-is. Declare `public class MyScript extends ScriptBase`; the engine calls `bind(host)` after construction.
You must supply your own imports in full-class mode.
---
## Lifecycle
| Stage | When | Description |
|--------|------|-------------|
| **Compile** | `.script load`, game start, Writer reload | `ScriptCompiler` compiles source; on failure the script is not loaded. |
| **`onLoad`** | After successful load, module still off | Best place to register `host.settings`. |
| **Module on** | ClickGUI or `.script enable` | `onEnable` runs; `ScriptBridge` registers on the event bus. |
| **Running** | While enabled | `onUpdate`, `onPacket`, etc. |
| **`onDisable`** | Module turned off | Bridge unregistered; timers cleared. |
| **Reload** | Full script reload | Old modules removed; enabled state restored when possible. |
Hooks do **not** run while the script module is **disabled**.
---
## Event hooks
All hooks are **optional**. If a matching method exists, the engine invokes it via reflection. The script module must be **enabled**.
### Update and tick
| Method | Parameter | Description |
|--------|-----------|-------------|
| `onPreUpdate` | `UpdateEvent e` | Before rotation/update (`EventType.PRE`). |
| `onUpdate` | `UpdateEvent e` | Also called in PRE (with `onPreUpdate`). |
| `onPostUpdate` | `UpdateEvent e` | POST phase. |
| `onTick` | `TickEvent e` | Client tick; `host.util` timers tick here. |
Use `e.getType()` → `EventType.PRE` / `POST` on `UpdateEvent`.
### Rendering
| Method | Parameter | Description |
|--------|-----------|-------------|
| `onRender2D` | `Render2DEvent e` | HUD layer; draw with `e.getGraphics()`. |
| `onRender3D` | `Render3DEvent e` | World render pass. |
### Network
| Method | Parameter | Description |
|--------|-----------|-------------|
| `onPacket` | `ScriptPacketEvent e` | Inbound or outbound packet; `e.cancel()` to block. |
`e.outgoing()` / `e.incoming()`, `e.packet()` → `ScriptPacket` or subtypes (`MovePacket`, `SystemChatPacket`, …).
### Player and world
| Method | Parameter | Description |
|--------|-----------|-------------|
| `onAttack` | `AttackEvent e` | `e.getTarget()` is the attacked entity. |
| `onKey` | `KeyEvent e` | Key code; `host.settings` keybinds fire here too. |
| `onWorldLoad` | `LoadWorldEvent e` | World join/change. |
| `onDisconnect` | — | Disconnected from server. |
| `onScreen` | `Screen screen` | GUI open/change (`null` = closed). |
| `onScroll` | `int delta` | Mouse wheel; use `host.util.consumeScroll()` for accumulated delta. |
### Chat and anti-cheat
| Method | Parameter | Description |
|--------|-----------|-------------|
| `onChat` | `ClientboundSystemChatPacket packet` | Raw system chat packet. |
| `onAntiCheat` | `String flag` | Fired when AntiCheatDetector reports a flag. |
| `onAntiCheat` | `String flag, LocalPlayer player` | Two-argument overload is also tried. |
---
## `host` API
Scripts use the global `host` (`ScriptHost`). In snippets it is injected automatically; in full classes use `protected ScriptHost host` from `ScriptBase`.
### `host.log(String)` / `host.notify(String title, String message)`
- `log`: Formatted client chat message.
- `notify`: Toast notification; falls back to chat if notifications fail.
### `host.name()`
Script file name without `.java`.
---
### `host.player` — `PlayerApi`
| Method | Returns | Description |
|--------|---------|-------------|
| `present()` | `boolean` | Local player exists |
| `entity()` | `ScriptEntity` | Wrapped local player |
| `x()`, `y()`, `z()` | `double` | Position |
| `pos()` | `ScriptVec3` | Position vector |
| `yaw()`, `pitch()` | `float` | Look angles |
| `setYaw`, `setPitch` | — | Set look |
| `health()`, `maxHealth()` | `float` | Health |
| `onGround()` | `boolean` | On ground |
| `sprinting()`, `setSprinting` | | Sprint state |
| `motion()` | `ScriptVec3` | `deltaMovement` |
| `setMotion(x,y,z)` | — | Set velocity |
| `swing()` | — | Main-hand swing |
| `sendChat(String)` | — | Leading `/` sends command, else chat |
| `clientMessage(String)` | — | Client-only chat |
| `attackStrength()` | `float` | 1.9+ attack cooldown scale |
---
### `host.world` — `WorldApi`
| Method | Returns | Description |
|--------|---------|-------------|
| `present()` | `boolean` | Level loaded |
| `entities()` | `List<ScriptEntity>` | Entities in render list |
| `players()` | `List<ScriptEntity>` | Players |
| `living()` | `List<ScriptEntity>` | Living entities |
| `blockAt(x,y,z)` | `ScriptBlock` | Block id / air check |
| `dimension()` | `String` | Dimension id (`minecraft:overworld`, …) |
#### `ScriptEntity`
`id()`, `name()`, `pos()`, `health()`, `player()`, `living()`, `distanceTo(other)`, `raw()` → Minecraft `Entity`.
#### `ScriptBlock`
`x,y,z`, `id()` (e.g. `minecraft:stone`), `air()`, `state()`, `pos()`.
#### `ScriptVec3`
Fields `x`, `y`, `z`; constant `ScriptVec3.ZERO`.
---
### `host.modules` — `ModulesApi`
Names match ClickGUI module names (see `Module.getName()`).
| Method | Description |
|--------|-------------|
| `get("KillAura")` | `Module` or `null` |
| `isEnabled("Scaffold")` | Enabled state |
| `setEnabled("Velocity", true)` | Enable/disable |
| `toggle("Blink")` | Toggle |
| `getValue("KillAura", "range")` | Property value |
| `setValue("Reach", "range", 3.5f)` | Set property (types must match) |
Property names are the internal property keys (e.g. `min-cps`, `mode`).
---
### `host.settings` — `SettingsApi`
ClickGUI settings owned by the script module. Create them in **`onLoad`**:
```java
BooleanProperty debug;
FloatProperty delay;
void onLoad() {
debug = host.settings.toggle("debug", false);
delay = host.settings.slider("delay-ms", 500f, 0f, 5000f);
host.settings.mode("mode", 0, "A", "B", "C");
host.settings.key("bind", 0);
host.settings.keybind(org.lwjgl.glfw.GLFW.GLFW_KEY_R, key -> host.log("&eR"));
}
```
| Method | Returns |
|--------|---------|
| `slider(name, def, min, max)` | `FloatProperty` |
| `toggle(name, def)` | `BooleanProperty` |
| `mode(name, defIndex, modes...)` | `ModeProperty` |
| `key(name, defKey)` | `KeyProperty` |
| `keybind(keyCode, IntConsumer)` | Fires while script is enabled |
---
### `host.packets` — `PacketsApi`
| Method | Description |
|--------|-------------|
| `send(Packet)` | Normal send (packet events run) |
| `sendNoEvent(Packet)` | Bypass client packet event |
| `send(ScriptPacket)` | Wrapped packet or `ChatPacket` helper |
| `wrap(packet, outgoing)` | Convert to `ScriptPacket` |
**Builders:**
| Method | Description |
|--------|-------------|
| `move(onGround)` | Ground flag only |
| `move(x,y,z,onGround)` | Position |
| `move(x,y,z,yaw,pitch,onGround)` | Position + look |
| `look(yaw,pitch,onGround)` | Look only |
| `swing()` | Main-hand swing |
| `chat(String)` | Chat/command helper |
| `attack(entityId)` | `AttackPacket` |
**Outbound wrappers:** `MovePacket`, `AttackPacket`, `InteractPacket`, `SwingPacket`, `ChatPacket`, `DigPacket`, `PlacePacket`, `HotbarPacket`, `PlayerCommandPacket`, `ClickSlotPacket`, `CloseScreenPacket`.
**Inbound wrappers:** `SystemChatPacket` (`text()`, `overlay()`).
`MovePacket`: `x()`, `y()`, `z()`, `yaw()`, `pitch()`, `onGround()`.
**Listening example:**
```java
void onPacket(ScriptPacketEvent e) {
if (e.incoming() && e.packet() instanceof SystemChatPacket chat) {
host.log("&7[chat] " + chat.text());
}
if (e.outgoing() && e.packet() instanceof MovePacket move) {
// move.onGround() ...
}
// e.cancel();
}
```
---
### `host.render` — `RenderApi`
Inside `onRender2D`:
```java
void onRender2D(Render2DEvent e) {
var gfx = e.getGraphics();
host.render.rect(gfx, 10, 10, 120, 30, 0x88000000);
host.render.outline(gfx, 10, 10, 120, 30, 1f, 0xFFFFFFFF);
host.render.text(gfx, "Hello", 14, 18, 0xFFFFFFFF);
}
```
Overload `rect(..., Color)` is also available.
---
### `host.util` — `UtilApi`
| Method | Description |
|--------|-------------|
| `randomInt(min, max)` | Inclusive int |
| `randomFloat(min, max)` | Float |
| `distance(x1,y1,z1,x2,y2,z2)` | 3D distance |
| `setInterval(Runnable, periodMs)` | Repeating timer; returns id |
| `setTimeout(Runnable, delayMs)` | One-shot timer |
| `clearInterval(id)` | Cancel timer |
| `addScroll` / `consumeScroll` | Wheel accumulation |
Timers run on client tick while the script is enabled; cleared on disable.
---
## Settings (ClickGUI)
1. Define properties in `onLoad` with `host.settings.*`.
2. Reload scripts so properties register.
3. Open ClickGUI → **Scripts** → your script → settings panel.
Module keybinds and config persist under `config/Wsamiaw/` like other modules.
---
## Packets
Scripts are **client-side** only. Sending packets is subject to server rules and anti-cheat.
- `send` — other modules (Velocity, Blink, …) still see the packet.
- `sendNoEvent` — skip your own handlers; use carefully.
- `onPacket` + `cancel()` — block the packet entirely.
---
## Rendering (2D)
The official script surface for drawing is `host.render` on `Render2DEvent`. Use `onRender3D` for world-space visuals (advanced).
---
## Modules API
Scripts may enable or configure other modules (useful on private test servers; risky on public servers).
```java
void onEnable() {
if (!host.modules.isEnabled("KillAura")) {
host.modules.setEnabled("KillAura", true);
}
}
```
---
## Commands
Chat prefix depends on client config (often `.`).
| Command | Description |
|---------|-------------|
| `.script` / `.scripts` / `.sc` | Short help |
| `.script list` | Loaded scripts and ON/OFF |
| `.script load` / `.reload` | Recompile and load from folder |
| `.script create <name>` | New `.java` template |
| `.script folder` | Open scripts folder in file manager |
| `.script writer` / `.edit` / `.ide` | Script Writer screen |
| `.script enable <name>` | Enable module |
| `.script disable <name>` | Disable module |
---
## Script Writer
ClickGUI top-right: **Script** next to **HUD** / **Theme**, or chat: `.script writer` / `.edit` / `.ide`.
### Layout
- **Sidebar** — all `*.java` files in your scripts folder; click to open.
- **Editor** — line numbers, Java syntax highlighting (including script hooks and `host`), selection, caret.
- **Toolbar** — rounded action buttons (see below).
- **Optional panels** — **Snippets** (insert templates), **Errors** (compile diagnostics for the open file).
- **Status bar** — save/compile status, line/column, keyboard hints.
### Toolbar actions
| Button | Action |
|--------|--------|
| **New** | Create a new script (name prompt). |
| **Save** | Write the open file to `config/Wsamiaw/scripts/`. |
| **Compile** | Save if dirty, recompile every script, refresh ClickGUI **Scripts** list. |
| **Find** | Search with match highlighting and prev/next. |
| **Snippets** | Toggle panel: `onPacket`, `onRender2D`, `host.settings`, packet cancel, timers, … |
| **Duplicate** | Copy current file to `name_copy.java`. |
| **Rename** | Rename the open script file. |
| **Delete** | Delete the open script file. |
| **Errors** | Show compile errors; click a message to jump to that line. |
| **Close** | Return to the previous screen (unsaved changes are saved). |
### Keyboard shortcuts
| Shortcut | Action |
|----------|--------|
| **Ctrl+S** | Save |
| **Ctrl+R** | Compile / reload all scripts |
| **Ctrl+F** | Find |
| **Ctrl+G** | Go to line |
| **Ctrl+Z** / **Ctrl+Y** | Undo / redo (64 steps) |
| **Ctrl+/** | Toggle `//` line comment |
| **Ctrl+A, C, X, V** | Select all, copy, cut, paste |
| **Tab** | Insert four spaces |
| **Enter** | New line with indent preserved; extra indent after `{` |
| **Esc** | Close find bar or exit Writer |
After a successful compile, enabled scripts stay on when possible; failed scripts are not loaded.
---
## Compilation and errors
1. **Syntax errors** — Writer or chat shows line numbers (snippet mode adjusts for wrapper offset).
2. **`must extend ScriptBase`** — Full class does not extend `ScriptBase` or instance creation failed.
3. **Runtime** — Exception in `onEnable` etc.; chat shows script name and approximate line.
Scripts that fail to compile are **not** loaded.
**Check JDK:**
```bash
java -version
javac -version
```
Launching Minecraft with a JDK is the most reliable setup.
---
## Example scripts
### A) Request plugin list via chat command
Some servers print `/plugins` output to chat; behavior varies by server.
```java
boolean waiting;
void onEnable() {
waiting = true;
host.player.sendChat("/plugins");
}
void onChat(ClientboundSystemChatPacket packet) {
if (!waiting) return;
String text = packet.content().getString();
host.log("&6--- Plugins ---");
host.log("&f" + text);
waiting = false;
}
```
### B) Filter system chat
```java
void onPacket(ScriptPacketEvent e) {
if (!e.incoming()) return;
if (e.packet() instanceof SystemChatPacket chat) {
String t = chat.text().toLowerCase();
if (t.contains("cheat") || t.contains("hack")) {
host.notify("Chat", t);
}
}
}
```
### C) Interval chat message with slider setting
```java
FloatProperty intervalSec;
int timerId;
void onLoad() {
intervalSec = host.settings.slider("interval-sec", 30f, 5f, 300f);
}
void onEnable() {
schedule();
}
void onDisable() {
if (timerId != 0) host.util.clearInterval(timerId);
}
void schedule() {
long ms = (long) (intervalSec.getValue() * 1000f);
timerId = host.util.setInterval(() -> {
if (host.player.present()) {
host.player.sendChat("test");
}
host.util.clearInterval(timerId);
schedule();
}, ms);
}
```
### D) Module status HUD
```java
void onRender2D(Render2DEvent e) {
int y = 4;
for (String mod : new String[] { "KillAura", "Scaffold", "Velocity" }) {
boolean on = host.modules.isEnabled(mod);
String line = mod + ": " + (on ? "ON" : "OFF");
int col = on ? 0xFF55FF55 : 0xFFFF5555;
host.render.text(e.getGraphics(), line, 4, y, col);
y += 10;
}
}
```
### E) Anti-cheat flag log
```java
void onAntiCheat(String flag) {
host.log("&c[AC] &f" + flag);
host.notify("AntiCheat", flag);
}
```
### F) Full class example
```java
import wsamiaw.script.ScriptBase;
import wsamiaw.events.TickEvent;
public class MyFullScript extends ScriptBase {
@Override
public void onEnable() {
host.log("&aFull class script");
}
void onTick(TickEvent e) {
// ...
}
}
```
File name must match the public class: `MyFullScript.java`.
---
## Limits and security
| Topic | Status |
|-------|--------|
| JavaScript / Lua | Not supported — Java only |
| Sandbox | None — scripts are trusted user code |
| Downloading scripts from the web | Not built-in — local folder only |
| Legacy Raven API | Removed — no `ScriptDefaults` or old packet nicknames |
| Threading | Timers run on client thread; heavy work hurts FPS |
Use on servers you are allowed to test on; respect server rules.
---
## Tips
1. **`onLoad` vs `onEnable`:** Register settings in `onLoad`; do heavy setup in `onEnable`.
2. **Null checks:** Use `host.player.present()` and `host.world.present()`.
3. **Reload:** Renaming a file creates a new module; old config keys may linger.
4. **Performance:** Avoid heavy work in `onPacket`; debounce with flags + tick.
5. **Debugging:** Add `host.settings.toggle("debug", true)` and gate `host.log` calls.
6. **ClickGUI:** Compile errors prevent the module from appearing under **Scripts**.
---
## Flow summary
```text
.java file → ScriptEngine.loadScripts()
→ compile (javac/ECJ)
→ ScriptBase instance + ScriptHost
→ ScriptModule (ClickGUI)
→ user enables → ScriptBridge → onEnable / onPacket / ...
```
For help, see the Discord link in the main README.
*Document version: Wsamiaw — Forge 1.8.9*