promotional bannermobile promotional banner

Wave Defense

A versatile PvE and PvP engine featuring wave defense, customizable shops, and three competitive game modes for Minecraft
Back to Files

wavedefense-0.7.2.jar

File namewavedefense-0.7.2.jar
Uploader
Rayman_GCRayman_GC
Uploaded
Aug 10, 2026
Downloads
7
Size
1.3 MB
Mod Loaders
Forge
File ID
8620240
Type
R
Release
Supported game versions
  • 1.20.1

Curse Maven Snippet

Forge

implementation fg.deobf("curse.maven:wave-defense-1492909:8620240")

Learn more about Curse Maven

What's new

Changelog

[0.7.2] - 2026-08-11 — one scroll implementation

Eleven screens kept their own scroll state next to two base classes that already provided it. That is not only duplication: each copy had drifted, and the drift was the bug.

Six screens computed how many rows fit twice, differently — once when laying rows out and once when handling the wheel — so the wheel ran past the end of the list. One drew a divider at y=100 above a list starting at 116. One placed its ▼ button at a fixed offset that assumed exactly five rows fit, putting the arrow in the middle of the list on a tall window. One drew item icons two pixels below their own rows. StartingItemsScreen had reimplemented the base class's three-pass scissor render and picked up two faults doing it: a ▼ button hardcoded off the bottom of a short window, and widgets straddling the list edge satisfying both passes and drawing twice.

Two screens now use ScrollableScreen directly rather than ListEditorScreen, because they show several mutually exclusive lists of different types. Both had one scroll offset per list where the lists are never on screen together — so two page counts, two clamps and two branches in mouseScrolled for what is always "the list currently shown".

ImportExportScreen had a real trap: two sections, only the second scrolling. The list of locations to export grew without bound, so past about a dozen arenas the import half was pushed off the bottom and became unreachable — the scroll applied only to the part you could no longer see. It is now one list of mixed rows.

Fixed

  • Mouse wheel now works on the four screens that had scroll state but no mouseScrolled
  • Row counts, clip bounds and scroll-button anchors are computed once per screen, not two or three times with different answers
  • ShopImportScreen never released its static listing callback, keeping the closed screen alive and rebuilding widgets on it when a late packet arrived
  • Deleting the last entries no longer leaves the view scrolled past the end
  • Backups being disabled no longer writes last_state.json into a directory that was deliberately not created, logging an error on every server stop

Added

  • ScrollableScreen reports, once per screen class, any non-static widget lying outside the scroll band. Pass 1 draws non-static widgets inside the band and passes 2 and 3 draw static ones outside it, so such a widget is drawn by nothing and its clicks are discarded — silently. This caught two screens of my own making where the mode tabs and the entire footer had become invisible.

Notes

  • No protocol change (still version 14); test suite unchanged at 128

[0.7.1] - 2026-08-10 — two races, both quiet

An audit of the whole mod turned these up. Neither shows in testing; both bite in production.

The backup system read live server state from its own thread. It runs on a private scheduler and called locationManager.save()waveManager.save() and — the sharp one — player.saveWithoutId() on live player entities, while the tick loop was moving them and changing their inventories. There was not one server.execute in the file. The result was a race that either threw or wrote a torn snapshot: a backup that looks fine until the day you need it.

It now captures first and writes second. Every read of live state happens on the server thread and produces plain NBT in memory; the disk work then runs off-thread against that copy. Restoring is the mirror image — read the files anywhere, apply them to the world on the server thread — which matters more, because restoring writes into the live world.

Ten of thirteen client caches were never cleared on disconnect. Each is a few static fields keyed by nothing, so they followed the player to the next server: the previous world's arenas still listed in the hub, its statistics on the stats screen, its teammates in the HUD, and half an interrupted shop upload still aimed at a location that no longer existed. ClientShopUploadQueue even had a cancel() whose javadoc said "used when the player disconnects" — nothing called it.

Fixed

  • Backup and restore no longer touch live server state off the server thread
  • updateLastKnownState hashes live locations and players on the server thread too
  • All thirteen client caches are cleared on disconnect, not three
  • ClientShopUploadQueue.cancel() now also resets the shop-point target, which otherwise filed the next global upload into a point from the previous server

Added

  • BackupThreadingTest — fails if any live-state read escapes a capture block, and if the two helpers reached indirectly stop declaring the precondition
  • ClientCacheCoverageTest — a new gui/Client* cache fails the build until it is wired into the disconnect handler, or listed as deliberately exempt
  • requireServerThread() reports a wrong-thread caller in the log instead of racing silently

Notes

  • No protocol change (still version 14)
  • Test suite: 128 tests

[0.7.0] - 2026-08-10 — the hub

The location menu listed names. Choosing between three arenas meant joining one to find out whether anybody was in it, and if the answer was no, leaving again.

Each row now carries what is actually happening there: how many players are inside, whether the arena is empty, gathering in the lobby, mid-match or finishing, and which wave or round it has reached. A search box appears once there are enough locations to need one, and the Join button greys out on a full arena instead of letting a player click and be refused.

The status arrives on its own small packet, refreshed every two seconds while the hub is open — the full location tree is far too heavy to resend on a timer, and it does not carry live state anyway. Nothing about the way in changed: the hub sends the same TeleportPacket the menu always did, so it inherits the rate limit, the player cap, the PvP spawn choice, team auto-balance and Battle Royale's random spawn. A second join path is exactly how the player cap once came to live in one entry point while the portal and the activation zone walked past it.

A row also says when a location cannot be entered at all — no waves, no spawn point, a PvP arena with fewer than two team spawns — instead of letting a player click and be told by the server. The check is deliberately narrow: it reports only what the server would certainly refuse, because a false "not ready" locks someone out of a working arena while a missed one costs a click.

Added

  • Live per-location status in the hub: players, phase, current wave or round
  • Search box in the hub, shown once a server has 8 or more locations
  • Sort by state, players or name — state first, since "where can I get into a game" is the question a player actually has
  • Rows name the reason a location cannot be joined, and the Join button greys out with it as a tooltip
  • The row you are standing in is marked, and the footer offers Leave — the hub says you must leave before joining elsewhere, so it should be where you can
  • LocationStatus + RequestHubStatusPacket / HubStatusPacket — a few dozen bytes a row
  • ClientHubStatus, cleared on logout so the next server does not inherit stale rows

Changed

  • Hub rows are taller and split into a name line and a status line
  • Join is now its own button; the whole row is no longer a click target that teleports you

Fixed

  • The hub's search box was drawn at y=30, overlapping the header panel that ends at y=31
  • With no search box the list still started as if there were one, wasting a row of height on the servers least likely to have space to spare
  • The hub no longer claims "you are already here" after a match ends underneath it

Notes

  • Protocol version 14 — client and server must be updated together
  • Twenty new lang keys across all 8 locales (1599 each, parity checked)
  • Test suite: 123 tests
  • The lobby / match customizer is a separate piece and is not in this release
  • Compile targets unchanged: Forge 47.2.0, Minecraft 1.20.1, Java 17, official mappings

[0.6.1] - 2026-08-09 — import/export works again, backups stop shouting

Two things that were quietly wrong.

Import and export were refused on any non-ASCII installation path. The containment guard that keeps a client-supplied filename inside the export directory compared canonical path strings. On a Windows profile named in Cyrillic — C:\Users\Руслан\… — the JDK spelled the same parent directory two different ways depending on whether it was resolving the directory or a file inside it, so the prefix test failed for every legitimate path and every import and export was rejected. The guard now compares normalised Paths element by element, which cannot disagree with itself that way, and closes the sibling-prefix bypass by construction rather than by remembering to append a separator.

Backups ran hourly and kept a week of them. Every value was hardcoded: a snapshot every 60 minutes, 24 full and 168 incremental copies retained. The mod's data lives inside the world folder, so any server that backs the world up was already covering it — this was duplicating that work and filling the disk doing it. There is now a [backup] section in wavedefense-common.toml, and it ships disabled. Turned on, the defaults are one snapshot every 6 hours keeping 3 full and 12 incremental, plus one write at shutdown.

Fixed

  • FilePathGuard.isInside rejected every path on installations whose path Java cannot round- trip through sun.jnu.encoding, breaking all six import/export packets
  • Backup scheduler no longer starts, and creates no directories, when backups are off

Changed

  • New [backup] config section: enabled (default false), intervalMinutes (360), maxFullBackups (3), maxIncrementalBackups (12), backupOnShutdown (true)
  • A shutdown snapshot is written after all saves have flushed, so it captures final state

Known gap

The backup subsystem has no command to trigger or restore a backup — it is scheduler-driven only. Left as is while the feature ships off by default.

Upgrading: no protocol change (still version 13). Compile targets unchanged — Forge 47.2.0, Minecraft 1.20.1, Java 17, official mappings.

This mod has no additional files