Skip to content

适配 GenerateMap 至 1.4.5#1077

Merged
ACaiCat merged 14 commits intoUnrealMultiple:masterfrom
Arispex:master
Feb 17, 2026
Merged

适配 GenerateMap 至 1.4.5#1077
ACaiCat merged 14 commits intoUnrealMultiple:masterfrom
Arispex:master

Conversation

@Arispex
Copy link
Contributor

@Arispex Arispex commented Feb 15, 2026

适配 GenerateMap 至 1.4.5
修复了在 Linux,macOS 的保存路径错误
已测试

Summary by Sourcery

将 GenerateMap 插件适配到 Terraria 1.4.5,并调整地图/世界导出行为和路径。

新功能:

  • 通过将当前世界(.wld)复制到专用 Maps 目录下带时间戳的文件中来导出世界文件。
  • 支持使用内部的世界地图瓦片缓冲区生成地图图像,并添加边缘偏移以兼容 1.4.5。

错误修复:

  • 通过使用与平台无关的路径组合方式和稳定的基础目录,修复在 Linux 和 macOS 上错误的保存路径。
  • 确保在查找世界文件时验证其是否存在,如果缺失则报告错误。

改进:

  • 移除在运行时对世界地图索引器的 detour hook,改为构建一个具有所需瓦片缓冲布局的可用地图。
  • 优化作者元数据,并将插件版本提升至 2.1.0。
  • 明确 /map file 命令描述,指出其会导出世界(.wld)文件。

文档:

  • 更新 README,加入新的作者列表,并添加 2.1.0 的更新日志条目,说明 1.4.5 适配与路径修复内容。
Original summary in English

Summary by Sourcery

Adapt the GenerateMap plugin to Terraria 1.4.5 and adjust map/world export behavior and paths.

New Features:

  • Export world files by copying the current world (.wld) into a timestamped file under a dedicated Maps directory.
  • Support generating map images using the internal world map tile buffer with edge offsets for 1.4.5 compatibility.

Bug Fixes:

  • Fix incorrect save paths on Linux and macOS by using platform-agnostic path combinations and a stable base directory.
  • Ensure world file lookup validates existence and reports an error if the world file is missing.

Enhancements:

  • Remove runtime detour hooking of the world map indexer and instead construct a working map with the required tile buffer layout.
  • Refine author metadata and bump the plugin version to 2.1.0.
  • Clarify the /map file command description to indicate it exports the world (.wld) file.

Documentation:

  • Update README with the new author list and a 2.1.0 changelog entry describing 1.4.5 adaptation and path fix.

@Arispex Arispex requested a review from a team as a code owner February 15, 2026 11:30
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体性的反馈:

  • SaveMapFile 中,GetWorldFilePath 可能会抛出 FileNotFoundException,其向外冒泡的方式会和当前 Generate 中的 try/catch 路径不一致;建议在本地处理世界文件缺失的情况(例如返回明确的错误或记录日志)而不是直接抛出异常,以保持与该命令其余部分一致的行为。
  • LightUpWholeMapCreateMapImg 现在都依赖于边缘偏移逻辑和 _tiles 的布局;也许值得提取一个小的辅助方法,或在单一位置对这一行为进行文档化,以避免将来世界地图边缘处理再次变更时出现不一致。
AI 代理提示词
Please address the comments from this code review:

## Overall Comments
- In `SaveMapFile`, `GetWorldFilePath` can throw a `FileNotFoundException` that will bubble up differently from the existing `Generate` try/catch path; consider handling the missing-world case locally (e.g., returning a clear error or logging) instead of throwing to keep behavior consistent with the rest of the command.
- `LightUpWholeMap` and `CreateMapImg` now both depend on the edge-offset logic and `_tiles` layout; it may be worth extracting a small helper or documenting this behavior in one place to avoid accidental divergence if the world map edge handling changes again.

## Individual Comments

### Comment 1
<location> `src/GenerateMap/MapGenerator.cs:44-66` </location>
<code_context>
+                var tile = MapHelper.CreateMapTile(x, y, byte.MaxValue);
+
+                // 1.4.5+ on different runtimes may read either raw or edge-offset coordinates during save.
+                if ((uint) x < (uint) width && (uint) y < (uint) height)
+                {
+                    Main.Map._tiles[x, y] = tile;
+                }
+
+                var rawX = x + edge;
+                var rawY = y + edge;
+                if ((uint) rawX < (uint) width && (uint) rawY < (uint) height)
+                {
+                    Main.Map._tiles[rawX, rawY] = tile;
</code_context>

<issue_to_address>
**suggestion:** The dual write to both raw and edge-offset coordinates can be simplified and documented via code structure.

Writing the same `tile` to both `(x, y)` and `(x + edge, y + edge)` is subtle and depends on save-time interpretation of map data. With `width = maxTilesX + edge * 2`, `(uint)x < (uint)width` / `(uint)y < (uint)height` are effectively always true here, so the first branch is unconditional and may confuse future readers.

To improve clarity:
- Either drop the first bounds check or restructure so the intent of the two writes is explicit (e.g., named helpers or comments for “raw” vs “offset” tiles).
- If both layouts are required, consider limiting one write to just the border region to reduce overlap and make the dual write easier to reason about.

```suggestion
        var width = Main.Map._tiles.GetLength(0);
        var height = Main.Map._tiles.GetLength(1);
        for (var x = 0; x < Main.maxTilesX; x++)
        {
            for (var y = 0; y < Main.maxTilesY; y++)
            {
                var tile = MapHelper.CreateMapTile(x, y, byte.MaxValue);

                // Populate both layouts used by different runtimes during save:
                // - "raw" coordinates (x, y) for legacy/vanilla behavior.
                // - edge-offset coordinates (x + edge, y + edge) for bordered map layouts.
                //
                // The raw coordinates are always within bounds because width/height include the edge padding.
                Main.Map._tiles[x, y] = tile;

                var offsetX = x + edge;
                var offsetY = y + edge;
                if ((uint) offsetX < (uint) width && (uint) offsetY < (uint) height)
                {
                    Main.Map._tiles[offsetX, offsetY] = tile;
                }
            }
        }
    }
    {
        Image<Rgba32> image = new (Main.maxTilesX, Main.maxTilesY);
```
</issue_to_address>

### Comment 2
<location> `src/GenerateMap/MapGenerator.cs:73-80` </location>
<code_context>
-        return File.ReadAllBytes(CreatMapFile());
-    }
-    
-    internal static byte[] CreatMapFileBytes()
     {
         var image = CreateMapImg();
         using var stream = new MemoryStream();
         image.SaveAsPng(stream);
         return stream.ToArray();
-
+    }
+    
+    internal static byte[] CreatMapFileBytes()
+    {
+        return File.ReadAllBytes(GetWorldFilePath());
     }

</code_context>

<issue_to_address>
**suggestion:** Method name `CreatMapFileBytes` now misrepresents that it returns world-file bytes rather than map-file bytes.

This method now reads bytes from the world file via `GetWorldFilePath()`, but its name still implies map data. Please rename it (and its usages) to something like `GetWorldFileBytes` so the name matches its new behavior.

Suggested implementation:

```csharp
    internal static byte[] GetWorldFileBytes()
    {
        return File.ReadAllBytes(GetWorldFilePath());
    }

```

Search the entire solution for usages of `CreatMapFileBytes` and update them to `GetWorldFileBytes` to match the new method name. This will typically include any code that previously expected "map file" bytes but now correctly refers to reading the world file bytes.
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In SaveMapFile, GetWorldFilePath can throw a FileNotFoundException that will bubble up differently from the existing Generate try/catch path; consider handling the missing-world case locally (e.g., returning a clear error or logging) instead of throwing to keep behavior consistent with the rest of the command.
  • LightUpWholeMap and CreateMapImg now both depend on the edge-offset logic and _tiles layout; it may be worth extracting a small helper or documenting this behavior in one place to avoid accidental divergence if the world map edge handling changes again.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `SaveMapFile`, `GetWorldFilePath` can throw a `FileNotFoundException` that will bubble up differently from the existing `Generate` try/catch path; consider handling the missing-world case locally (e.g., returning a clear error or logging) instead of throwing to keep behavior consistent with the rest of the command.
- `LightUpWholeMap` and `CreateMapImg` now both depend on the edge-offset logic and `_tiles` layout; it may be worth extracting a small helper or documenting this behavior in one place to avoid accidental divergence if the world map edge handling changes again.

## Individual Comments

### Comment 1
<location> `src/GenerateMap/MapGenerator.cs:44-66` </location>
<code_context>
+                var tile = MapHelper.CreateMapTile(x, y, byte.MaxValue);
+
+                // 1.4.5+ on different runtimes may read either raw or edge-offset coordinates during save.
+                if ((uint) x < (uint) width && (uint) y < (uint) height)
+                {
+                    Main.Map._tiles[x, y] = tile;
+                }
+
+                var rawX = x + edge;
+                var rawY = y + edge;
+                if ((uint) rawX < (uint) width && (uint) rawY < (uint) height)
+                {
+                    Main.Map._tiles[rawX, rawY] = tile;
</code_context>

<issue_to_address>
**suggestion:** The dual write to both raw and edge-offset coordinates can be simplified and documented via code structure.

Writing the same `tile` to both `(x, y)` and `(x + edge, y + edge)` is subtle and depends on save-time interpretation of map data. With `width = maxTilesX + edge * 2`, `(uint)x < (uint)width` / `(uint)y < (uint)height` are effectively always true here, so the first branch is unconditional and may confuse future readers.

To improve clarity:
- Either drop the first bounds check or restructure so the intent of the two writes is explicit (e.g., named helpers or comments for “raw” vs “offset” tiles).
- If both layouts are required, consider limiting one write to just the border region to reduce overlap and make the dual write easier to reason about.

```suggestion
        var width = Main.Map._tiles.GetLength(0);
        var height = Main.Map._tiles.GetLength(1);
        for (var x = 0; x < Main.maxTilesX; x++)
        {
            for (var y = 0; y < Main.maxTilesY; y++)
            {
                var tile = MapHelper.CreateMapTile(x, y, byte.MaxValue);

                // Populate both layouts used by different runtimes during save:
                // - "raw" coordinates (x, y) for legacy/vanilla behavior.
                // - edge-offset coordinates (x + edge, y + edge) for bordered map layouts.
                //
                // The raw coordinates are always within bounds because width/height include the edge padding.
                Main.Map._tiles[x, y] = tile;

                var offsetX = x + edge;
                var offsetY = y + edge;
                if ((uint) offsetX < (uint) width && (uint) offsetY < (uint) height)
                {
                    Main.Map._tiles[offsetX, offsetY] = tile;
                }
            }
        }
    }
    {
        Image<Rgba32> image = new (Main.maxTilesX, Main.maxTilesY);
```
</issue_to_address>

### Comment 2
<location> `src/GenerateMap/MapGenerator.cs:73-80` </location>
<code_context>
-        return File.ReadAllBytes(CreatMapFile());
-    }
-    
-    internal static byte[] CreatMapFileBytes()
     {
         var image = CreateMapImg();
         using var stream = new MemoryStream();
         image.SaveAsPng(stream);
         return stream.ToArray();
-
+    }
+    
+    internal static byte[] CreatMapFileBytes()
+    {
+        return File.ReadAllBytes(GetWorldFilePath());
     }

</code_context>

<issue_to_address>
**suggestion:** Method name `CreatMapFileBytes` now misrepresents that it returns world-file bytes rather than map-file bytes.

This method now reads bytes from the world file via `GetWorldFilePath()`, but its name still implies map data. Please rename it (and its usages) to something like `GetWorldFileBytes` so the name matches its new behavior.

Suggested implementation:

```csharp
    internal static byte[] GetWorldFileBytes()
    {
        return File.ReadAllBytes(GetWorldFilePath());
    }

```

Search the entire solution for usages of `CreatMapFileBytes` and update them to `GetWorldFileBytes` to match the new method name. This will typically include any code that previously expected "map file" bytes but now correctly refers to reading the world file bytes.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Member

@ACaiCat ACaiCat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

非常好的地图生成

@ACaiCat ACaiCat added this pull request to the merge queue Feb 17, 2026
Merged via the queue into UnrealMultiple:master with commit 6566d2c Feb 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments