Lin.Helper.Core
1.5.4
dotnet add package Lin.Helper.Core --version 1.5.4
NuGet\Install-Package Lin.Helper.Core -Version 1.5.4
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lin.Helper.Core" Version="1.5.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lin.Helper.Core" Version="1.5.4" />
<PackageReference Include="Lin.Helper.Core" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Lin.Helper.Core --version 1.5.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Lin.Helper.Core, 1.5.4"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Lin.Helper.Core@1.5.4
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Lin.Helper.Core&version=1.5.4
#tool nuget:?package=Lin.Helper.Core&version=1.5.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Lin.Helper.Core
Lineage 1 遊戲資源檔案格式處理函式庫,提供 PAK、SPR、DAT、IMG、TIL、XML 等格式的讀取與處理功能。
安裝
dotnet add package Lin.Helper.Core
功能總覽
| 功能 | 類別 | 說明 |
|---|---|---|
| PAK 讀寫 | PakFile |
PAK/IDX 封裝檔讀取、提取、新增、刪除 |
| PAK 加解密 | PakTools |
PAK/IDX 封裝檔加解密 |
| SPR 解析 | SprReader |
Sprite 動畫圖檔解析 |
| SPR List 解析 | SprListParser |
list.spr / wlist.spr 解析 |
| DAT 解密 | DatFile |
Lineage M DAT 資源檔解密 |
| 圖片轉換 | ImageConverter |
IMG/TIL/TBT 格式轉換 |
| TIL 進階處理 | L1Til |
TIL 解析、版本檢測、降採樣 |
| XML 加解密 | XmlCracker |
遊戲設定 XML 加解密 |
使用範例
PAK 檔案讀寫
using Lin.Helper.Core.Pak;
// 開啟 PAK 檔案
using var pak = new PakFile("Text.idx");
Console.WriteLine($"檔案數量: {pak.Count}");
Console.WriteLine($"加密類型: {pak.EncryptionType}"); // L1, DES, ExtB, None
// 列出所有檔案
foreach (var file in pak.Files)
{
Console.WriteLine($"{file.FileName} ({file.FileSize} bytes)");
}
// 提取單一檔案
byte[] data = pak.Extract("config.xml");
// 提取所有檔案
pak.ExtractAll("output/folder");
// 提取所有檔案 (含進度回報)
pak.ExtractAll("output/folder", (current, total, fileName) =>
{
Console.WriteLine($"[{current}/{total}] {fileName}");
});
// 新增檔案
pak.Add("new_file.xml", newData);
// 從檔案路徑新增
pak.Add("C:/path/to/file.xml");
// 刪除檔案
pak.Delete("old_file.xml");
// 替換檔案
pak.Replace("config.xml", modifiedData);
// 儲存變更 (新增/刪除/替換後必須呼叫)
pak.Save();
// 建立新的 PAK 檔案
using var newPak = PakFile.Create("NewPak.idx", encrypted: true);
newPak.Add("file1.xml", data1);
newPak.Add("file2.xml", data2);
newPak.Save();
PAK 檔案排序驗證
using Lin.Helper.Core.Pak;
using var pak = new PakFile("Text.idx");
// 檢查檔案是否已正確排序
bool sorted = pak.IsSorted(); // 預設 ASCII 不區分大小寫
// 指定排序類型
bool sortedUnderscore = pak.IsSorted(PakFile.SortType.UnderscoreFirst);
// 取得排序錯誤詳細資訊
var errors = pak.VerifySortOrder();
foreach (var (index, fileName, expectedFileName) in errors)
{
Console.WriteLine($"[{index}] {fileName} 應為 {expectedFileName}");
}
// 新增檔案時維持排序順序
pak.Add("new_file.xml", data, maintainSort: true);
// 指定排序類型 (底線優先: 數字 → 底線 → 字母)
pak.Add("new_file.xml", data, maintainSort: true, sortType: PakFile.SortType.UnderscoreFirst);
// 找到插入位置 (不實際新增)
int insertIdx = pak.FindInsertIndex("abc.xml");
pak.Save();
PAK 檔案加解密 (低階 API)
using Lin.Helper.Core.Pak;
// 初始化加密表 (從資源檔載入)
PakTools.Initialize();
// 或手動設定加密表
// PakTools.SetMaps(map1, map2, map3, map4, map5);
// 解密資料 (index: 從第幾個 byte 開始解密)
byte[] decrypted = PakTools.Decode(encryptedData, index: 0);
// 加密資料
byte[] encrypted = PakTools.Encode(plainData, index: 0);
// 支援進度回報
var progress = new Progress<int>(percent => Console.WriteLine($"{percent}%"));
byte[] result = PakTools.Decode(data, 0, progress);
SPR 精靈圖解析
using Lin.Helper.Core.Sprite;
// 載入 SPR 檔案
byte[] sprData = File.ReadAllBytes("monster.spr");
SprFrame[] frames = SprReader.Load(sprData);
// 取得每一幀
for (int i = 0; i < frames.Length; i++)
{
var frame = frames[i];
Console.WriteLine($"Frame: {frame.Width}x{frame.Height}, Type: {frame.Type}");
// frame.Image 是 ImageSharp Image<Rgba32>
frame.Image?.SaveAsPng($"frame_{i}.png");
}
SPR List 解析 (list.spr / wlist.spr)
using Lin.Helper.Core.Sprite;
// 從檔案載入
SprListFile sprList = SprListParser.LoadFromFile("list.spr");
// 或從 byte[] 載入
SprListFile sprList = SprListParser.LoadFromBytes(data);
// 遍歷條目
foreach (var entry in sprList.Entries)
{
Console.WriteLine($"#{entry.Id} {entry.Name} - {entry.ImageCount} images");
// 動作資訊
foreach (var action in entry.Actions)
{
Console.WriteLine($" Action: {action.ActionName}, Frames: {action.FrameCount}");
}
// 屬性資訊
foreach (var attr in entry.Attributes)
{
Console.WriteLine($" Attr: {attr.AttributeName} = {attr.RawParameters}");
}
}
DAT 檔案解密 (Lineage M)
using Lin.Helper.Core.Dat;
// 開啟 DAT 檔案
var datFile = new DatFile("resource.dat");
datFile.ParseEntries();
Console.WriteLine($"檔案數量: {datFile.Entries.Count}");
// 遍歷檔案
foreach (var entry in datFile.Entries)
{
Console.WriteLine($"{entry.Path} ({entry.Size} bytes)");
}
// 提取單一檔案
byte[] content = datFile.ExtractFile(datFile.Entries[0]);
// 匯出所有檔案到資料夾
datFile.ExtractAll("output/folder");
圖片格式轉換
using Lin.Helper.Core.Image;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
// IMG 格式 (未壓縮 RGB555)
Image<Rgba32> img = ImageConverter.LoadImg(imgData);
// TBT 格式 (單一圖塊,RLE 壓縮)
Image<Rgba32> tbt = ImageConverter.LoadTbt(tbtData);
// TIL 格式 (地圖圖塊集)
TileSet tileSet = ImageConverter.LoadTil(tilData);
Console.WriteLine($"圖塊數量: {tileSet.TileCount}");
for (int i = 0; i < tileSet.Tiles.Length; i++)
{
tileSet.Tiles[i]?.SaveAsPng($"tile_{i}.png");
}
// L1Image 格式 (RLE 壓縮圖片)
L1Image l1img = ImageConverter.LoadL1Image(data);
Console.WriteLine($"Offset: ({l1img.XOffset}, {l1img.YOffset})");
Console.WriteLine($"Size: {l1img.Image.Width}x{l1img.Image.Height}");
// 放到指定大小的畫布上
L1Image canvas = ImageConverter.LoadL1Image(data, canvasWidth: 24, canvasHeight: 24);
// RGB555 顏色轉換
Rgba32 color = ImageConverter.Rgb555ToRgba32(0x7C00); // 紅色
圖片格式轉換 (byte[] 版本 - 無 ImageSharp 依賴)
如果不想使用 ImageSharp,可以使用 *Raw 系列方法取得原始 RGBA byte[]:
using Lin.Helper.Core.Image;
// IMG 格式
RawImage img = ImageConverter.LoadImgRaw(imgData);
Console.WriteLine($"Size: {img.Width}x{img.Height}");
// img.Pixels 是 RGBA byte[] (Width * Height * 4 bytes)
// TBT 格式
RawImage tbt = ImageConverter.LoadTbtRaw(tbtData);
// TIL 格式
RawTileSet tileSet = ImageConverter.LoadTilRaw(tilData);
foreach (var tile in tileSet.Tiles)
{
// tile.Pixels 是 RGBA byte[]
}
// L1Image 格式
RawL1Image l1img = ImageConverter.LoadL1ImageRaw(data);
Console.WriteLine($"Offset: ({l1img.XOffset}, {l1img.YOffset})");
// RGB555 轉 RGBA
byte[] rgba = new byte[4];
ImageConverter.Rgb555ToRgba(0x7C00, rgba, 0); // r=255, g=0, b=0, a=255
SPR 精靈圖解析 (byte[] 版本)
using Lin.Helper.Core.Sprite;
byte[] sprData = File.ReadAllBytes("monster.spr");
RawSprFrame[] frames = SprReader.LoadRaw(sprData);
foreach (var frame in frames)
{
Console.WriteLine($"Frame: {frame.Width}x{frame.Height}");
// frame.Pixels 是 RGBA byte[] (Width * Height * 4 bytes)
}
TIL 進階處理 (版本檢測、降採樣)
using Lin.Helper.Core.Tile;
byte[] tilData = File.ReadAllBytes("map.til");
// 自動解壓縮 (支援 Brotli/Zlib)
byte[] decompressed = L1Til.Decompress(tilData);
// 檢測版本
L1Til.TileVersion version = L1Til.GetVersion(tilData);
Console.WriteLine($"Version: {version}"); // Classic, Remaster, Hybrid, Unknown
// 取得 tile 尺寸
int tileSize = L1Til.GetTileSize(tilData); // 24 or 48
// 判斷是否為 Remaster (48x48)
if (L1Til.IsRemaster(tilData))
{
Console.WriteLine("This is a Remaster (48x48) tile file");
}
// 解析為 block 列表
List<byte[]> blocks = L1Til.Parse(tilData);
Console.WriteLine($"Block count: {blocks.Count}");
// 解析為 TileBlocks (支援共用 block 優化)
L1Til.TileBlocks tileBlocks = L1Til.ParseToTileBlocks(tilData);
Console.WriteLine($"Total: {tileBlocks.Count}, Unique: {tileBlocks.UniqueCount}");
// 分析 block 資訊
var analysis = L1Til.AnalyzeBlock(blocks[0]);
Console.WriteLine($"Type: {analysis.Type}, Format: {analysis.Format}");
// 分析整個 til 檔案
var (classic, remaster, hybrid, unknown) = L1Til.AnalyzeTilBlocks(tilData);
Console.WriteLine($"Classic: {classic}, Remaster: {remaster}, Hybrid: {hybrid}");
// 將 Remaster (48x48) 降採樣為 Classic (24x24)
byte[] downscaled = L1Til.DownscaleTil(tilData);
// 從 block 列表組裝 til 檔案
byte[] rebuilt = L1Til.BuildTil(blocks);
// 從 TileBlocks 組裝 (保留共用結構)
byte[] rebuiltFromBlocks = L1Til.BuildTilFromTileBlocks(tileBlocks);
XML 加解密
using Lin.Helper.Core.Xml;
byte[] data = File.ReadAllBytes("config.xml");
// 檢查是否加密
if (XmlCracker.IsEncrypted(data))
{
// 解密
byte[] decrypted = XmlCracker.Decrypt(data);
// 取得正確的編碼
Encoding encoding = XmlCracker.GetXmlEncoding(decrypted, "config-c.xml");
string xml = encoding.GetString(decrypted);
}
// 檢查是否為解密後的 XML
if (XmlCracker.IsDecryptedXml(data))
{
// 加密
byte[] encrypted = XmlCracker.Encrypt(data);
}
支援的檔案格式
| 格式 | 說明 | 類別 |
|---|---|---|
.idx / .pak |
PAK 封裝檔索引與資料 | PakTools |
.spr |
Sprite 動畫圖檔 | SprReader |
list.spr / wlist.spr |
Sprite 清單定義 | SprListParser |
.dat |
Lineage M 資源封裝檔 | DatFile |
.img |
未壓縮圖片 (RGB555) | ImageConverter |
.tbt |
單一圖塊 (RLE 壓縮) | ImageConverter |
.til |
地圖圖塊集 | ImageConverter (轉圖片) / L1Til (解析/降採樣) |
.xml |
加密 XML 設定檔 | XmlCracker |
平台支援
- .NET 8.0+
- .NET 9.0+
- .NET 10.0+
支援 Windows、Linux、macOS 等所有 .NET 支援的平台。
自 v1.1.0 起,圖片處理改用 ImageSharp,實現完整跨平台支援。
授權
MIT License
作者
Flyworld
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- BouncyCastle.Cryptography (>= 2.5.1)
- SharpZipLib (>= 1.4.2)
- SixLabors.ImageSharp (>= 3.1.12)
- ZstdSharp.Port (>= 0.8.4)
-
net8.0
- BouncyCastle.Cryptography (>= 2.5.1)
- SharpZipLib (>= 1.4.2)
- SixLabors.ImageSharp (>= 3.1.12)
- System.Text.Encoding.CodePages (>= 9.0.0)
- ZstdSharp.Port (>= 0.8.4)
-
net9.0
- BouncyCastle.Cryptography (>= 2.5.1)
- SharpZipLib (>= 1.4.2)
- SixLabors.ImageSharp (>= 3.1.12)
- ZstdSharp.Port (>= 0.8.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.5.4 | 342 | 2/13/2026 |
| 1.5.3 | 108 | 2/13/2026 |
| 1.5.2 | 96 | 2/13/2026 |
| 1.5.1 | 99 | 2/12/2026 |
| 1.5.0 | 116 | 2/10/2026 |
| 1.4.2 | 163 | 1/28/2026 |
| 1.4.0 | 108 | 1/28/2026 |
| 1.3.12 | 105 | 1/24/2026 |
| 1.3.11 | 212 | 1/17/2026 |
| 1.3.10 | 104 | 1/17/2026 |
| 1.3.9 | 105 | 1/17/2026 |
| 1.3.8 | 109 | 1/14/2026 |
| 1.3.7 | 129 | 1/6/2026 |
| 1.3.6 | 108 | 1/6/2026 |
| 1.3.5 | 109 | 1/6/2026 |
| 1.3.3 | 117 | 1/4/2026 |
| 1.3.2 | 111 | 1/4/2026 |
| 1.3.1 | 130 | 12/31/2025 |
| 1.3.0 | 110 | 12/31/2025 |
| 1.2.0 | 111 | 12/31/2025 |
Loading failed