Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ jobs:
loaders: fabric
game-versions: '1.20.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.20.1-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.1 Fabric to Modrinth
Expand All @@ -127,6 +128,7 @@ jobs:
loaders: fabric
game-versions: '1.21.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.21.1-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.11 Fabric to Modrinth
Expand All @@ -142,6 +144,7 @@ jobs:
loaders: fabric
game-versions: '1.21.11'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.21.11-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.1 NeoForge to Modrinth
Expand Down Expand Up @@ -224,6 +227,7 @@ jobs:
loaders: fabric
game-versions: '1.20.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.20.1-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.1 Fabric to CurseForge
Expand All @@ -239,6 +243,7 @@ jobs:
loaders: fabric
game-versions: '1.21.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.21.1-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.11 Fabric to CurseForge
Expand All @@ -254,6 +259,7 @@ jobs:
loaders: fabric
game-versions: '1.21.11'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(embedded)
files: versions/1.21.11-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.1 NeoForge to CurseForge
Expand All @@ -269,6 +275,7 @@ jobs:
loaders: neoforge
game-versions: '1.21.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/1.21.1-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.11 NeoForge to CurseForge
Expand All @@ -284,6 +291,7 @@ jobs:
loaders: neoforge
game-versions: '1.21.11'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/1.21.11-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.2 NeoForge to CurseForge
Expand All @@ -299,6 +307,7 @@ jobs:
loaders: neoforge
game-versions: '26.2'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/26.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.1.2 NeoForge to CurseForge
Expand All @@ -314,6 +323,7 @@ jobs:
loaders: neoforge
game-versions: '26.1.2'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/26.1.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

# mc-publish can report success without actually creating a version (e.g.
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
# Changelog

## 1.8.0 - 2026-09-10

### Added
- **Custom death screen.** Set `deathScreenUrl` in `config/webgui/server.json` and the vanilla death screen is replaced by your page. Leave it empty and nothing changes — the feature is opt-in because replacing that screen takes away the player's only way to respawn.
- The page receives a `webgui:death` event describing what happened: `killer` (`{type: "player" | "mob" | "environment", name, uuid}`, plus `entityType` such as `minecraft:zombie` for mobs), the damage `cause`, the vanilla `deathMessage`, and `hardcore` / `canRespawn` flags.
- `window.webgui.respawn()` respawns the player, standing in for the vanilla Respawn button.
- Escape does not close the page, exactly as the vanilla screen refuses to close. If the page fails to load, Escape starts working again and respawns instead, so a broken page can never trap a player.
- The vanilla screen is left alone while the browser is still starting, so dying during the first seconds of a session shows the normal screen rather than nothing.
- **Version mismatches now say so.** The server introduces itself on join, and a client whose WebGUI speaks a different protocol gets a message naming both versions instead of watching pages quietly fail to open.
- **`requireClientMod`** in `config/webgui/server.json` (default `false`). When enabled, players without a compatible WebGUI are refused with a message that names this mod and the version the server runs.
- **`pageEventsPerSecond`** in `config/webgui/server.json` (default `20`, `0` disables). Caps how many `postToGame` messages one player's pages may send per second.
- **One JavaScript library: [`@webgui/client`](https://www.npmjs.com/package/@webgui/client).** Plain JS, React, Vue and Svelte in a single package with subpath imports (`@webgui/client/react` and so on). `@webgui/react`, `@webgui/vue` and `@webgui/svelte` were three parallel implementations of the same logic that had to be updated together for every new event; they still install and work, now as re-exports.
- The mod leaves the last death payload on `window.webgui.death`, the way it already did for `client` and `entity`, so a page whose bundle starts listening after the event has fired can still read it.
- **The server can host its own pages.** Drop files in `config/webgui/web/` and point any URL setting at them with `webgui:/index.html` — no web host, no domain, no port to open. They travel down the connection the player is already on, so it works behind NAT like everything else a server sends.
- Addressed by SHA-256: a client that already has a file never asks for it again, and a changed file is simply a different name, so a page can never be stale.
- The folder is created on first start with a working page in it, and `/webgui reload` picks up edits without a restart — everyone online is told about the new files, and a bundled page a player already has open is refreshed in place, so you can edit a file and watch the result.
- Limits, so a mistake here cannot take a server down: 8 MiB per file, 64 MiB in total, 2000 files, and `assetBytesPerSecond` (default 4 MiB/s per player).
- **External hosting is unchanged.** `http://` and `https://` URLs behave exactly as before, and the two mix freely.
- One thing to know: a bundled page is served from `http://127.0.0.1:25580`, not from your domain, so your API needs to allow that origin in CORS.
- `window.webgui.assetsBase` — where the server's own files are served from, so a page can build a URL to one without knowing the port.
- `serveBundledPages`, `bundledPagesDir` and `assetBytesPerSecond` in `config/webgui/server.json`.
- **`client.fov`** — the vertical field of view in degrees. A page already knew where the player was and which way they faced, and could read its own viewport, but not this; without it there was no way to turn a point in the world into a point on the screen. It is the setting, not the momentary value — the game stretches it while sprinting or under a speed effect.
- **`client.lookingAt`** — what the crosshair is on: `{type: "block", block, pos, face, distance}`, `{type: "entity", uuid, entityType, name, pos, distance}`, or `{type: "none"}`. This is the game's own answer, the one it uses for the block outline and the name above a mob, rather than a second ray cast with its own idea of reach. `type` is always there, so a page switches on it instead of testing for a field that comes and goes.
- **The mod has settings of its own, in the game's mod list.** NeoForge shows a **Config** button on WebGUI's entry; on Fabric it is Mod Menu's config button. Choices are saved as you make them, to `config/webgui/client.json`.
- **Page developer tools**, the first setting on that screen. With it on, what Chromium knows about the page goes into the game log: `console.*` calls with the file and line that made them, uncaught exceptions with where they were thrown, failed requests with their URL and status, and browser warnings — blocked mixed content, CORS refusals — that were previously invisible. A page in the game has no inspector, and until now a blank page left nothing to go on. Off by default and capped at 20 messages a second. It is not the DevTools window: that needs a remote debugging port the browser library does not open. See [Debugging a page](https://webgui.space/guide/debugging).
- **A file can be downloaded from a page.** Files land in `webgui-downloads/` under the game directory and the player is told the name. Previously CEF asked the host where to put a download, heard nothing, and threw it away — so an invoice or a CSV export was simply unclickable.

### Changed
- **A NeoForge server no longer refuses clients that lack WebGUI.** Its channels were registered as required, so anyone without the mod — or with an older build of it — was disconnected with *"Incompatible client! Please use NeoForge <version>"*, which blames the wrong mod. They now join and are told, in chat, what the server runs and what they are missing. Set `requireClientMod: true` to keep turning them away, with a message that actually explains why.

### Fixed
- **Fixed the death screen arriving late on NeoForge.** The page URL was pushed on join on Fabric but not on NeoForge, where the client only learned about it from the death packet itself.
- Fixed a page event flood from one player being able to saturate the server thread.
- **`/webgui reload` now applies every setting it claims to.** `trustedCommandOrigins` and `mainMenuUrl` are copies each connected client holds, and the reload never re-sent them: removing an origin from the trusted list, or changing the main menu page, quietly did nothing for anyone already online until they reconnected. Joining and reloading now push the same set through one path, so they cannot drift apart again.
- **Fixed `window.webgui` being undefined while a page was still loading.** The bridge was injected only after the document finished, so a plain inline script calling it threw `Cannot read properties of undefined`; only pages that waited for `DOMContentLoaded` or later ever worked.

### Known limitations
- **A second game client on the same machine gets no browser.** The browser library keeps one Chromium cache for the whole machine and locks it, so the second client to start finds it taken. Reported upstream; nothing WebGUI can do from its side.
- **`window.open` does nothing.** Pop-up windows are not supported; open pages through the mod instead.
- **On Fabric, the settings screen needs [Mod Menu](https://modrinth.com/mod/modmenu)**, since Fabric has no mod list of its own. Without it, `config/webgui/client.json` can be edited by hand.

## 1.7.0 - 2026-09-08

### Changed
Expand Down
17 changes: 16 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ if (sc_loader == "fabric") {
modImplementation "net.fabricmc:fabric-loader:${loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
include(modImplementation("maven.modrinth:rinku:${rinku_version}"))
// Compiled against, never shipped and never required: it is only needed to
// implement the entrypoint that puts a Config button in its list.
modCompileOnly("maven.modrinth:modmenu:${modmenu_version}")
}
} else {
configurations {
Expand All @@ -81,6 +84,10 @@ if (sc_loader == "fabric") {
into layout.projectDirectory.dir('run/mods')
}

def removeRinkuForServerRun = tasks.register('removeRinkuForServerRun', Delete) {
delete fileTree(layout.projectDirectory.dir('run/mods')) { include 'rinku*.jar' }
}

neoForge {
version = project.neoforge_version
// Register the mod so moddev's JUnit runtime can load it during tests.
Expand All @@ -107,6 +114,10 @@ if (sc_loader == "fabric") {
}
server {
server()
// Both dev runs share versions/<target>/run, so the jar dropped in
// for the client is also visible to the server — which is exactly
// what kills it. Take it back out before the server starts.
taskBefore(removeRinkuForServerRun)
}
}
}
Expand Down Expand Up @@ -210,8 +221,12 @@ processResources {
expand version: project.version, minecraft_range: project.minecraft_range
}
} else {
// Likewise, keep Fabric metadata out of the NeoForge jar.
// Likewise, keep Fabric metadata out of the NeoForge jar. The death-screen
// mixin goes with it: NeoForge replaces the screen through ScreenEvent
// instead, and the mixin targets Yarn's MinecraftClient, which does not
// exist under Mojang mappings.
exclude 'fabric.mod.json'
exclude 'webgui.fabric.mixins.json'
filesMatching('META-INF/neoforge.mods.toml') {
expand version: project.version, minecraft_range: project.minecraft_range
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx4G
org.gradle.parallel=true
dev.kikugie.stonecutter.hard_mode=true

mod_version=1.7.0
mod_version=1.8.0
maven_group=land.webgui
archives_base_name=webgui

Expand Down
Loading
Loading