新增存档修复功能
This commit is contained in:
parent
cd7399e2c0
commit
a83c97166c
@ -64,6 +64,11 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
{
|
||||
return this.ToString();
|
||||
}
|
||||
|
||||
public virtual bool FixedData(out string log)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class s_base_Byte : s_Base
|
||||
@ -269,10 +274,10 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
int startptr = (block * SrcCfg.block_single_len);
|
||||
for (int i = 0; i < SrcCfg.block_single_len; i++)
|
||||
{
|
||||
if (i == 4) itemiddata[0] = data[startptr + i];
|
||||
if (i == 5) itemiddata[1] = data[startptr + i];
|
||||
if (i == 6) countdata[0] = data[startptr + i];
|
||||
if (i == 7) countdata[1] = data[startptr + i];
|
||||
if (i == 0) itemiddata[0] = data[startptr + i];
|
||||
if (i == 1) itemiddata[1] = data[startptr + i];
|
||||
if (i == 2) countdata[0] = data[startptr + i];
|
||||
if (i == 3) countdata[1] = data[startptr + i];
|
||||
}
|
||||
itemdata.Add((HexHelper.bytesToInt(itemiddata, 2, 0), HexHelper.bytesToInt(countdata, 2, 0)));
|
||||
}
|
||||
@ -280,7 +285,55 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
str += $"{MHHelper.Get2MHFItemName(item.Item1)}:{item.Item2}\r\n";
|
||||
return str;
|
||||
}
|
||||
|
||||
public override bool FixedData(out string log)
|
||||
{
|
||||
if (!SrcVerHad)
|
||||
{
|
||||
log = "没有数据";
|
||||
return false;
|
||||
}
|
||||
|
||||
log = this.GetType().Name + "\r\n";
|
||||
byte[] itemiddata = new byte[2];
|
||||
byte[] countdata = new byte[2];
|
||||
List<(int, int)> itemdata = new List<(int, int)>();
|
||||
for (int block = 0; block < SrcCfg.block_count; block++)
|
||||
{
|
||||
int startptr = (block * SrcCfg.block_single_len);
|
||||
for (int i = 0; i < SrcCfg.block_single_len; i++)
|
||||
{
|
||||
if (i == 0) itemiddata[0] = data[startptr + i];
|
||||
if (i == 1) itemiddata[1] = data[startptr + i];
|
||||
if (i == 2) countdata[0] = data[startptr + i];
|
||||
if (i == 3) countdata[1] = data[startptr + i];
|
||||
}
|
||||
|
||||
uint itemid = HexHelper.bytesToUInt(itemiddata, 2, 0);
|
||||
uint count = HexHelper.bytesToUInt(countdata, 2, 0);
|
||||
if (itemid < 0)
|
||||
continue;
|
||||
|
||||
//log += $"[{block}]{itemid}:{MHHelper.Get2MHFItemName((int)itemid)}:{count}\r\n";
|
||||
|
||||
if (SrcVer == MHFVer.GG)
|
||||
{
|
||||
bool needfix = (itemid >= 9749);
|
||||
|
||||
if (needfix)
|
||||
{
|
||||
//抹除数据
|
||||
for (int i = 0; i < SrcCfg.block_single_len; i++)
|
||||
data[startptr + i] = 0x00;
|
||||
log += $"抹除数据:[{block}]{itemid}:{MHHelper.Get2MHFItemName((int)itemid)}:{count}\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class s_pPlaytime : s_4byte_UInt32_Base
|
||||
{
|
||||
public override string ToString()
|
||||
@ -340,18 +393,18 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
public class s_SR_重弩 : s_4byte_UInt32_Base { }
|
||||
public class s_SR_弓 : s_4byte_UInt32_Base { }
|
||||
|
||||
public class s_SR_片手_Status1 : s_base_Byte{}
|
||||
public class s_SR_双刀_Status1 :s_base_Byte{}
|
||||
public class s_SR_大剑_Status1 :s_base_Byte{}
|
||||
public class s_SR_太刀_Status1 :s_base_Byte{}
|
||||
public class s_SR_锤子_Status1 :s_base_Byte{}
|
||||
public class s_SR_笛_Status1 :s_base_Byte{}
|
||||
public class s_SR_长枪_Status1 :s_base_Byte{}
|
||||
public class s_SR_铳枪_Status1 :s_base_Byte{}
|
||||
public class s_SR_穿龙棍_Status1 :s_base_Byte{}
|
||||
public class s_SR_轻弩_Status1 :s_base_Byte{}
|
||||
public class s_SR_重弩_Status1 :s_base_Byte{}
|
||||
public class s_SR_弓_Status1 : s_base_Byte {}
|
||||
public class s_SR_片手_Status1 : s_base_Byte { }
|
||||
public class s_SR_双刀_Status1 : s_base_Byte { }
|
||||
public class s_SR_大剑_Status1 : s_base_Byte { }
|
||||
public class s_SR_太刀_Status1 : s_base_Byte { }
|
||||
public class s_SR_锤子_Status1 : s_base_Byte { }
|
||||
public class s_SR_笛_Status1 : s_base_Byte { }
|
||||
public class s_SR_长枪_Status1 : s_base_Byte { }
|
||||
public class s_SR_铳枪_Status1 : s_base_Byte { }
|
||||
public class s_SR_穿龙棍_Status1 : s_base_Byte { }
|
||||
public class s_SR_轻弩_Status1 : s_base_Byte { }
|
||||
public class s_SR_重弩_Status1 : s_base_Byte { }
|
||||
public class s_SR_弓_Status1 : s_base_Byte { }
|
||||
|
||||
public class s_SR_片手_Status2 : s_base_Byte { }
|
||||
public class s_SR_双刀_Status2 : s_base_Byte { }
|
||||
@ -412,7 +465,8 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
public class s_pRP : s_2byte_Int16_Base { }
|
||||
public class s_pKQF : s_base_Bytesarray { }
|
||||
public class ExtraBox背包 : s_base_BytesarrayGroup { }
|
||||
public class s_ItemPouch背包 : s_base_BytesarrayGroup {
|
||||
public class s_ItemPouch背包 : s_base_BytesarrayGroup
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
195
Data/MH2DosSaveDataLoader.cs
Normal file
195
Data/MH2DosSaveDataLoader.cs
Normal file
@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace MonsterHunterSaveBruteForce
|
||||
{
|
||||
class MH2DosSaveDataLoader
|
||||
{
|
||||
// 已知数值常量
|
||||
private const ushort KnownMoney = 5929; // 0x1729
|
||||
private const ushort KnownExp = 6525; // 0x197D
|
||||
private const ushort ItemLargePotion = 0x0008; // 回復藥・大 的ID
|
||||
private const ushort ItemLargePotionQty = 5; // 回復藥・大 的数量
|
||||
|
||||
// 道具箱特征(前6个道具)
|
||||
private static readonly List<(ushort id, ushort quantity)> ItemPattern = new List<(ushort, ushort)>
|
||||
{
|
||||
(0x0001, 1), // 調合書①入門編
|
||||
(0x0002, 1), // 調合書②初級編
|
||||
(0x0003, 1), // 調合書③中級編
|
||||
(0x0007, 3), // 回復藥
|
||||
(ItemLargePotion, ItemLargePotionQty), // 回復藥・大
|
||||
(0x0015, 2) // 冷飲
|
||||
};
|
||||
|
||||
public static void LoadSaveData()
|
||||
{
|
||||
Console.WriteLine("===== PS2怪物猎人2存档暴力破解工具 =====");
|
||||
Console.WriteLine("此工具使用金钱、经验和道具特征进行暴力破解");
|
||||
|
||||
// 1. 加载存档
|
||||
byte[] saveData = File.ReadAllBytes("play00.bin");
|
||||
Console.WriteLine($"存档大小: {saveData.Length} 字节");
|
||||
|
||||
// 2. 暴力破解
|
||||
BruteForceDecryption(saveData);
|
||||
}
|
||||
|
||||
static void BruteForceDecryption(byte[] data)
|
||||
{
|
||||
Console.WriteLine("开始暴力破解,这可能需要一些时间...");
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
int totalAttempts = 0;
|
||||
const int reportInterval = 100000; // 每100,000次尝试报告一次进度
|
||||
|
||||
// 限制搜索范围提高效率
|
||||
//int searchRange = Math.Min(0x10000, data.Length - 20);
|
||||
int searchRange = data.Length - 20;
|
||||
|
||||
// 尝试所有可能的密钥组合 (0x0000 - 0xFFFF)
|
||||
for (ushort key = 0; key < ushort.MaxValue; key++)
|
||||
{
|
||||
// 解密整个存档
|
||||
byte[] decrypted = DecryptWithKey(data, key);
|
||||
|
||||
// 验证金钱和经验值
|
||||
var (moneyFound, expFound) = ValidateMoneyAndExp(decrypted);
|
||||
|
||||
// 验证道具箱特征
|
||||
//bool itemsValid = ValidateItemBox(decrypted);
|
||||
|
||||
bool itemsValid = true;
|
||||
|
||||
// 如果三项验证都通过
|
||||
//if (moneyFound && expFound && itemsValid)
|
||||
if(ValidateName(decrypted))
|
||||
{
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"\n暴力破解成功! 密钥: 0x{key:X4}");
|
||||
Console.WriteLine($"耗时: {stopwatch.Elapsed.TotalSeconds:F2} 秒");
|
||||
Console.WriteLine($"尝试次数: {totalAttempts}");
|
||||
|
||||
// 保存解密文件
|
||||
//File.WriteAllBytes("decrypted_play00.bin", decrypted);
|
||||
Console.WriteLine("解密文件已保存: decrypted_play00.bin");
|
||||
return;
|
||||
}
|
||||
|
||||
// 报告进度
|
||||
if (++totalAttempts % reportInterval == 0)
|
||||
{
|
||||
Console.WriteLine($"已尝试 {totalAttempts} 种密钥组合... 当前密钥: 0x{key:X4}");
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"\n暴力破解完成,但未找到有效密钥。耗时: {stopwatch.Elapsed.TotalSeconds:F2} 秒");
|
||||
Console.WriteLine($"总尝试次数: {totalAttempts}");
|
||||
}
|
||||
|
||||
static byte[] DecryptWithKey(byte[] data, ushort key)
|
||||
{
|
||||
byte[] keyBytes = BitConverter.GetBytes(key);
|
||||
byte[] decrypted = new byte[data.Length];
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
decrypted[i] = (byte)(data[i] ^ keyBytes[i % 2]);
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
static (bool moneyFound, bool expFound) ValidateMoneyAndExp(byte[] decrypted)
|
||||
{
|
||||
bool moneyFound = false;
|
||||
bool expFound = false;
|
||||
|
||||
// 扫描整个文件寻找金钱和经验值
|
||||
for (int i = 0; i < decrypted.Length - 1; i++)
|
||||
{
|
||||
ushort value = BitConverter.ToUInt16(decrypted, i);
|
||||
|
||||
// 检查是否是金钱值
|
||||
if (value == KnownMoney)
|
||||
{
|
||||
moneyFound = true;
|
||||
}
|
||||
|
||||
// 检查是否是经验值
|
||||
if (value == KnownExp)
|
||||
{
|
||||
expFound = true;
|
||||
}
|
||||
|
||||
// 如果两个都已找到,提前退出
|
||||
if (moneyFound && expFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (moneyFound, expFound);
|
||||
}
|
||||
|
||||
static bool ValidateName(byte[] data)
|
||||
{
|
||||
byte[] checkdata = new byte[4] { 0xE1, 0xA9, 0x8C, 0x8E };
|
||||
// 扫描整个文件寻找道具箱特征
|
||||
for (int offset = 0; offset < data.Length - checkdata.Length; offset++)
|
||||
{
|
||||
for (int i = 0; i < checkdata.Length; i++)
|
||||
{
|
||||
if (data[0] == checkdata[0]
|
||||
&& data[1] == checkdata[1]
|
||||
&& data[2] == checkdata[2]
|
||||
&& data[3] == checkdata[3])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ValidateItemBox(byte[] decrypted)
|
||||
{
|
||||
// 尝试不同的道具结构 (4字节和8字节)
|
||||
return ValidateItemStructure(decrypted, 4) || ValidateItemStructure(decrypted, 8);
|
||||
}
|
||||
|
||||
static bool ValidateItemStructure(byte[] data, int slotSize)
|
||||
{
|
||||
// 扫描整个文件寻找道具箱特征
|
||||
for (int offset = 0; offset < data.Length - (slotSize * 6); offset++)
|
||||
{
|
||||
bool patternMatch = true;
|
||||
|
||||
// 检查前6个道具是否匹配已知模式
|
||||
for (int slot = 0; slot < 6; slot++)
|
||||
{
|
||||
int slotOffset = offset + (slot * slotSize);
|
||||
|
||||
// 获取道具ID和数量
|
||||
ushort itemId = BitConverter.ToUInt16(data, slotOffset);
|
||||
ushort quantity = BitConverter.ToUInt16(data, slotOffset + 2);
|
||||
|
||||
// 检查是否匹配预期值
|
||||
if (itemId != ItemPattern[slot].id || quantity != ItemPattern[slot].quantity)
|
||||
{
|
||||
patternMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到匹配模式
|
||||
if (patternMatch)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
using Axibug.MHFSaveAutoConverter.DataStruct;
|
||||
using Axibug.MHFSaveAutoConverter.SQL;
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using static Axibug.MHFSaveAutoConverter.DataStruct.MHFSaveDataCfg;
|
||||
@ -8,6 +10,24 @@ namespace Axibug.MHFSaveAutoConverter.Data
|
||||
{
|
||||
public class SaveDataCoverter
|
||||
{
|
||||
|
||||
public static bool InsertTargetDB_new(long uid, bool is_female, string name, byte[] targetdata)
|
||||
{
|
||||
string str = "INSERT INTO \"public\".\"characters\" (\"user_id\", \"is_female\", \"is_new_character\", \"name\", \"unk_desc_string\", \"gr\", \"hr\", \"weapon_type\", \"last_login\", \"savedata\", \"decomyset\", \"hunternavi\", \"otomoairou\", \"partner\", \"platebox\", \"platedata\", \"platemyset\", \"rengokudata\", \"savemercenary\", \"restrict_guild_scout\", \"minidata\", \"gacha_items\", \"daily_time\", \"house_info\", \"login_boost\", \"skin_hist\", \"kouryou_point\", \"gcp\", \"guild_post_checked\", \"time_played\", \"weapon_id\", \"scenariodata\", \"savefavoritequest\", \"friends\", \"blocked\", \"deleted\", \"cafe_time\", \"netcafe_points\", \"boost_time\", \"cafe_reset\", \"bonus_quests\", \"daily_quests\", \"promo_points\", \"rasta_id\", \"pact_id\", \"stampcard\", \"mezfes\") " +
|
||||
$"VALUES ({uid}, '{(is_female ? "t" : "f")}', 'f', '{name}', '', 0, 0, 0, 1750087006, @savedata, NULL, NULL, NULL, E'\\\\001cmp 20110113 \\\\000\\\\000\\\\002\\\\001\\\\250\\\\000\\\\377\\\\000\\\\255'::bytea, NULL, NULL, NULL, NULL, NULL, 'f', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-05-26 11:24:26.725902+08', 0, 0, E'\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000'::bytea, E'\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000'::bytea, '', '', 'f', 0, 0, NULL, NULL, 0, 0, 0, NULL, NULL, 0, NULL);";
|
||||
var savedataparam = new NpgsqlParameter("@savedata", NpgsqlDbType.Bytea);
|
||||
savedataparam.Value = targetdata;
|
||||
return SQLRUN_TARGET_DB.ExcuteSQL(str, new List<NpgsqlParameter> { savedataparam });
|
||||
}
|
||||
|
||||
|
||||
public static bool UpdateTargetDB_old(long cid, byte[] targetdata)
|
||||
{
|
||||
string str = $"UPDATE \"characters\" set savedata = @savedata where \"id\" = {cid};";
|
||||
var savedataparam = new NpgsqlParameter("@savedata", NpgsqlDbType.Bytea);
|
||||
savedataparam.Value = targetdata;
|
||||
return SQLRUN_SRC_DB.ExcuteSQL(str, new List<NpgsqlParameter> { savedataparam });
|
||||
}
|
||||
public static bool loadCharacterOLD(long cid, out string name, out bool is_female, out byte[] data)
|
||||
{
|
||||
string sql = $"SELECT \"name\",savedata,is_female from \"characters\" WHERE id = {cid}";
|
||||
@ -60,5 +80,25 @@ namespace Axibug.MHFSaveAutoConverter.Data
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool FixedSaveData(MHFVer from, MHFVer target, byte[] src, out byte[] targetdata, out string err)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] decdata = MHFCompression.Decompress(src);
|
||||
SaveDataEntity se = new SaveDataEntity(from, target, decdata);
|
||||
targetdata = se.FixedEquipBox(decdata, out string log);
|
||||
err = default;
|
||||
Console.WriteLine(log);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
err = ex.ToString();
|
||||
targetdata = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Data;
|
||||
using static Axibug.MHFSaveAutoConverter.DataStruct.DataStruct;
|
||||
using static Axibug.MHFSaveAutoConverter.DataStruct.MHFSaveDataCfg;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
{
|
||||
public class SaveDataEntity
|
||||
@ -70,6 +71,35 @@ namespace Axibug.MHFSaveAutoConverter.DataStruct
|
||||
Console.WriteLine("====写入完毕====");
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public byte[] FixedEquipBox(byte[] srcdata, out string log)
|
||||
{
|
||||
log = null;
|
||||
byte[] targetdata = srcdata.ToArray();
|
||||
|
||||
Console.WriteLine("====尝试开始写入====");
|
||||
foreach (var singledata in saveHandles)
|
||||
{
|
||||
if (!(singledata is s_Itembox itembox))
|
||||
continue;
|
||||
|
||||
itembox.FixedData(out log);
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine(singledata.GetType().Name);
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
string str = singledata.ToString();
|
||||
if (str.Length > 100)
|
||||
str = str.Substring(0, 100) + "...";
|
||||
|
||||
bool ret = singledata.Write(TargetVer, targetdata);
|
||||
Console.WriteLine($"写入:{singledata.GetType().Name} =>{(ret ? "成功" : "失败")}");
|
||||
Console.WriteLine(str);
|
||||
}
|
||||
Console.WriteLine("====写入完毕====");
|
||||
return targetdata;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
83
Program.cs
83
Program.cs
@ -1,8 +1,12 @@
|
||||
using Axibug.MHFSaveAutoConverter.Data;
|
||||
using Axibug.MHFSaveAutoConverter.DataStruct;
|
||||
using Axibug.MHFSaveAutoConverter.SQL;
|
||||
using HaoYue.MHFUserSrv.Server.Common;
|
||||
using MonsterHunterSaveBruteForce;
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Text;
|
||||
using static Axibug.MHFSaveAutoConverter.DataStruct.MHFSaveDataCfg;
|
||||
|
||||
@ -13,6 +17,7 @@ namespace Axibug.MHFSaveAutoConverter
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
//MH2DosSaveDataLoader.LoadSaveData();
|
||||
Console.Title = "皓月云MHF存档迁移工具 ver 0.1.0";
|
||||
Console.WriteLine("读取配置");
|
||||
try
|
||||
@ -29,6 +34,24 @@ namespace Axibug.MHFSaveAutoConverter
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine($"==欢迎使用 {Console.Title} Axibug.MHFSaveAutoConverter==");
|
||||
|
||||
int funcid = 0;
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine("Step0.使用什么功能?[0]存档继承,[1]存档修复 What function to use? [0] userdata inheritance, [1] userdata repair");
|
||||
string var = Console.ReadLine();
|
||||
if (!int.TryParse(var, out funcid))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (funcid == 1)
|
||||
{
|
||||
FixedItemBox();
|
||||
break;
|
||||
}
|
||||
|
||||
string[] verlist = Enum.GetNames(typeof(MHFVer));
|
||||
|
||||
MHFVer src;
|
||||
@ -73,7 +96,7 @@ namespace Axibug.MHFSaveAutoConverter
|
||||
continue;
|
||||
}
|
||||
Console.WriteLine("===>操作的角色ID:" + cid);
|
||||
if (!SaveDataCoverter.loadCharacterOLD(cid, out string name,out bool is_female, out byte[] srcdata))
|
||||
if (!SaveDataCoverter.loadCharacterOLD(cid, out string name, out bool is_female, out byte[] srcdata))
|
||||
{
|
||||
Console.WriteLine("读取失败");
|
||||
continue;
|
||||
@ -112,7 +135,7 @@ namespace Axibug.MHFSaveAutoConverter
|
||||
}
|
||||
|
||||
//if (!UpdateTargetDB(targetuserid, is_female, name, targetdata))
|
||||
if (!InsertTargetDB(targetuserid, is_female, name, targetdata))
|
||||
if (!SaveDataCoverter.InsertTargetDB_new(targetuserid, is_female, name, targetdata))
|
||||
{
|
||||
Console.WriteLine($"写入目标{target}数据库失败");
|
||||
continue;
|
||||
@ -124,22 +147,54 @@ namespace Axibug.MHFSaveAutoConverter
|
||||
}
|
||||
|
||||
|
||||
public static bool InsertTargetDB(long uid,bool is_female,string name, byte[] targetdata)
|
||||
|
||||
public static bool FixedItemBox()
|
||||
{
|
||||
string str = "INSERT INTO \"public\".\"characters\" (\"user_id\", \"is_female\", \"is_new_character\", \"name\", \"unk_desc_string\", \"gr\", \"hr\", \"weapon_type\", \"last_login\", \"savedata\", \"decomyset\", \"hunternavi\", \"otomoairou\", \"partner\", \"platebox\", \"platedata\", \"platemyset\", \"rengokudata\", \"savemercenary\", \"restrict_guild_scout\", \"minidata\", \"gacha_items\", \"daily_time\", \"house_info\", \"login_boost\", \"skin_hist\", \"kouryou_point\", \"gcp\", \"guild_post_checked\", \"time_played\", \"weapon_id\", \"scenariodata\", \"savefavoritequest\", \"friends\", \"blocked\", \"deleted\", \"cafe_time\", \"netcafe_points\", \"boost_time\", \"cafe_reset\", \"bonus_quests\", \"daily_quests\", \"promo_points\", \"rasta_id\", \"pact_id\", \"stampcard\", \"mezfes\") " +
|
||||
$"VALUES ({uid}, '{(is_female?"t":"f")}', 'f', '{name}', '', 0, 0, 0, 1750087006, @savedata, NULL, NULL, NULL, E'\\\\001cmp 20110113 \\\\000\\\\000\\\\002\\\\001\\\\250\\\\000\\\\377\\\\000\\\\255'::bytea, NULL, NULL, NULL, NULL, NULL, 'f', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-05-26 11:24:26.725902+08', 0, 0, E'\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000'::bytea, E'\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\001\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000'::bytea, '', '', 'f', 0, 0, NULL, NULL, 0, 0, 0, NULL, NULL, 0, NULL);";
|
||||
var savedataparam = new NpgsqlParameter("@savedata", NpgsqlDbType.Bytea);
|
||||
savedataparam.Value = targetdata;
|
||||
return SQLRUN_TARGET_DB.ExcuteSQL(str,new List<NpgsqlParameter> { savedataparam });
|
||||
string[] verlist = Enum.GetNames(typeof(MHFVer));
|
||||
MHFVer src;
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine("Step1.选择要继承的角色的原始MHF版本: Select the original MHF version of the character you want to inherit:");
|
||||
for (int i = 0; i < verlist.Length; i++)
|
||||
Console.WriteLine($"[{i}]{verlist[i]}");
|
||||
|
||||
int srcidx;
|
||||
string ver = Console.ReadLine();
|
||||
if (!int.TryParse(ver, out srcidx))
|
||||
continue;
|
||||
if (srcidx >= 0 && srcidx < verlist.Length)
|
||||
{
|
||||
src = (MHFVer)Enum.Parse(typeof(MHFVer), verlist[srcidx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Console.WriteLine($"step3.请输入[{src}]版本中的源Characters表中的角色ID: Please enter the character ID from the source Characters table in [{src}] version:");
|
||||
if (!long.TryParse(Console.ReadLine(), out long cid))
|
||||
{
|
||||
Console.WriteLine("输入有误");
|
||||
return false;
|
||||
}
|
||||
Console.WriteLine("===>操作的角色ID:" + cid);
|
||||
if (!SaveDataCoverter.loadCharacterOLD(cid, out string name, out bool is_female, out byte[] srcdata))
|
||||
{
|
||||
Console.WriteLine("读取失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static bool UpdateTargetDB(long cid, bool is_female, string name, byte[] targetdata)
|
||||
if (!SaveDataCoverter.FixedSaveData(src, src, srcdata, out byte[] targetdata, out string err))
|
||||
{
|
||||
string str = $"UPDATE \"characters\" set savedata = @savedata where \"id\" = {cid};";
|
||||
var savedataparam = new NpgsqlParameter("@savedata", NpgsqlDbType.Bytea);
|
||||
savedataparam.Value = targetdata;
|
||||
return SQLRUN_TARGET_DB.ExcuteSQL(str, new List<NpgsqlParameter> { savedataparam });
|
||||
Console.WriteLine($"处理失败:{err}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SaveDataCoverter.UpdateTargetDB_old(cid, targetdata))
|
||||
{
|
||||
Console.WriteLine($"处理失败:{err}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine($"写入玩家{name}修正数据");
|
||||
return true;
|
||||
}
|
||||
|
||||
//public static SaveDataEntity SetData(long cid, string name, byte[] srcdata)
|
||||
|
||||
@ -88,7 +88,8 @@ namespace Axibug.MHFSaveAutoConverter.SQL
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ExcuteSQL(string strSql)
|
||||
|
||||
public static bool ExcuteSQL(string strSql, List<NpgsqlParameter> param = null)
|
||||
{
|
||||
NpgsqlConnection con = GetSqlConnect();
|
||||
bool bneedPush = true;
|
||||
@ -100,6 +101,13 @@ namespace Axibug.MHFSaveAutoConverter.SQL
|
||||
{
|
||||
using (NpgsqlCommand SqlCommand = new NpgsqlCommand(strSqlinsert, con))
|
||||
{
|
||||
if (param != null)
|
||||
{
|
||||
foreach (NpgsqlParameter p in param)
|
||||
{
|
||||
SqlCommand.Parameters.Add(p);
|
||||
}
|
||||
}
|
||||
setnumbert = SqlCommand.ExecuteNonQuery();
|
||||
}
|
||||
PushConnect(con);
|
||||
@ -115,6 +123,33 @@ namespace Axibug.MHFSaveAutoConverter.SQL
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//public static bool ExcuteSQL(string strSql)
|
||||
//{
|
||||
// NpgsqlConnection con = GetSqlConnect();
|
||||
// bool bneedPush = true;
|
||||
// if (string.IsNullOrEmpty(strSql))
|
||||
// return false;
|
||||
// string strSqlinsert = strSql;
|
||||
// int setnumbert = 0;
|
||||
// try
|
||||
// {
|
||||
// using (NpgsqlCommand SqlCommand = new NpgsqlCommand(strSqlinsert, con))
|
||||
// {
|
||||
// setnumbert = SqlCommand.ExecuteNonQuery();
|
||||
// }
|
||||
// PushConnect(con);
|
||||
// bneedPush = false;
|
||||
// return true;
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// if (bneedPush)
|
||||
// {
|
||||
// PushConnect(con);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
public static DateTime ConvertTimestamptzToDatetime(object obj)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user