Rebirth: Mr Wang 解锁全CG
快速教程
重命名为 GameFrameworkSetting.dat
先关闭游戏,然后放入(或替换)
%HOMEPATH%/AppData/LocalLow/DSGame/Rebirth Mr Wang
文件夹下启动游戏,点击回想相册,理论上来说应该已经解锁了
实现过程
星宇来了想玩点黄油,懒得过剧情了想着直接看CG玩,于是开始找解锁全CG的教程,
找了一圈也没找到,所以就开始自己探索通往涩涩的道路,
这类黄油一般都是Unity做的,直接找到%HOMEPATH%/AppData/LocalLow/DSGame/Rebirth Mr Wang
路径,路径下有三个文件,
GameFrameworkSetting.dat
Label.sav
和 Player.log
. 经过一番摸索后发现GameFrameworkSetting.dat里大概长这样:
由于没接触过Unity,所以我暂时没管这堆乱码,去掉这些乱码应该是一个JSON格式,可以看到Revive下有8个JsonObject,每个都有 IsLock
字段,正好对应8个CG,所以我直接推测这就是控制CG解锁的内容
但是CG未解锁的时候IsLock不应该是true吗(划掉)
所以我直接把这8个false全改成了true,原以为这样就可以快快乐乐的开冲了,但是启动游戏后发现回想相册里啥也没有,看了一眼Player.log,报了读取文件的错
又试了一会依然没用,只能开始想办法逆向读取和写入这个文件的代码了
根据Player.log里的报错记录,可以看见加载里用到了StarForce这个类,在Assembly-CSharp.dll这个dll里可以找到,然后顺藤摸瓜一路找到DefaultSetting这个类里面的反序列化方法
可以看到这里就是一些基本的读取操作,再追踪传进来的这个BinaryReader,在GameFrameworkSerializer里:
可以看到这个reader在传进来前被读取了四次,最后进入callback,也就是上面的Deserialize方法
接下来写一个读取的代码:
CG类
public class CG
{
public bool IsLock { get;set; }
public int passId { get; set; }
public int StartingEventId { get; set; }
public int StartingSceneId { get; set; }
public int EndingEventId { get; set; }
public int UnlockEventId { get; set; }
public int Index { get; set; }
public CG()
{
}
}
读取类
using LitJson;
SortedDictionary<string, string> m_Settings = new SortedDictionary<string, string>();
byte version;
// 反序列化
FileStream stream = new FileStream("E:/WORKSPACE/rebirth_crack/GameFrameworkSetting.dat", FileMode.Open, FileAccess.ReadWrite);
using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8))
{
reader.ReadByte();
reader.ReadByte();
reader.ReadByte();
version = reader.ReadByte();
int num = reader.Read7BitEncodedInt32();
Console.WriteLine(num);
for (int i = 0; i < num; i++)
{
string key = reader.ReadString();
string value = reader.ReadString();
Console.WriteLine(key + " : " + value);
m_Settings.Add(key,value);
}
// 使用LitJson解析JSON字符串,再解析回去
List<CG> list = JsonMapper.ToObject<List<CG>>(m_Settings["Revive"]);
list.ForEach(cg => cg.IsLock = true);
m_Settings["Revive"] = JsonMapper.ToJson(list);
};
这样读取并修改里面的内容就完成了
然后要把修改完后的内容再写回去
找到GameFrameworkSerializer类里的Serialize方法:
public bool Serialize(Stream stream, T data, byte version)
{
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8))
{
byte[] header = this.GetHeader();
writer.Write(header[0]);
writer.Write(header[1]);
writer.Write(header[2]);
writer.Write(version);
SerializeCallback<T> callback = null;
if (!this.m_SerializeCallbacks.TryGetValue(version, out callback))
{
throw new GameFrameworkException(Utility.Text.Format("Serialize callback '{0}' is not exist.", version.ToString()));
}
return callback(writer, data);
}
}
可以看到这里先写了3个字节的header,然后写了一个version,这个header是在GameFramework的代码里直接设置的,version直接读取原文件的第四个字节应该就好了(前面用了version这个变量存)
header可以在GameFramework的DefaultSettingSerializer里找到:
然后写入设置部分的代码可以在DefaultSetting里找到,这也是作为一个callback使用的
有了这些之后,就可以开始写写入的代码了
FileStream writeStream = new FileStream("E:/WORKSPACE/rebirth_crack/GameFrameworkSetting.dat", FileMode.Open, FileAccess.ReadWrite);
using (BinaryWriter writer = new BinaryWriter(writeStream, Encoding.UTF8))
{
byte[] Header = new byte[] { 0x45, 0x4c, 0x53 };
writer.Write(Header[0]);
writer.Write(Header[1]);
writer.Write(Header[2]);
writer.Write(version);
writer.Write7BitEncodedInt(m_Settings.Count);
foreach( KeyValuePair<string, string> pair in m_Settings)
{
writer.Write(pair.Key);
writer.Write(pair.Value);
}
writer.Flush();
}
接下来这个GameFrameworkSetting.dat就是解锁CG之后的文件了,可以正常使用