openfrontio / openfrontio/OpenFrontIO

Windows checkouts silently corrupt map .bin files (no .gitattributes; autocrlf converts them as text)

Open
#4,601 3 comments 0 reactions 1 assignee Claimed by @eastwoodgrant View on GitHub
approved
Dominant language
TypeScript
Stars
2.7k
Forks
1.4k
Avg merge
17h 43m
Merged PRs (30d)
310

Description

## Problem

The repo has no `.gitattributes`, so binary map assets are subject to git's text/eol handling. On a default Windows clone (`core.autocrlf=true` — the Git for Windows recommended installer setting), checkout LF→CRLF conversion rewrites map bins: every `0x0A` byte in the terrain data grows a `0x0D` prefix. The file on disk no longer matches `width*height`, and the game crashes the moment such a map loads:

```
Error: Invalid data: buffer size 4855502 incorrect for 2904x1672 terrain plus 4 bytes for dimensions.
at genTerrainFromBin (src/core/game/TerrainMapLoader.ts)
```

**Currently corrupted on a default Windows checkout (7 files):** `europe/map.bin` (+14 bytes), `greatlakes/map.bin` (+8), `korea/map.bin` (+2), `levant/map.bin` (+57), `didierfrance/map16x.bin` (+113), `losangeles/map4x.bin` (+1), `venice/map4x.bin` (+15).

## Why it's sneaky

- **The committed blobs are clean** — verified via `git cat-file -s` (e.g. `europe/map.bin` blob is exactly 4,855,488 = 2904×1672). Corruption happens purely at checkout, so prod/CI (non-Windows or autocrlf off) never sees it. It strictly bites Windows contributors, who get a broken game out of a fresh clone.
- **Every map bin is exposed, not just these 7.** git's binary-detection heuristic looks for a NUL byte in the first ~8k; terrain data contains none there, so ALL `map*.bin` files are classified as "text" and eligible for conversion. The 7 above are simply the maps whose bytes happen to include `0x0A` today — any map regenerated in the future can silently join them.

## Repro

1. Windows, Git for Windows with the default "Checkout Windows-style" setting (`core.autocrlf=true`).
2. Fresh clone (or fresh worktree checkout).
3. `resources/maps/europe/map.bin` is 4,855,502 bytes on disk vs a 4,855,488-byte blob. Verified each inserted byte is a `0x0D` immediately preceding an existing `0x0A` (14 LFs in the file, 14 CRLF pairs after checkout, +14 bytes exactly).
4. Load Europe (or Great Lakes / Korea / Levant) → `genTerrainFromBin` throws the size error above.

## Fix

One `.gitattributes` at the repo root immunizes everything forever:

```
*.bin binary
*.webp binary
*.png binary
```

(Existing corrupted working copies self-heal on the next checkout of those paths after the attributes land.)

---
*Made and verified by Claude — blob sizes checked against two independent clones, corruption reproduced on demand via a fresh checkout of a pre-`.gitattributes` revision, and the LF→CRLF byte accounting confirmed exactly (every excess byte is a CR inserted before an existing LF).*

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.