Skip to main content

EternalTD Content Packages

EternalTD now tracks official content through a content_packages config set and exposes those packages through /etd setup.

Package Categories

The current code uses three package categories:

  • FREE
  • PREMIUM
  • RESOURCES

The setup menu currently exposes those as:

  • Free Content
  • Premium Packs
  • Resources

Verified Premade Packages

These are the premade packages currently defined in the repo:

PackageCategoryToggleable in /etd setupTracked assets
EternalTD Hub WorldFreeNoServer world-container folder etd_spawn
EternalTD TutorialFreeYestutorial.yml, tutorial_waves.yml, tutorial_npc.yml, etd_tutorial
Towers of the Grassy LandsFreeYes5 level files, 1 waves file, 1 NPC file, 5 worlds
Towers from the DepthsPremiumYes5 level files, 1 waves file, 1 NPC file, 5 worlds
Towers of the Rising SunPremiumYes5 level files, 1 waves file, 1 NPC file, 5 worlds
EternalTD Custom ModelsResourcesNoMarker file only, plus imported FreeMinecraftModels content when present

Package Lifecycle

The package browser currently distinguishes between:

  • not downloaded
  • not installed
  • installed
  • partially installed
  • out of date and updatable
  • out of date but inaccessible
  • needs access

That state is computed from tracked assets on disk, isEnabled flags inside tracked config files, and Nightbreak access/update checks.

Two detection rules matter when a package looks stuck on "partially installed":

  • World-container folders are matched at both layouts. Paper 26.1 and newer migrate plugin worlds into <level-name>/dimensions/minecraft/<world>. EternalTD counts a world-container folder as present if it exists at either the legacy root or the migrated location, and it deliberately checks for the folder, not for level.dat — requiring level.dat would flip the package to "not installed" during a partial migration and trigger a re-install that Paper then refuses to merge.
  • Marker-tracked packages have a content fallback. A package tracked only by a marker file can also be detected by the presence of its content folders under plugins/. When that happens the marker is written immediately so the state stays stable afterwards. This is what makes the custom models pack read as installed when its models were imported by hand instead of through the menu. The fallback folder list is defined in code, not read from the package's YAML.

Toggleable vs Shared Packages

Toggleable packages work by flipping isEnabled inside tracked config files under:

plugins/EternalTD/levels/
plugins/EternalTD/waves/
plugins/EternalTD/npcs/

Shared packages do not behave like normal toggles:

  • The hub world is treated as shared installed content.
  • The custom model pack is treated as shared resource content.

For those packages, the setup menu tells you to remove files manually and then run /etd reload.

Bulk Operations

The bulk content operations currently implemented are:

  • /etd downloadall — downloads the EternalTD plugin update and all available content
  • /etd downloadallcontent — downloads all available content (no plugin update)
  • /etd updatecontent (alias /etd updateallcontent) — downloads only outdated content

The content download/update commands:

  • require a linked Nightbreak token
  • download into plugins/EternalTD/imports
  • skip packages that are inaccessible or already current
  • reload EternalTD automatically after successful downloads

/etd downloadall additionally checks for and downloads a plugin update first; if no token is linked or authentication fails it stops before the content step.

Practical Notes

  • Package checks deduplicate by Nightbreak slug before bulk download/update.
  • The setup UI refreshes content and access info on a cooldown instead of hitting Nightbreak on every open.
  • The custom models package writes a marker under plugins/EternalTD/content_markers/ so EternalTD can track that the shared resource package was downloaded.
  • Tracked level, wave, and NPC files are matched by filename anywhere beneath levels/, waves/, and npcs/, so packages that ship their files in a subfolder are still detected.
  • Towers of the Rising Sun previously tracked its wave file as towers_of_the_rising_sun.yml while the pack actually ships towers_of_the_rising_sun_waves.yml, which left it permanently reading as not fully installed. The tracked name is now corrected automatically and written back to the package config on load — no manual fix needed.