导入导出修改的功能

This commit is contained in:
sin365 2024-05-11 18:23:01 +08:00
parent 6fdc6327e7
commit cebb390167
3 changed files with 230 additions and 41 deletions

View File

@ -24,6 +24,20 @@ namespace MHFOldShopTools
}
}
public static bool LoadFile(string FilePath, out string[] lines)
{
try
{
lines = File.ReadAllLines(FilePath);
return true;
}
catch (Exception ex)
{
lines = null;
return false;
}
}
public static string[] GetDirFile(string Path)
{
return Directory.GetFiles(Path);
@ -33,6 +47,7 @@ namespace MHFOldShopTools
{
return Encoding.Default.GetBytes(value);
}
public static bool SaveFile(string FilePath, byte[] buffer)
{
try
@ -52,5 +67,11 @@ namespace MHFOldShopTools
return false;
}
}
public static void SaveFile(string FilePath, string[] strArr)
{
System.IO.File.WriteAllLines(FilePath, strArr);
}
}
}

View File

@ -1,4 +1,5 @@
using System.Text;
using System.Collections.Generic;
using System.Text;
namespace MHFOldShopTools
{
@ -6,8 +7,7 @@ namespace MHFOldShopTools
{
static string loc = Path.GetDirectoryName(AppContext.BaseDirectory) + "\\";
const string InDir = "Input";
const string OutDir = "Out";
const string InDir = "Files";
const string Ver = "0.1";
static void Main(string[] args)
@ -19,42 +19,45 @@ namespace MHFOldShopTools
if (!Directory.Exists(loc + InDir))
{
Console.WriteLine("Input文件不存在");
Console.WriteLine("Files文件不存在");
Console.ReadLine();
return;
}
//if (!Directory.Exists(loc + OutDir))
//{
// Console.WriteLine("Out文件不存在");
// Console.ReadLine();
// return;
//}
//if (!Directory.Exists(loc + PosFile2DosDir))
//{
// Console.WriteLine("Templete文件不存在");
// Console.ReadLine();
// return;
//}
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
int bflag = 0;
string[] files = FileHelper.GetDirFile(loc + InDir);
Console.WriteLine($"共{files.Length}个文件,是否处理? (y/n)");
while (true)
{
Console.WriteLine($"请确保Files目录中已放置解密的MHF-FW5 mhfdat.bin文件请选择:");
Console.WriteLine($"[1]解析Files目录中bin文件生成同名txt清单和csv表");
Console.WriteLine($"[2]解析Files目录中csv文件修改回同名的bin文件中");
Console.WriteLine($"Please ensure that the decrypted MHF-FW5 mhfdat.bin file is placed in the Files directory. Please select:");
Console.WriteLine($"[1],Parse the .bin file in the Files directory and generate a .txt list and .csv table with the same name");
Console.WriteLine($"[2],Parse the .csv file in the Files directory and modify it back to the .bin file with the same name");
string yn = Console.ReadLine();
if (yn.ToLower() != "y")
return;
if (yn.ToLower() == "1")
bflag = 1;
else if(yn.ToLower() == "2")
bflag = 2;
if (bflag != 0)
break;
}
if (bflag == 1)
{
int index = 0;
int errcount = 0;
for (int i = 0; i < files.Length; i++)
{
string FileName = files[i].Substring(files[i].LastIndexOf("\\"));
if (!FileName.ToLower().Contains(".bin"))
if (System.IO.Path.GetExtension(FileName).ToLower() != ".bin")
{
continue;
}
@ -63,8 +66,50 @@ namespace MHFOldShopTools
Console.WriteLine($">>>>>>>>>>>>>>开始处理 第{index}个文件 {FileName}<<<<<<<<<<<<<<<<<<<");
FileHelper.LoadFile(files[i], out byte[] data);
ReaderItems(data);
Console.WriteLine($">>>>>>>>>>>>>>处理完毕");
ReaderItems(data, out List<string> OutInputString, out List<string> outPutCsv);
string listfileName = System.IO.Path.GetFileNameWithoutExtension(FileName) + ".txt";
string listoutpath = loc + InDir + "\\" + listfileName;
FileHelper.SaveFile(listoutpath, OutInputString.ToArray());
string csvfileName = System.IO.Path.GetFileNameWithoutExtension(FileName) + ".csv";
string csvoutpath = loc + InDir + "\\" + csvfileName;
FileHelper.SaveFile(csvoutpath, outPutCsv.ToArray());
Console.WriteLine($">>>>>>>>>>>>>>处理完毕>>>>>>>>>>>>>>");
}
}
else
{
int index = 0;
int errcount = 0;
for (int i = 0; i < files.Length; i++)
{
string FileName = files[i].Substring(files[i].LastIndexOf("\\"));
if (System.IO.Path.GetExtension(FileName).ToLower() != ".csv")
{
continue;
}
index++;
Console.WriteLine($">>>>>>>>>>>>>>开始处理 第{index}个文件 {FileName}<<<<<<<<<<<<<<<<<<<");
FileHelper.LoadFile(files[i], out string[] lines);
List<ShopItem> itemlist = LoadStructForCsv(lines);
string binfileName = System.IO.Path.GetFileNameWithoutExtension(FileName) + ".bin";
string binoutpath = loc + InDir + "\\" + binfileName;
FileHelper.LoadFile(binoutpath, out byte[] bindata);
ModifyItem(bindata, itemlist, out byte[] ResultData);
FileHelper.SaveFile(binoutpath, ResultData);
Console.WriteLine($">>>>>>>>>>>>>>处理完毕>>>>>>>>>>>>>>");
}
}
while (true)
@ -74,16 +119,40 @@ namespace MHFOldShopTools
}
static int StartPtr = 0x539A78;
static int NPStore_Ptr = 0x537924;
const int _singelItemDatalenght = 12;
static void ReaderItems(byte[] data)
{
List<ShopItem> items = new List<ShopItem>();
static int NPStore_ItemCount = 712;
static void ReaderItems(byte[] data,out List<string> OutInput,out List<string> outPutCsv)
{
OutInput = new List<string>();
outPutCsv = new List<string>();
List<ShopItem> items = new List<ShopItem>();
for (int i = 0; i < NPStore_ItemCount; i++)
{
items.Add(GetShopItemInfo(data, NPStore_Ptr + (i * _singelItemDatalenght)));
}
for (int i = 0; i < items.Count; i++)
{
ShopItem item = items[i];
string ItemInfo;
if (item.UnKnow)
ItemInfo = $"{"0x" + item.Ptr.ToString("X") + ":"} | 解析失败";
else
ItemInfo = $"{"0x" + item.Ptr.ToString("X") + ":"} | {item.ItemID} ({MHHelper.Get2MHFItemName(item.ItemID)}) | {item.Point}点 | {item.Group}{GetShopName(item.Group)} {item.LevelType}({GetLevelTypeName(item.LevelType)})| [{item.OtherData[0].ToString("X")} {item.OtherData[1].ToString("X")} {item.OtherData[2].ToString("X")} {item.OtherData[3].ToString("X")}]";
OutInput.Add(ItemInfo);
outPutCsv.Add($"{item.ItemID},{item.Point},{item.Group},{item.LevelType}");
Console.WriteLine(ItemInfo);
}
/*
int TempPtr = 0x539A78;
int ToUpCount = 712;
for (int i = 0; i < ToUpCount; i++)
{
items.Add(GetShopItemInfo(data, StartPtr + (-1 * i * _singelItemDatalenght)));
items.Add(GetShopItemInfo(data, TempPtr + (-1 * i * _singelItemDatalenght)));
}
for (int i = items.Count - 1; i >= 0; i--)
@ -93,10 +162,53 @@ namespace MHFOldShopTools
if (item.UnKnow)
ItemInfo = $"{"0x" + item.Ptr.ToString("X") + ":"} | 解析失败";
else
ItemInfo = $"{ "0x" + item.Ptr.ToString("X") + ":"} | {item.ItemID} ({MHHelper.Get2MHFItemName(item.ItemID)}) | {item.Point}点 | {item.Group}{GetShopName(item.Group)}| [{item.OtherData[0].ToString("X")} {item.OtherData[1].ToString("X")} {item.OtherData[2].ToString("X")} {item.OtherData[3].ToString("X")}]";
ItemInfo = $"{ "0x" + item.Ptr.ToString("X") + ":"} | {item.ItemID} ({MHHelper.Get2MHFItemName(item.ItemID)}) | {item.Point}点 | {item.Group}{GetShopName(item.Group)} {item.LevelType}({GetLevelTypeName(item.LevelType)})| [{item.OtherData[0].ToString("X")} {item.OtherData[1].ToString("X")} {item.OtherData[2].ToString("X")} {item.OtherData[3].ToString("X")}]";
Console.WriteLine(ItemInfo);
}
*/
}
static List<ShopItem> LoadStructForCsv(string[] lines)
{
List<ShopItem> itemList = new List<ShopItem>();
for (int i = 0;i < lines.Length; i++)
{
string[] temp = lines[i].Split(',');
ShopItem item = new ShopItem()
{
ItemID = Convert.ToInt32(temp[0]),
Point = Convert.ToInt32(temp[1]),
Group = Convert.ToInt32(temp[2]),
LevelType = Convert.ToInt32(temp[3]),
};
itemList.Add(item);
}
return itemList;
}
static void ModifyItem(byte[] srcdata, List<ShopItem> items,out byte[] ResultData)
{
byte[] target = HexHelper.CopyByteArr(srcdata);
//ClearData
for (int i = NPStore_Ptr; i < NPStore_Ptr + (NPStore_ItemCount * _singelItemDatalenght); i++)
target[i] = 0x00;
for (int i = 0; i < items.Count; i++)
{
ShopItem itemdata = items[i];
int tempItemIDPtr = NPStore_Ptr + (i * _singelItemDatalenght);
int tempPricePtr = tempItemIDPtr + 4;
int tempMenuPtr = tempItemIDPtr + 4 + 4;
int tempLevelPtr = tempItemIDPtr + 4 + 4 + 1;
HexHelper.ModifyDataToBytes(target, HexHelper.intToBytes(itemdata.ItemID), tempItemIDPtr);
HexHelper.ModifyDataToBytes(target, HexHelper.intToBytes(itemdata.Point), tempPricePtr);
target[tempMenuPtr] = (byte)itemdata.Group;
target[tempLevelPtr] = (byte)itemdata.LevelType;
}
ResultData = target;
}
static string GetShopName(int gourp)
@ -114,17 +226,33 @@ namespace MHFOldShopTools
}
}
static string GetLevelTypeName(int Level)
{
switch (Level)
{
case 0:return "无限制";
case 1:return "HR31以上";
case 2:return "HR100以上";
case 3:return "SR1以上";
case 4:return "SR31以上";
default:
return "未定义";
}
}
static ShopItem GetShopItemInfo(byte[] data, int StartPos)
{
int ItemID = -1;
int Point = -1;
int Group = -1;
int LevelType = -1;
bool UnKnow = false;
try
{
ItemID = HexHelper.bytesToInt(data, 4, StartPos);
Point = HexHelper.bytesToInt(data, 4, StartPos + 4);
Group = HexHelper.bytesToInt(data, 1, StartPos + 4 + 4);
LevelType = HexHelper.bytesToInt(data, 1, StartPos + 4 + 4 + 1);
UnKnow = false;
}
catch(Exception ex)
@ -138,6 +266,7 @@ namespace MHFOldShopTools
ItemID = ItemID,
Point = Point,
Group = Group,
LevelType = LevelType,
OtherData = new int[]{ data[StartPos + 4 + 4 + 0],data[StartPos + 4 + 4 + 1], data[StartPos + 4 + 4 + 2], data[StartPos + 4 + 4 + 3] },
UnKnow = UnKnow
};
@ -150,6 +279,7 @@ namespace MHFOldShopTools
public int ItemID;
public int Point;
public int Group;
public int LevelType;
public int[] OtherData;
public bool UnKnow;
}

38
README.md Normal file
View File

@ -0,0 +1,38 @@
##[Cn]
本工具是用于Monster Hunter Frontier 老版本Forward 5的玩家道具商店读写工具。
因为老版本怪物猎人边境的NPC商店列表商店并不受服务器控制。如Erupe的shop相关的表
纯客户端文件固定死的。
为了便于修改,以及为了实现服务器控制客户端商店列表,实现一个工具或类库。于是有了本工具。
本工具可以将mhfdat文件解析后将商店数据输出txt清单和csv文件。
同时也可以自己编辑csv文件。用本工具重新导入mhfdat。得以修复。
对非中国服务器的老版本服务器运营者因为老版本MHF中国只有我一个运营的服务器也分享本工具。
如果您的服务器有Launcher那么可以通过集成本工具最终由服务器控制客户端商店列表。我服务器就是这么做的
** 目前只处理了NetCafe Point Store这一个商店
##[En]
This tool is a player item store read-write tool for Monster Hunter Frontier older versions (Forward 5).
Because the NPC store list store in the old version of Monster Hunter Frontier is not controlled by the server. (such as Erupe's shop related table)
The pure client file is fixed.
To facilitate modification and to achieve server control of the client store list, implement a tool or library. So there was this tool.
This tool can parse the mhfdat file and output the store data as a txt list and CSV file.
At the same time, you can also edit CSV files yourself. Use this tool to re import mhfdat. Can be repaired.
I also share this tool with operators of older versions of non Chinese servers (as I am the only one operating the server in MHF China).
If your server has a Launcher, then the client store list can be ultimately controlled by the server through the set cost tool. (That's how my server does it)
** Currently, only the NetCafe Point Store has been processed