Scripting reference (Markdown)

Full documentation in Markdown format. Use the formatted guide on Scripting for easier reading in the browser.

← Formatted guide
# 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*