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
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,55 @@ way to 1.0.0; see [docs/ROADMAP.md](docs/ROADMAP.md).

## [Unreleased]

## [1.1.0] - 2026-11-07

The first full release since 1.0.0, on Forge, NeoForge and Fabric for Minecraft 26.3, 26.2, 26.1, 1.21.11,
1.21.5, 1.21.1 and 1.20.6: 21 jars, one per loader and version. The details of everything below are in the
beta sections that follow. Players and servers need the same version. The network protocol is the same as
in 1.1.0-beta.8 and later (11).

### Before you update

Back up your world. Scripted clients ran on every loader and version during development and dedicated
servers start on all of them, but only the Forge 26.3 jar has been started from a launcher profile, and
nobody has played the released jars yet. Testing happens on this release, and fixes go into 1.1.1. Please
report what you find on [GitHub](https://github.com/JnH-Projects/MCHeli-Rework-Forge/issues) with your
`logs/latest.log`.

### Installing

This jar contains only the mod's code. The vehicles, models, textures and sounds are EMB4's original
MCHeli content, which you download yourself:

1. Install Forge, NeoForge or Fabric for your Minecraft version. On Fabric, also install Fabric API.
2. Put `mcheli-<loader>-<minecraft>-1.1.0.jar` in the `mods` folder.
3. Download `MC1.7.10_mcheli_1.0.3.zip` from the
[MCHeli CurseForge page, Files tab](https://www.curseforge.com/minecraft/mc-mods/mcheli-minecraft-helicopter-mod/files).
4. Create a folder called `mcheli` next to `mods` and put the zip in it. Do not unzip it.
5. Start the game. The first start converts the zip, which takes a few seconds.

### Added since 1.0.0

- NeoForge and Fabric next to Forge, and six more Minecraft versions next to 26.3.
- Vehicle workshop: build a vehicle in game from a Blockbench or Blender model, with its own textures and
sounds, and send it to a server for its operators to approve.
- Content packs, sent to players when they join a server.
- Fuel, the vehicle screen, cargo and supply vehicles.
- The rest of the original's equipment, including the thermal view, UAV stations, the drafting table and
the team manager.
- Night glow on tracers, rocket motors, flares and explosions, and wrecks that keep burning for 30 seconds.
- Server settings in `serverconfig/mcheli-server.toml`, and `/mcheli` to list, give and reload vehicles.

### Changed

- 1.20.2 and 1.19.4 are not part of this release.

### Fixed

- Drafting table: the recipe position ("1 / 35") ran into the top row of the inventory and the "Inventory"
title crossed the panel's border, on every Minecraft version. The position now sits between narrower `<<`
and `>>` buttons, and the title sits above the panel.

## [1.1.0-beta.9] - 2026-11-07

Phase 13 of the road to 1.1.0: every loader on every supported version. This beta ships 21 jars, one per
Expand Down Expand Up @@ -760,6 +809,7 @@ Phase 1: foundation and flyable helicopters.
- Free look moved from Left Ctrl to Left Alt, because Left Ctrl is now the vanilla sprint key.
- Roll damping runs per tick instead of per frame, so handling no longer depends on frame rate.

[1.1.0]: https://github.com/JnH-Projects/MCHeli-Rework-Forge/releases/tag/v1.1.0
[1.1.0-beta.9]: https://github.com/JnH-Projects/MCHeli-Rework-Forge/releases/tag/v1.1.0-beta.9
[1.1.0-beta.8.1]: https://github.com/JnH-Projects/MCHeli-Rework-Forge/releases/tag/v1.1.0-beta.8.1
[1.1.0-beta.8]: https://github.com/JnH-Projects/MCHeli-Rework-Forge/releases/tag/v1.1.0-beta.8
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ MCHeli Rework is a ground-up port of MCHeli 1.0.3, a mod that stopped at Minecra
system is rewritten for the modern game, while the original vehicle definitions, models,
textures and sounds load unchanged.

> **Status:** on the way to 1.1.0, now at phase 13 (`1.1.0-beta.9`). Every helicopter, plane,
> **Status:** `1.1.0` is the current release. Every helicopter, plane,
> tank, car and ground vehicle can be placed, crewed and driven with the original handling, all
> 229 weapons fire, and the scripted HUDs, fuel, the vehicle screen and all of the original's
> equipment are in, down to UAV stations, the drafting table and the team manager. The vehicle
> workshop builds new vehicles in game from a Blockbench or Blender model, with their own textures
> and sounds, and sends them to a server for its operators to approve. From `1.1.0-beta.9` on,
> every jar ships: Forge, NeoForge and Fabric for every version from 1.20.6 to 26.3 (see
> [supported versions](docs/ROADMAP.md#supported-versions)). See the [roadmap](docs/ROADMAP.md).
> and sounds, and sends them to a server for its operators to approve. Every jar ships: Forge,
> NeoForge and Fabric for every version from 1.20.6 to 26.3 (see
> [supported versions](docs/ROADMAP.md#supported-versions)). Testers are playing these jars for the
> first time on this release, and fixes go into 1.1.1. See the [roadmap](docs/ROADMAP.md).

## Showcase video

Expand Down Expand Up @@ -63,7 +64,8 @@ mod does not ship it: on first start it converts the player's own copy of the or
to the modern resource layout. This repository holds none of it either; the unit tests import
the same zip.

The rework is by **JayMar921** ([JnH Projects](https://github.com/JnH-Projects)).
The rework is by **JayMar921** ([JnH Projects](https://github.com/JnH-Projects)). More of their
projects and plugins are at [jhprojects.dev](https://www.jhprojects.dev).

## Licensing note

Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Architecture

This document explains how MCHeli Rework is organized and why. It reflects the code as of
`1.1.0-beta.3`.
`1.1.0`.

## Goals

Expand Down
24 changes: 16 additions & 8 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The original mod is about 60,000 lines of 1.7.10 code. Nearly all of it touches APIs that no
longer exist (immediate mode OpenGL, numeric ids, the old network and event systems), so the port
happened in four phases toward 1.0.0, and 1.1.0 continues with six more. Each phase ends with a
happened in four phases toward 1.0.0, and 1.1.0 continued with nine more. Each phase ends with a
tagged pre-release that installs and runs on its own.

| Phase | Version | Theme | State |
Expand All @@ -12,8 +12,9 @@ tagged pre-release that installs and runs on its own.
| 3 | `1.0.0-alpha.3` | Weapons and combat | Implemented, in-game test in progress |
| 4 | `1.0.0-beta.1` | HUD and polish | Done |
| | `1.0.0` | Release: code-only jar | Released |
| 5-13 | `1.1.0-beta.1` to `beta.9` | Content packs, NeoForge and Fabric, equipment, workshop, every release version from 1.20.6 to 26.3 ([plan](#road-to-110)) | In progress |
| | `1.1.0` | Release on CurseForge | Planned |
| 5-13 | `1.1.0-beta.1` to `beta.9` | Content packs, NeoForge and Fabric, equipment, workshop, every release version from 1.20.6 to 26.3 ([plan](#road-to-110)) | Released |
| | `1.1.0` | Release on CurseForge | Released |
| | `1.1.1` | Fixes for what testers find on 1.1.0 ([list](#111-after-testing)) | Planned |

## Phase 1: foundation and flyable helicopters

Expand Down Expand Up @@ -105,7 +106,7 @@ split into nine phases, each ending in a beta.
|-------|--------------|-------------|------------|
| `1.1.0-beta.N` | GitHub pre-release | Mirrored, GitHub pre-release | Not uploaded |
| `1.1.0-rc.N` (if needed) | GitHub pre-release | Mirrored, GitHub pre-release | Not uploaded |
| `1.1.0` | GitHub release | Mirrored, GitHub release | Uploaded, one file per Minecraft version |
| `1.1.0` | GitHub release | Mirrored, GitHub release | Uploaded, one file per Minecraft version and loader |

Every beta goes through the usual flow: set `mod_version`, move the changelog section, merge,
tag `v1.1.0-beta.N` in the private repo, mirror the commits to the public repo and tag the same
Expand Down Expand Up @@ -141,7 +142,7 @@ Rules that hold for every beta:
| 12 | `1.1.0-beta.8` | Workshop: textures, sounds and sharing (Forge 26.3 only) | Released |
| | `1.1.0-beta.8.1` | Hotfix: the files missing from the released jars | Released |
| 13 | `1.1.0-beta.9` | Every loader on every supported version, 1.20.6 to 26.3 | Released |
| | `1.1.0` | Release on CurseForge | Planned |
| | `1.1.0` | Release on CurseForge | Released |

The order is deliberate. The registry and the source split come first because everything else
sits on them. Content packs come before the workshop, since the workshop's output is a pack.
Expand Down Expand Up @@ -325,15 +326,22 @@ to the 1.1.0 release. Only the Forge 26.3 jar has been started from a launcher p

## 1.1.0 release

No new features after beta.9; a `1.1.0-rc.N` follows only if beta.9 testing finds problems.
No new features after beta.9. Hands-on testing moved from before this release to after it: testers play
the released jars, and what they find goes into 1.1.1 instead of a `1.1.0-rc.N`.

- [x] Drafting table labels no longer run into the inventory
- [x] Tag `v1.1.0` in both repositories; upload one CurseForge file per Minecraft version and loader, with
the player-facing changelog from `docs/CURSEFORGE.md`

## 1.1.1: after testing

Fixes for what testers find on 1.1.0, and these checks, which no one has done yet:

- [ ] The phase 7 smoke tests for every jar ([TESTING.md](TESTING.md#smoke-test-every-jar)), each from a
launcher profile, with a real flight, weapons, sound by ear and a pack download from a server
- [ ] Every phase checklist done on every supported Minecraft version
- [ ] A 1.0.0 world and the beta worlds load with their vehicles and items intact
- [ ] A pack made in the workshop on one version loads on every other supported version
- [ ] Tag `v1.1.0` in both repositories; upload one CurseForge file per Minecraft version and loader, with
the player-facing changelog from `docs/CURSEFORGE.md`

## Open decisions

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ net.minecraftforge.gradle.merge-source-sets=true
mod_id=mcheli
mod_name=MCHeli Rework
mod_group=com.jnhprojects.mcheli
mod_version=1.1.0-beta.9
mod_version=1.1.0
mod_authors=JayMar921 (rework), EMB4 (original author), Fureniku (CurseForge maintainer)
mod_license=MCHeli Rework Licence 1.0 (see LICENSE)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public DraftingTableScreen(DraftingTableMenu menu, Inventory inventory, Componen
imageWidth = 400;
imageHeight = 240;
inventoryLabelX = 30;
inventoryLabelY = 130;
inventoryLabelY = 122;
}

@Override
Expand All @@ -85,8 +85,8 @@ protected void init() {
}
create = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.create"), b -> create())
.bounds(leftPos + 120, topPos + 89, 50, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 36, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 155, topPos + 111, 35, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 16, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 180, topPos + 111, 16, 20).build());
previousPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.previous_page"), b -> turnPage(-1))
.bounds(leftPos + 210, topPos + 210, 60, 20).build());
nextPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.next_page"), b -> turnPage(1))
Expand Down Expand Up @@ -268,7 +268,8 @@ protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
}
ItemStack result = result();
graphics.drawString(font, font.plainSubstrByWidth(result.getHoverName().getString(), 85), 120, 20, WHITE, true);
graphics.drawString(font, (index + 1) + " / " + lists.get(list).size(), 120, 134, TEXT, false);
String position = (index + 1) + " / " + lists.get(list).size();
graphics.drawString(font, position, 158 - font.width(position) / 2, 117, TEXT, false);
ingredients(graphics, entry.value(), mouseX, mouseY);
graphics.renderItem(result, 178, 52);
if (pageCount == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public DraftingTableScreen(DraftingTableMenu menu, Inventory inventory, Componen
imageWidth = 400;
imageHeight = 240;
inventoryLabelX = 30;
inventoryLabelY = 130;
inventoryLabelY = 122;
}

@Override
Expand All @@ -85,8 +85,8 @@ protected void init() {
}
create = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.create"), b -> create())
.bounds(leftPos + 120, topPos + 89, 50, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 36, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 155, topPos + 111, 35, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 16, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 180, topPos + 111, 16, 20).build());
previousPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.previous_page"), b -> turnPage(-1))
.bounds(leftPos + 210, topPos + 210, 60, 20).build());
nextPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.next_page"), b -> turnPage(1))
Expand Down Expand Up @@ -268,7 +268,8 @@ protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
}
ItemStack result = result();
graphics.drawString(font, font.plainSubstrByWidth(result.getHoverName().getString(), 85), 120, 20, WHITE, true);
graphics.drawString(font, (index + 1) + " / " + lists.get(list).size(), 120, 134, TEXT, false);
String position = (index + 1) + " / " + lists.get(list).size();
graphics.drawString(font, position, 158 - font.width(position) / 2, 117, TEXT, false);
ingredients(graphics, entry.value(), mouseX, mouseY);
graphics.renderItem(result, 178, 52);
if (pageCount == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public DraftingTableScreen(DraftingTableMenu menu, Inventory inventory, Componen
imageWidth = 400;
imageHeight = 240;
inventoryLabelX = 30;
inventoryLabelY = 130;
inventoryLabelY = 122;
}

@Override
Expand All @@ -89,8 +89,8 @@ protected void init() {
}
create = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.create"), b -> create())
.bounds(leftPos + 120, topPos + 89, 50, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 36, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 155, topPos + 111, 35, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 16, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 180, topPos + 111, 16, 20).build());
previousPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.previous_page"), b -> turnPage(-1))
.bounds(leftPos + 210, topPos + 210, 60, 20).build());
nextPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.next_page"), b -> turnPage(1))
Expand Down Expand Up @@ -264,7 +264,8 @@ protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
}
ItemStack result = result();
graphics.drawString(font, font.plainSubstrByWidth(result.getHoverName().getString(), 85), 120, 20, WHITE, true);
graphics.drawString(font, (index + 1) + " / " + lists.get(list).size(), 120, 134, TEXT, false);
String position = (index + 1) + " / " + lists.get(list).size();
graphics.drawString(font, position, 158 - font.width(position) / 2, 117, TEXT, false);
ingredients(graphics, entry.display(), mouseX, mouseY);
graphics.renderItem(result, 178, 52);
if (pageCount == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public DraftingTableScreen(DraftingTableMenu menu, Inventory inventory, Componen
imageWidth = 400;
imageHeight = 240;
inventoryLabelX = 30;
inventoryLabelY = 130;
inventoryLabelY = 122;
}

@Override
Expand All @@ -90,8 +90,8 @@ protected void init() {
}
create = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.create"), b -> create())
.bounds(leftPos + 120, topPos + 89, 50, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 36, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 155, topPos + 111, 35, 20).build());
previous = addRenderableWidget(Button.builder(Component.literal("<<"), b -> step(-1)).bounds(leftPos + 120, topPos + 111, 16, 20).build());
next = addRenderableWidget(Button.builder(Component.literal(">>"), b -> step(1)).bounds(leftPos + 180, topPos + 111, 16, 20).build());
previousPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.previous_page"), b -> turnPage(-1))
.bounds(leftPos + 210, topPos + 210, 60, 20).build());
nextPage = addRenderableWidget(Button.builder(Component.translatable("gui.mcheli.drafting_table.next_page"), b -> turnPage(1))
Expand Down Expand Up @@ -265,7 +265,8 @@ protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
}
ItemStack result = result();
graphics.drawString(font, font.plainSubstrByWidth(result.getHoverName().getString(), 85), 120, 20, WHITE, true);
graphics.drawString(font, (index + 1) + " / " + lists.get(list).size(), 120, 134, TEXT, false);
String position = (index + 1) + " / " + lists.get(list).size();
graphics.drawString(font, position, 158 - font.width(position) / 2, 117, TEXT, false);
ingredients(graphics, entry.display(), mouseX, mouseY);
graphics.renderItem(result, 178, 52);
if (pageCount == 0) {
Expand Down
Loading
Loading