Skip to content
Open
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
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ logs/
runtime/
temp/
reobf/
CHANGELOG
LICENSE.txt
*.sh

# Misc
Expand Down
17 changes: 0 additions & 17 deletions CHANGELOG.md

This file was deleted.

51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,49 @@
FlightView
==========
# FlightView

[![Build](https://github.com/fubira/FlightView/actions/workflows/build.yml/badge.svg)](https://github.com/fubira/FlightView/actions/workflows/build.yml)

Minecraft client mod that displays elytra flight information. Available for both Fabric and NeoForge.

## Features

- **Flight HUD** — ground speed (GS) and air speed (AS) in km/h, plus yaw and pitch
- **Elytra durability** — remaining durability, colored as it wears down
- **Auto camera** — switches to third-person back view while flying, restores the previous view on landing

## Controls

Press **V** to cycle through modes:

| Mode | Behavior |
|------|----------|
| 0 | Disabled |
| 1 | HUD only |
| 2 | HUD + auto camera |

## Tech stack

Java 25, Gradle. Fabric Loom for the Fabric module and NeoForge ModDev for the NeoForge module. Settings persist through Cloth Config (Fabric) and the NeoForge config spec (NeoForge).

## Requirements

Minecraft and mod-loader versions are defined in [`gradle.properties`](gradle.properties).

## Build

```sh
./gradlew build
```

Combined artifacts are written to `build/libs/`.

## Structure

| Module | Contents |
|--------|----------|
| `common` | Shared resources (language files) |
| `fabric` | Fabric implementation |
| `neoforge` | NeoForge implementation |

## License

[MIT](LICENSE.md) © fubira
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;

public class WorldRenderLastEventListener {
public class ElytraFlightTracker {
// 飛行開始からこの tick 数を超えたら自動でカメラを切り替える
private static final long CAMERA_SWITCH_DELAY_TICKS = 15;

private boolean isLastFlying = false;
private CameraType lastCameraType = null;
private boolean isCameraChanged = false;

public WorldRenderLastEventListener() {
public ElytraFlightTracker() {
ClientTickEvents.END_CLIENT_TICK.register(this::onWorldRenderLast);
}

Expand Down Expand Up @@ -57,7 +60,7 @@ public void endElytraFlying() {
public void updateElytraFlying(long ticks) {
Minecraft mc = Minecraft.getInstance();

if (!isCameraChanged && ticks > 15) {
if (!isCameraChanged && ticks > CAMERA_SWITCH_DELAY_TICKS) {
if (FlightViewMod.isCameraChange()) {
mc.options.setCameraType(CameraType.THIRD_PERSON_BACK);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void onInitializeClient() {
}
});

new WorldRenderLastEventListener();
new ElytraFlightTracker();
new FlightViewRenderer();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@

public class FlightViewRenderer
{
private static final int HUD_X = 8;
private static final int HUD_Y = 32;
private static final int LINE_HEIGHT = 10;
private static final int BACKGROUND_PADDING = 2;
private static final int ELYTRA_INFO_X_OFFSET = 20;
private static final float BACKGROUND_OPACITY = 0.4F;

// 速度換算: ブロック/tick から km/h へ (20 tick/秒 × 3.6)
private static final double BLOCKS_PER_TICK_TO_KMH = 20.0D * 3.6D;

// エリトラ耐久の消耗率しきい値。この割合を超えると警告色で表示する
private static final double ELYTRA_WEAR_CRITICAL = 0.95D;
private static final double ELYTRA_WEAR_WARNING = 0.9D;

private static final int COLOR_TEXT = ARGB.color(224, 224, 224);
private static final int COLOR_CRITICAL = ARGB.color(224, 64, 64);
private static final int COLOR_WARNING = ARGB.color(224, 128, 64);

public FlightViewRenderer() {
HudElementRegistry.addLast(Identifier.fromNamespaceAndPath("flightview", "hud"), (context, tickDelta) -> {
Minecraft mc = Minecraft.getInstance();
Expand All @@ -30,12 +48,12 @@ public FlightViewRenderer() {
return;

ItemStack itemstack = player.getItemBySlot(EquipmentSlot.CHEST);
renderFlightInfo(context, 8, 32, player, itemstack);
renderFlightInfo(context, HUD_X, HUD_Y, player, itemstack);
});
}

protected List<String> getFlightInfoString(Player player) {
List<String> stringArray = new ArrayList<>();
protected List<String> getFlightInfoLines(Player player) {
List<String> lines = new ArrayList<>();
double dx = player.position().x - player.xOld;
double dy = player.position().y - player.yOld;
double dz = player.position().z - player.zOld;
Expand All @@ -44,14 +62,15 @@ protected List<String> getFlightInfoString(Player player) {
float yaw = Mth.wrapDegrees(player.getYRot());
float pitch = Mth.wrapDegrees(player.getXRot());

stringArray.add(String.format("GS: %.2f(km/h)", groundSpeed * 20.0D * 3.6D));
stringArray.add(String.format("AS: %.2f(km/h)", airSpeed * 20.0D * 3.6D));
stringArray.add(String.format("Y: %.1f P: %.1f", yaw, pitch));
lines.add(String.format("GS: %.2f(km/h)", groundSpeed * BLOCKS_PER_TICK_TO_KMH));
lines.add(String.format("AS: %.2f(km/h)", airSpeed * BLOCKS_PER_TICK_TO_KMH));
lines.add(String.format("Y: %.1f P: %.1f", yaw, pitch));

return stringArray;
return lines;
}

protected int getElytraLife(ItemStack stack) {
// エリトラは残り耐久が1に達した時点で飛行不能になるため、飛行可能な残量として1を引く
return stack.getMaxDamage() - stack.getDamageValue() - 1;
}

Expand All @@ -60,36 +79,36 @@ protected String getElytraInfoString(ItemStack stack) {
}

protected int getElytraInfoColor(ItemStack stack) {
int color = ARGB.color(224, 224, 224);
double left = (double)stack.getDamageValue() / stack.getMaxDamage();
if (left > 0.95D)
color = ARGB.color(224, 64, 64);
else if (left > 0.9D)
color = ARGB.color(224, 128, 64);
return color;
double wear = (double) stack.getDamageValue() / stack.getMaxDamage();
if (wear > ELYTRA_WEAR_CRITICAL)
return COLOR_CRITICAL;
if (wear > ELYTRA_WEAR_WARNING)
return COLOR_WARNING;
return COLOR_TEXT;
}

protected int renderFlightInfo(GuiGraphicsExtractor drawContext, int x, int y, Player player, ItemStack stack) {
Minecraft mc = Minecraft.getInstance();
List<String> flightInfoString = getFlightInfoString(player);
List<String> flightInfoLines = getFlightInfoLines(player);
String elytraInfoString = getElytraInfoString(stack);

int backgroundColor = mc.options.getBackgroundColor(0.4f);
int backgroundColor = mc.options.getBackgroundColor(BACKGROUND_OPACITY);
final boolean hasElytra = stack.getItem() == Items.ELYTRA;
final int lineHeight = 10;
final int areaWidth = flightInfoString.stream().map(mc.font::width).max(Integer::compare).get();
final int areaHeight = lineHeight * flightInfoString.size() + (hasElytra ? (int)(lineHeight * 1.5) : 0);
final int areaWidth = flightInfoLines.stream().mapToInt(mc.font::width).max().orElse(0);
final int areaHeight = LINE_HEIGHT * flightInfoLines.size() + (hasElytra ? (int)(LINE_HEIGHT * 1.5) : 0);

drawContext.pose().pushMatrix();
drawContext.fill(x - 2, y - 2, x + areaWidth + 2, y + areaHeight + 2, backgroundColor);
drawContext.fill(x - BACKGROUND_PADDING, y - BACKGROUND_PADDING, x + areaWidth + BACKGROUND_PADDING, y + areaHeight + BACKGROUND_PADDING, backgroundColor);

flightInfoString.forEach(s -> drawContext.text(mc.font, s, x, y + lineHeight * flightInfoString.indexOf(s), ARGB.color(224, 224, 224), false));
for (int i = 0; i < flightInfoLines.size(); i++) {
drawContext.text(mc.font, flightInfoLines.get(i), x, y + LINE_HEIGHT * i, COLOR_TEXT, false);
}

if (hasElytra) {
int px = x + 20;
int py = (int)(y + flightInfoString.size() * lineHeight + lineHeight * 0.5f);
int px = x + ELYTRA_INFO_X_OFFSET;
int py = (int)(y + flightInfoLines.size() * LINE_HEIGHT + LINE_HEIGHT * 0.5f);
drawContext.text(mc.font, elytraInfoString, px, py, getElytraInfoColor(stack), false);
drawElytraIcon(drawContext, x, y + flightInfoString.size() * lineHeight, stack);
drawElytraIcon(drawContext, x, y + flightInfoLines.size() * LINE_HEIGHT, stack);
}

drawContext.pose().popMatrix();
Expand Down
12 changes: 0 additions & 12 deletions neoforge/.eclipse/configurations/Neoforge - Client.launch

This file was deleted.

12 changes: 0 additions & 12 deletions neoforge/.eclipse/configurations/Neoforge - Data.launch

This file was deleted.

12 changes: 0 additions & 12 deletions neoforge/.eclipse/configurations/Neoforge - GameTestServer.launch

This file was deleted.

12 changes: 0 additions & 12 deletions neoforge/.eclipse/configurations/Neoforge - Server.launch

This file was deleted.

16 changes: 0 additions & 16 deletions neoforge/.eclipse/configurations/Prepare Neoforge - Client.launch

This file was deleted.

16 changes: 0 additions & 16 deletions neoforge/.eclipse/configurations/Prepare Neoforge - Data.launch

This file was deleted.

This file was deleted.

16 changes: 0 additions & 16 deletions neoforge/.eclipse/configurations/Prepare Neoforge - Server.launch

This file was deleted.

Loading
Loading