CNPCExtended-3.0.1-forge-1.20.1.jar
Curse Maven Snippet
What's new
# CNPC Extended 3.0.1 (Forge 1.20.1 and Fabric 1.21.1)
Security fixes. Script-facing behaviour is unchanged. Update both server and clients.
- A server could run any code on a player's PC: `runClientFunction` / `sendToClient` could call the client script
engine's built-ins (`eval`, `load`, `quit`). The server can now only call functions the player's own client scripts
define.
- A server could make `cnpc://` read any folder on a player's PC (the client trusted the folder path the server sent).
The client now ignores that path and only reads from disk for the world it is hosting itself.
- A page's events no longer reach its script once the page has been closed for 2 seconds (it was 30 s, so a modified
client could replay events into a closed page).
- Key codes from clients are limited to real key codes (any number used to grow a server-side map).
- **New: Fabric 1.21.1 build** with the same features as Forge (separate file on this project).
# CNPC Extended 3.0.0 (Forge 1.20.1)
## Upgrading
- Replace the old CNPCExtended jar with `CNPCExtended-3.0.0-forge-1.20.1.jar` on the server **and** every client. Old and new builds refuse to connect to each other (network protocol 3), instead of connecting and misreading packets as 1.x did.
- **MCEF is no longer a separate download.** It is bundled inside the jar, unmodified (LGPL notice in `META-INF/MCEF-NOTICE.txt`). Remove the standalone MCEF jar or leave it; Forge keeps whichever MCEF is newer. On first launch Chromium itself still downloads once into `mods/mcef-libraries`, as before.
- Existing scripts, pages, `config/cnpcextended-*.toml` files and `/cnpcext` commands work unchanged. No 1.x method was removed or changed; everything below is additive or a fix.
## Fixed
- **FPS dropping over time (browser leak).** 1.x only closed a page's Chromium browser when the player pressed Escape. Every `closeHtmlGui()` from a script, every GUI replaced by another GUI, and every screen that opened over a GUI left a live browser rendering in the background. Pages are now closed whenever their screen goes away, and a sweep closes anything orphaned.
- **"Loading browser..." and the 0.5–1 s open delay.** See *Faster opening* below. The text is gone; pages appear when fully drawn, with a small spinner only if a page takes longer than 400 ms.
- Events from a page reached the wrong script when a second page or an overlay from another script was opened. When one GUI replaced another, the old page's close notice ended the **new** page's session, so the new page's events were dropped.
- Page events larger than 32 KB kicked the player. They are now split and rejoined (limit `maxEventKB`, default 1 MB).
- Pages larger than about 1.5 MB failed to open (data: URL limit).
- `cnpc://` images, fonts, sounds and CSS only worked in singleplayer. They are now streamed from the server's scripts folder to every player (cached, unchanged files are not resent).
- Init data could close the `<script>` tag early (text containing `</script>` broke or injected into the page).
- A LAN guest could send client-bound packets that the host's game then ran (opening pages or calling client-script functions on the host). Each packet now only travels in its own direction.
- `syncScriptsPath()` sent the server's disk path to every player; it now only applies to the singleplayer/LAN host.
- `setGuiEscapable()` right after opening was lost if Chromium or the page was still loading.
- `hasOverlay()` stayed true after a page closed itself with `cnpc.close()`, and became false after the player respawned although the overlay was still shown. Key hold state was also lost on respawn.
- `isInGui()` / `getOpenScreen()` only updated when a key was pressed; screens opened by clicking (chests, NPC dialogs) went unnoticed.
- The last released key was reported again every tick (`clientKeyReleased` and a network packet every tick, forever).
- A page with `data-mc-slot` items kept drawing them after the elements were removed.
- One page script error in a `cnpc.onEvent` handler stopped the other handlers for that event.
- A client script function that throws every tick flooded the log; errors are now reported for the first 5 and every 1000th.
- Query answers (`queryKeybinds` etc.) were accepted from any player; now only from the player asked.
- Script commands vanished after `/reload`; deleted script commands still ran; loading N commands resent the command tree N times.
- `/cnpcext sync force` flipped the saved `overwriteExisting` setting on disk and back (left `true` after a crash). It now overrides for that run only, and reloads synced commands immediately.
- The global preloader and the command loader ran in random order at startup, so synced `commands.json` changes needed a second restart.
- `/cnpcext status` leaked a file handle; `/cnpcext version` showed 1.2.0.
- Cutscenes: mouse look was never blocked (the 1.x hook targeted a method that does not exist); starting a cutscene during another turned view bobbing off permanently; leaving a world mid-cutscene left the camera stuck and bobbing off; speed 0 or less never ended; a bad start keyframe crashed the client; the editor's preview played the same object being edited; per-keyframe logs spammed INFO.
- `hideHudElement("actionbar")` hid the title text instead of the action bar (it now hides both, so existing scripts see no loss).
- Skip-menu: a failing auto-load retried in an endless loop.
- (3.0.0 pre-release) Pages served from the https origin showed their source code as plain text: CEF passed `text/html; charset=utf-8` to Chromium unparsed. Pages are now served as `text/html` with a UTF-8 byte order mark.
- The MCEF offline-download fix crashed when the libraries path was unset.
## Faster opening (approach change)
| | 1.x | 3.0 |
|---|---|---|
| Page loading | base64 data: URL of the whole file, every open | served from memory at a per-server https origin (~2x faster for a 500 KB page, no size limit) |
| HTML over the network | whole file on every open (the Arvan menu is 500 KB) | once per login; later opens send a hash + init data |
| First open after launch | cold Chromium start (~490 ms) | Chromium pre-warmed at startup (~140 ms) |
| Showing | "Loading browser..." then a half-built first frame | shown once the page has run its scripts and painted |
| Reopening | new browser every time | opt-in keep-alive: `cnpc.onReopen(cb)` pages reopen in about one frame |
| Chromium message pump | extra pump for the GUI and for every overlay, every frame | one extra pump per frame |
| Reading the HTML file | read and copied on the server thread every open | cached until the file changes |
Pages served from the https origin also get `localStorage`, `crypto.subtle` and working relative links (`<img src="img/x.png">` loads from the page's own folder in the scripts directory). Set `httpsOrigin = false` in the client config to load pages as data: URLs like 1.x.
## Added: server script API
On `cnpcext` (every method taking `eventOrPlayer` accepts a CNPC event, an IPlayer or a ServerPlayer):
- `openHtmlGui(e, file)`, `openHtmlGui(e, file, json)`, `openHtmlGui(e, file, json, options)` — options: `{"width":0,"height":0,"escapable":true,"keepAlive":true}`.
- The returned handle: `handle.isOpen()`, `handle.send(event, json)` (only reaches that page, never a newer one), `handle.close()`, `handle.getId()`, plus the existing `setGuiEscapable`.
- `isHtmlGuiOpen(e)`, `closeHtmlGui(e)`, `sendToBrowser(e, event, json)`.
- `sendToOverlay(e, name, event, json)`, `setOverlayPosition(e, name, x, y)`, `setOverlaySize(e, name, w, h)`, `setOverlayInteractive(e, name, on)`, `isOverlayInteractive(e, name)`.
- `getClientBridge(e)` also accepts an IPlayer or event (no `getMCEntity()` needed).
On the client bridge: `isHtmlGuiOpen()`, `openHtmlGui(file, json, options)`, `sendToOverlay`, `setOverlayPosition`, `setOverlaySize`, `isOverlayInteractive`, `getOverlays()`, `sendJsonToClient(channel, json)`, `runClientFunction(name, json)`.
On `htmlGuiEvent(e)`: the 1.x fields are unchanged; new are `e.session`, `e.overlayName`, `e.requestId`, `e.isRequest()`, `e.isOverlay()`, `e.reply(value)` (JS object, array, JSON string or plain value), `e.replyError(message)`, `e.close()` (closes the page that sent the event, if it is still open). `e.player` is always the player's current entity, also after a respawn. `__guiClosed` data now says why: `{"reason":"player"}` or `{"reason":"replaced"}`.
Entity slots: `followCursor` (default true) is now honoured on every CustomNPCs build; 1.x could not pass it to builds such as GBPort 20260227, where entities always followed the cursor. An entity with `followCursor: false` can be spun by dragging it with the left mouse button (`"spin": false` turns that off).
Native slots: data sent to an open page (`sendToBrowser`, `handle.send`, `sendToOverlay`) that contains `overlayItems` / `overlayEntities` now sets those item/entity slots without reopening the page (other slots are kept; an entry with a slot and no item empties it).
HUD: new element names `title`, `bossbar`, `air`, `mounthealth`, `jumpbar`, `subtitles`, and any overlay by full id (`"minecraft:boss_event_progress"`, `"somemod:mana_bar"`). `"all"` hides the same set as 1.x.
## Added: for other mods
`com.cnpcextended.api.HtmlPageEvent.Message` and `.Closed` are posted on `MinecraftForge.EVENT_BUS` (server thread) before the script gets page traffic. Mods that open pages with `ClientBridgeAPI.openHtmlGui` handle them there (`getSource()`, `getName()`, `getData()`, `reply()`); cancelling keeps the event from the script. This replaces mixins into CNPCExtended internals, which 3.0 no longer matches.
## Added: page API (`window.cnpc`)
- `cnpc.request(name, data, timeoutMs)` → Promise, answered by `e.reply(...)` / `e.replyError(...)` in the script.
- `cnpc.onReopen(cb)` — opt into keep-alive; `cb(initData)` runs with the new data on each reopen. `park` / `reopen` events.
- `cnpc.holdReady()` / `cnpc.ready()` — keep the page hidden until async setup is done.
- `cnpc.offEvent(name[, cb])`, `cnpc.setEscapable(bool)`, `cnpc.playSound(id, volume, pitch)`, `cnpc.log(...)` (to the game log).
- `cnpc.version`, `cnpc.kind` (`"gui"`/`"overlay"`), `cnpc.name` (overlay name), `cnpc.session`.
- Events are sent at the end of the current task instead of on the next animation frame.
## New config
Server/common `cnpcextended-common.toml`, section `[htmlGui]`: `streamAssets` (true), `maxAssetKB` (16384), `scriptAssetFolders` (`web`, `gui`, `html`, `assets` — the only top-level folders `.js`/`.json` files are served from, so script sources and data never reach players), `maxEventKB` (1024).
Client `cnpcextended-client.toml`, section `[htmlGui]`: `keepAlivePages` (2), `keepAliveMinutes` (10), `httpsOrigin` (true), `prewarm` (true), `loadingIndicatorDelayMs` (400, -1 = never).
## Compatibility notes
- Everything a 1.x page or script could call still exists with the same signature and result. Checked against the 1.x jar: no public method, field or class that scripts reach was removed.
- Kept on purpose, although odd: `sendToBrowser(event, CompoundTag)` still sends numbers without type suffix and booleans as 0/1; init text that is not JSON is still passed through; the bridge is still placed after a bare `<head>` (moving it would switch some pages between quirks and standards mode); `cnpc.sendEvent(name, falsy)` still sends `{}`; GUI width/height are still ignored (full screen).
- `__guiClosed` still does not fire when a script closes the GUI or another (non-HTML) screen opens over it, as in 1.x; use `handle.isOpen()` / `isHtmlGuiOpen()` to check.
This mod has no additional files

