Commit 81bac10e authored by hex's avatar hex

Replay: keep .yrp3d playback; export decks from embedded .yrp

parent 1cd5d12a
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using UnityEngine;
using YGOSharp.OCGWrapper.Enums;
public class selectReplay : WindowServantSP
{
......@@ -64,8 +65,6 @@ public class selectReplay : WindowServantSP
KF_replay(superScrollView.selectedString);
}
PrecyOcg precy;
private void onGod()
{
if (!superScrollView.Selected())
......@@ -76,7 +75,7 @@ public class selectReplay : WindowServantSP
{
return;
}
KF_replay(superScrollView.selectedString, true);
RMSshow_none(InterString.Get("旧录像上帝视角已移除(仅支持联机对战与 .yrp3d 录像)。"));
}
private void onSort()
......@@ -132,219 +131,182 @@ public class selectReplay : WindowServantSP
);
}
byte[] getYRPbuffer(string path)
private void onYdk()
{
if (path.Substring(path.Length - 4, 4) == ".yrp")
if (!superScrollView.Selected())
{
return File.ReadAllBytes(path);
return;
}
byte[] returnValue = null;
try
string yrp3dPath = "replay/" + superScrollView.selectedString + ".yrp3d";
if (!File.Exists(yrp3dPath))
{
var collection = TcpHelper.readPackagesInRecord(path);
foreach (var item in collection)
{
// Debug.Log(item.Fuction);
if (item.Fuction == (int)YGOSharp.OCGWrapper.Enums.GameMessage.sibyl_replay)
{
returnValue = item.Data.reader.ReadToEnd();
break;
}
}
RMSshow_none(InterString.Get("录像没有录制完整。"));
return;
}
catch (Exception e)
if (!TryGetEmbeddedYrpFromYrp3d(yrp3dPath, out byte[] yrpBytes))
{
// Debug.Log(e);
RMSshow_none(InterString.Get("该录像不包含可提取的卡组信息。"));
return;
}
if (!TryParseDecksFromYrp(yrpBytes, out List<List<int>> mainDecks, out List<List<int>> extraDecks))
{
RMSshow_none(InterString.Get("录像没有录制完整。"));
return;
}
if (mainDecks.Count == 0 || mainDecks.Count != extraDecks.Count)
{
RMSshow_none(InterString.Get("该录像不包含可提取的卡组信息。"));
return;
}
// Debug.Log(returnValue);
return returnValue;
}
Percy.YRP getYRP(byte[] buffer)
{
Percy.YRP returnValue = new Percy.YRP();
try
{
BinaryReader reader = new BinaryReader(new MemoryStream(buffer));
returnValue.ID = reader.ReadInt32();
returnValue.Version = reader.ReadInt32();
returnValue.Flag = reader.ReadInt32();
returnValue.Seed = reader.ReadUInt32();
returnValue.DataSize = reader.ReadInt32();
returnValue.Hash = reader.ReadInt32();
returnValue.Props = reader.ReadBytes(8);
if (returnValue.ID == 0x32707279) // REPLAY_ID_YRP2
{
for (int i = 0; i < 8; i++)
{
reader.ReadUInt32();
// returnValue.SeedsV2[i] = reader.ReadUInt32();
}
for (int i = 0; i < 4; i++) // other flags, unused for now
{
reader.ReadUInt32();
}
}
Directory.CreateDirectory("deck");
}
catch (Exception)
{
RMSshow_none(InterString.Get("写入失败!请检查文件夹权限。"));
return;
}
byte[] raw = reader.ReadToEnd();
if ((returnValue.Flag & 0x1) > 0)
for (int i = 0; i < mainDecks.Count; i++)
{
var builder = new StringBuilder();
builder.Append("#created by ygopro2\r\n#main\r\n");
for (int j = 0; j < mainDecks[i].Count; j++)
{
SevenZip.Compression.LZMA.Decoder lzma = new SevenZip.Compression.LZMA.Decoder();
lzma.SetDecoderProperties(returnValue.Props);
MemoryStream decompressed = new MemoryStream();
lzma.Code(
new MemoryStream(raw),
decompressed,
raw.LongLength,
returnValue.DataSize,
null
);
raw = decompressed.ToArray();
builder.Append(mainDecks[i][j]).Append("\r\n");
}
reader = new BinaryReader(new MemoryStream(raw));
if ((returnValue.Flag & 0x2) > 0)
builder.Append("#extra\r\n");
for (int j = 0; j < extraDecks[i].Count; j++)
{
Program.I().room.mode = 2;
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData[0].name = reader.ReadUnicode(20);
returnValue.playerData[1].name = reader.ReadUnicode(20);
returnValue.playerData[2].name = reader.ReadUnicode(20);
returnValue.playerData[3].name = reader.ReadUnicode(20);
returnValue.StartLp = reader.ReadInt32();
returnValue.StartHand = reader.ReadInt32();
returnValue.DrawCount = reader.ReadInt32();
returnValue.opt = reader.ReadInt32();
Program.I().ocgcore.MasterRule = returnValue.opt >> 16;
for (int i = 0; i < 4; i++)
{
int count = reader.ReadInt32();
for (int i2 = 0; i2 < count; i2++)
{
returnValue.playerData[i].main.Add(reader.ReadInt32());
}
count = reader.ReadInt32();
for (int i2 = 0; i2 < count; i2++)
{
returnValue.playerData[i].extra.Add(reader.ReadInt32());
}
}
builder.Append(extraDecks[i][j]).Append("\r\n");
}
else
string path = "deck/" + superScrollView.selectedString + "_" + (i + 1).ToString() + ".ydk";
try
{
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData.Add(new Percy.YRP.PlayerData());
returnValue.playerData[0].name = reader.ReadUnicode(20);
returnValue.playerData[1].name = reader.ReadUnicode(20);
returnValue.StartLp = reader.ReadInt32();
returnValue.StartHand = reader.ReadInt32();
returnValue.DrawCount = reader.ReadInt32();
returnValue.opt = reader.ReadInt32();
Program.I().ocgcore.MasterRule = returnValue.opt >> 16;
for (int i = 0; i < 2; i++)
{
int count = reader.ReadInt32();
for (int i2 = 0; i2 < count; i2++)
{
returnValue.playerData[i].main.Add(reader.ReadInt32());
}
count = reader.ReadInt32();
for (int i2 = 0; i2 < count; i2++)
{
returnValue.playerData[i].extra.Add(reader.ReadInt32());
}
}
File.WriteAllText(path, builder.ToString());
RMSshow_none(InterString.Get("卡组入库:[?]", path));
}
while (reader.BaseStream.Position < reader.BaseStream.Length)
catch (Exception)
{
returnValue.gameData.Add(reader.ReadBytes(reader.ReadByte()));
RMSshow_none(InterString.Get("写入失败!请检查文件夹权限。"));
return;
}
}
catch (Exception e)
{
// Debug.Log(e);
}
return returnValue;
}
private void onYdk()
private void onYrp()
{
if (!superScrollView.Selected())
RMSshow_none(InterString.Get("导出 .yrp 功能已移除(仅支持联机对战与 .yrp3d 录像)。"));
}
private static bool TryGetEmbeddedYrpFromYrp3d(string yrp3dPath, out byte[] yrpBytes)
{
yrpBytes = null;
List<Package> collection = TcpHelper.readPackagesInRecord(yrp3dPath);
for (int i = 0; i < collection.Count; i++)
{
return;
if (collection[i].Fuction == (int)GameMessage.sibyl_replay)
{
yrpBytes = collection[i].Data.get();
return yrpBytes != null && yrpBytes.Length > 0;
}
}
return false;
}
private static bool TryParseDecksFromYrp(
byte[] yrpBytes,
out List<List<int>> mainDecks,
out List<List<int>> extraDecks
)
{
mainDecks = null;
extraDecks = null;
try
{
Percy.YRP yrp;
if (File.Exists("replay/" + superScrollView.selectedString))
{
yrp = getYRP(File.ReadAllBytes("replay/" + superScrollView.selectedString));
}
else
{
yrp = getYRP(getYRPbuffer("replay/" + superScrollView.selectedString + ".yrp3d"));
}
for (int i = 0; i < yrp.playerData.Count; i++)
var headerReader = new BinaryReader(new MemoryStream(yrpBytes));
int id = headerReader.ReadInt32();
headerReader.ReadInt32(); // version
int flag = headerReader.ReadInt32();
headerReader.ReadUInt32(); // seed
int dataSize = headerReader.ReadInt32();
headerReader.ReadInt32(); // hash
byte[] props = headerReader.ReadBytes(8);
if (id == 0x32707279) // REPLAY_ID_YRP2
{
string value = "#created by ygopro2\r\n#main\r\n";
for (int i2 = 0; i2 < yrp.playerData[i].main.Count; i2++)
for (int i = 0; i < 8; i++)
{
value += yrp.playerData[i].main[i2].ToString() + "\r\n";
headerReader.ReadUInt32();
}
value += "#extra\r\n";
for (int i2 = 0; i2 < yrp.playerData[i].extra.Count; i2++)
for (int i = 0; i < 4; i++)
{
value += yrp.playerData[i].extra[i2].ToString() + "\r\n";
headerReader.ReadUInt32();
}
string name =
"deck/" + superScrollView.selectedString + "_" + (i + 1).ToString() + ".ydk";
File.WriteAllText(name, value);
RMSshow_none(InterString.Get("卡组入库:[?]", name));
}
if (yrp.playerData.Count == 0)
byte[] raw = headerReader.ReadToEnd();
if ((flag & 0x1) > 0)
{
RMSshow_none(InterString.Get("录像没有录制完整。"));
var lzma = new SevenZip.Compression.LZMA.Decoder();
lzma.SetDecoderProperties(props);
using (var decompressed = new MemoryStream())
{
lzma.Code(new MemoryStream(raw), decompressed, raw.LongLength, dataSize, null);
raw = decompressed.ToArray();
}
}
}
catch (Exception e)
{
// UnityEngine.Debug.Log(e);
RMSshow_none(InterString.Get("录像没有录制完整。"));
}
}
private void onYrp()
{
if (!superScrollView.Selected())
{
return;
}
try
{
if (File.Exists("replay/" + superScrollView.selectedString + ".yrp3d"))
var reader = new BinaryReader(new MemoryStream(raw));
int playerCount = ((flag & 0x2) > 0) ? 4 : 2;
for (int i = 0; i < playerCount; i++)
{
File.WriteAllBytes(
"replay/" + superScrollView.selectedString + ".yrp",
getYRPbuffer("replay/" + superScrollView.selectedString + ".yrp3d")
);
RMSshow_none(
InterString.Get(
"录像入库:[?]",
"replay/" + superScrollView.selectedString + ".yrp"
)
);
printFile();
reader.ReadUnicode(20);
}
else
reader.ReadInt32(); // StartLp
reader.ReadInt32(); // StartHand
reader.ReadInt32(); // DrawCount
reader.ReadInt32(); // opt
mainDecks = new List<List<int>>(playerCount);
extraDecks = new List<List<int>>(playerCount);
for (int i = 0; i < playerCount; i++)
{
RMSshow_none(InterString.Get("录像没有录制完整。"));
int mainCount = reader.ReadInt32();
var main = new List<int>(Mathf.Max(mainCount, 0));
for (int j = 0; j < mainCount; j++)
{
main.Add(reader.ReadInt32());
}
int extraCount = reader.ReadInt32();
var extra = new List<int>(Mathf.Max(extraCount, 0));
for (int j = 0; j < extraCount; j++)
{
extra.Add(reader.ReadInt32());
}
mainDecks.Add(main);
extraDecks.Add(extra);
}
return true;
}
catch (Exception)
{
RMSshow_none(InterString.Get("录像没有录制完整。"));
mainDecks = null;
extraDecks = null;
return false;
}
}
......@@ -461,44 +423,22 @@ public class selectReplay : WindowServantSP
{
if (god)
{
RMSshow_none(
InterString.Get("您正在观看旧版的录像(上帝视角),不保证稳定性。")
);
if (precy != null)
precy.dispose();
precy = new PrecyOcg();
var collections = TcpHelper.getPackages(
precy.ygopro.getYRP3dBuffer(
getYRP(getYRPbuffer("replay/" + name + ".yrp3d"))
)
);
pushCollection(collections);
}
else
{
var collection = TcpHelper.readPackagesInRecord("replay/" + name + ".yrp3d");
pushCollection(collection);
RMSshow_none(InterString.Get("旧录像上帝视角已移除(仅支持 .yrp3d 录像播放)。"));
return;
}
var collection = TcpHelper.readPackagesInRecord("replay/" + name + ".yrp3d");
pushCollection(collection);
return;
}
else
if (name.Length > 4 && name.Substring(name.Length - 4, 4) == ".yrp")
{
if (name.Length > 4 && name.Substring(name.Length - 4, 4) == ".yrp")
if (File.Exists("replay/" + name))
{
if (File.Exists("replay/" + name))
{
RMSshow_none(
InterString.Get("您正在观看旧版的录像(上帝视角),不保证稳定性。")
);
if (precy != null)
precy.dispose();
precy = new PrecyOcg();
var collections = TcpHelper.getPackages(
precy.ygopro.getYRP3dBuffer(getYRP(File.ReadAllBytes("replay/" + name)))
);
pushCollection(collections);
}
RMSshow_none(InterString.Get("旧版 .yrp 录像播放已移除(仅支持 .yrp3d)。"));
return;
}
}
RMSshow_none(InterString.Get("录像没有录制完整。"));
}
catch (Exception)
{
......@@ -527,6 +467,16 @@ public class selectReplay : WindowServantSP
public override void show()
{
base.show();
var godButton = UIHelper.getByName(gameObject, "god_");
if (godButton != null)
{
godButton.SetActive(false);
}
var yrpButton = UIHelper.getByName(gameObject, "yrp_");
if (yrpButton != null)
{
yrpButton.SetActive(false);
}
printFile();
Program.charge();
}
......@@ -556,13 +506,6 @@ public class selectReplay : WindowServantSP
fileInfos[i].Name.Substring(0, fileInfos[i].Name.Length - 6)
);
}
if (
fileInfos[i].Name.Length > 4
&& fileInfos[i].Name.Substring(fileInfos[i].Name.Length - 4, 4) == ".yrp"
)
{
superScrollView.add(fileInfos[i].Name);
}
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment