-.Close()'d everything.
-Added a FourScore header and applied it to ImportFile and ImportFCM. --Not sure if there's any equivalent header for FMV/FCM. -Seemingly have the update bytes being read properly. TODO: Make ImportFCM actually utilize the update bytes to write frames.
This commit is contained in:
parent
ff12c2c5ef
commit
bedbf1d5e1
|
@ -26,6 +26,7 @@ namespace BizHawk.MultiClient
|
|||
public const string RERECORDS = "rerecordCount";
|
||||
public const string GUID = "GUID";
|
||||
public const string STARTSFROMSAVESTATE = "StartsFromSavestate";
|
||||
public const string FOURSCORE = "FourScore";
|
||||
|
||||
public static string MovieVersion = "BizHawk v0.0.1";
|
||||
|
||||
|
|
|
@ -100,7 +100,8 @@ namespace BizHawk.MultiClient
|
|||
errorMsg = "";
|
||||
warningMsg = "";
|
||||
Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY);
|
||||
var file = new FileInfo(path);
|
||||
FileInfo file = new FileInfo(path);
|
||||
StreamReader sr = file.OpenText();
|
||||
string[] buttons = new string[] { };
|
||||
string controller = "";
|
||||
string emulator = "";
|
||||
|
@ -121,8 +122,6 @@ namespace BizHawk.MultiClient
|
|||
break;
|
||||
}
|
||||
m.Header.SetHeaderLine(MovieHeader.PLATFORM, platform);
|
||||
using (StreamReader sr = file.OpenText())
|
||||
{
|
||||
int lineNum = 0;
|
||||
string line = "";
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
|
@ -162,6 +161,7 @@ namespace BizHawk.MultiClient
|
|||
if (ParseHeader(line, "StartsFromSavestate") == "1")
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
sr.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,13 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
m.Header.SetHeaderLine("PAL", pal.ToString());
|
||||
}
|
||||
else if (line.StartsWith("fourscore"))
|
||||
m.Header.SetHeaderLine(
|
||||
MovieHeader.FOURSCORE,
|
||||
Convert.ToBoolean(
|
||||
int.Parse(ParseHeader(line, "fourscore"))
|
||||
).ToString()
|
||||
);
|
||||
else if (line.StartsWith("sub"))
|
||||
{
|
||||
Subtitle s = new Subtitle();
|
||||
|
@ -223,7 +230,7 @@ namespace BizHawk.MultiClient
|
|||
warningMsg = "FDS Insert";
|
||||
break;
|
||||
case '8':
|
||||
warningMsg = "FDS Select";
|
||||
warningMsg = "FDS Select Side";
|
||||
break;
|
||||
default:
|
||||
warningMsg = "unknown";
|
||||
|
@ -260,7 +267,7 @@ namespace BizHawk.MultiClient
|
|||
// Everything not explicitly defined is treated as a comment.
|
||||
m.Header.Comments.Add(line);
|
||||
}
|
||||
}
|
||||
sr.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -296,6 +303,8 @@ namespace BizHawk.MultiClient
|
|||
if (signature != "FCM\x1A")
|
||||
{
|
||||
errorMsg = "This is not a valid .FCM file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
// 004 4-byte little-endian unsigned int: version number, must be 2
|
||||
|
@ -317,6 +326,8 @@ namespace BizHawk.MultiClient
|
|||
if ((int)(flags & 2) == 0)
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
bool pal = false;
|
||||
|
@ -340,8 +351,13 @@ namespace BizHawk.MultiClient
|
|||
m.SetRerecords((int)rerecordCount);
|
||||
// 014 4-byte little-endian unsigned int: length of controller data in bytes
|
||||
uint movieDataSize = r.ReadUInt32();
|
||||
// 018 4-byte little-endian unsigned int: offset to the savestate inside file
|
||||
uint savestateOffset = r.ReadUInt32();
|
||||
/*
|
||||
018 4-byte little-endian unsigned int: offset to the savestate inside file
|
||||
The savestate offset is <header_size + length_of_metadata_in_bytes + padding>. The savestate offset should be
|
||||
4-byte aligned. At the savestate offset there is a savestate file. The savestate exists even if the movie is
|
||||
reset-based.
|
||||
*/
|
||||
r.ReadUInt32();
|
||||
// 01C 4-byte little-endian unsigned int: offset to the controller data inside file
|
||||
uint firstFrameOffset = r.ReadUInt32();
|
||||
// 020 16-byte md5sum of the ROM used
|
||||
|
@ -374,28 +390,115 @@ namespace BizHawk.MultiClient
|
|||
r.ReadByte();
|
||||
string author = System.Text.Encoding.UTF8.GetString(authorBytes.ToArray());
|
||||
m.Header.SetHeaderLine(MovieHeader.AUTHOR, author);
|
||||
// Advance to first byte of input data
|
||||
// byte[] throwaway = new byte[firstFrameOffset];
|
||||
// r.Read(throwaway, 0, (int)firstFrameOffset);
|
||||
// Advance to first byte of input data.
|
||||
r.BaseStream.Position = firstFrameOffset;
|
||||
// moviedatasize stuff
|
||||
// read frame data
|
||||
// TODO: special commands like fds disk switch, etc, and power/reset
|
||||
// TODO: use stringbuilder class for speed
|
||||
// string ButtonLookup = "RLDUSsBARLDUSsBARLDUSsBARLDUSsBA"; //TODO: This assumes input data is the same in fcm as bizhawk, which it isn't
|
||||
// string frame = "|0|"; //TODO: read reset command rather than hard code it off
|
||||
for (int frame = 0; frame < frameCount; frame++)
|
||||
string[] buttons = new string[8] { "A", "B", "Select", "Start", "Up", "Down", "Left", "Right" };
|
||||
bool fourscore = false;
|
||||
int frame = 1;
|
||||
while (frame <= frameCount)
|
||||
{
|
||||
byte update = r.ReadByte();
|
||||
SimpleController controllers = new SimpleController();
|
||||
controllers.Type = new ControllerDefinition();
|
||||
controllers.Type.Name = "NES Controller";
|
||||
if ((int)(update & 0x128) != 0)
|
||||
{
|
||||
// Control update: 1aabbbbb
|
||||
bool reset = false;
|
||||
int command = update & 0x1F;
|
||||
/*
|
||||
bbbbb:
|
||||
** 0 Do nothing
|
||||
** 1 Reset
|
||||
** 2 Power cycle
|
||||
** 7 VS System Insert Coin
|
||||
** 8 VS System Dipswitch 0 Toggle
|
||||
** 24 FDS Insert
|
||||
** 25 FDS Eject
|
||||
** 26 FDS Select Side
|
||||
*/
|
||||
switch (command)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
reset = true;
|
||||
controllers["Reset"] = true;
|
||||
break;
|
||||
case 2:
|
||||
reset = true;
|
||||
if (frame != 1)
|
||||
{
|
||||
warningMsg = "hard reset";
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
warningMsg = "VS System Insert Coin";
|
||||
break;
|
||||
case 8:
|
||||
warningMsg = "VS System Dipswitch 0 Toggle";
|
||||
break;
|
||||
case 24:
|
||||
warningMsg = "FDS Insert";
|
||||
break;
|
||||
case 25:
|
||||
warningMsg = "FDS Eject";
|
||||
break;
|
||||
case 26:
|
||||
warningMsg = "FDS Select Side";
|
||||
break;
|
||||
default:
|
||||
warningMsg = "unknown";
|
||||
break;
|
||||
}
|
||||
if (warningMsg != "")
|
||||
warningMsg = "Unable to import " + warningMsg + " command at frame " + frame + ".";
|
||||
/*
|
||||
1 Even if the header says "movie begins from reset", the file still contains a quicksave, and the
|
||||
quicksave is actually loaded. This flag can't therefore be trusted. To check if the movie actually begins
|
||||
from reset, one must analyze the controller data and see if the first non-idle command in the file is a
|
||||
Reset or Power Cycle type control command.
|
||||
*/
|
||||
if (!reset && frame == 1)
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
byte joy = r.ReadByte();
|
||||
// Read each byte of controller one data
|
||||
frame += "|";
|
||||
r.ReadBytes(3); //Lose remaining controllers for now
|
||||
m.AppendFrame("Test");
|
||||
Controller update: 0aabbccc
|
||||
* bb: Gamepad number minus one (?)
|
||||
*/
|
||||
int player = ((update >> 3) & 3) + 1;
|
||||
/*
|
||||
ccc:
|
||||
* 0 A
|
||||
* 1 B
|
||||
* 2 Select
|
||||
* 3 Start
|
||||
* 4 Up
|
||||
* 5 Down
|
||||
* 6 Left
|
||||
* 7 Right
|
||||
*/
|
||||
int button = update & 7;
|
||||
}
|
||||
// set 4 score flag if necessary
|
||||
// aa: Number of delta bytes to follow
|
||||
int delta = (update >> 5) & 3;
|
||||
MnemonicsGenerator mg = new MnemonicsGenerator();
|
||||
mg.SetSource(controllers);
|
||||
string mnemonic = mg.GetControllersAsMnemonic();
|
||||
while (false)
|
||||
m.AppendFrame(mnemonic);
|
||||
frame++;
|
||||
}
|
||||
m.Header.SetHeaderLine(MovieHeader.FOURSCORE, fourscore.ToString());
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -421,6 +524,8 @@ namespace BizHawk.MultiClient
|
|||
if (signature != "FMV\x1A")
|
||||
{
|
||||
errorMsg = "This is not a valid .FMV file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
// 004 1-byte flags:
|
||||
|
@ -432,6 +537,8 @@ namespace BizHawk.MultiClient
|
|||
if ((int)(flags & 0x80) != 0)
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
// 005 1-byte flags:
|
||||
|
@ -483,6 +590,8 @@ namespace BizHawk.MultiClient
|
|||
if (!controller1 && !controller2 && !FDS)
|
||||
{
|
||||
warningMsg = "No input recorded.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
/*
|
||||
|
@ -503,12 +612,6 @@ namespace BizHawk.MultiClient
|
|||
if (FDS)
|
||||
bytesPerFrame++;
|
||||
long frames = (fs.Length - 144) / bytesPerFrame;
|
||||
for (long frame = 0; frame < frames; frame++)
|
||||
{
|
||||
byte controllerstate;
|
||||
SimpleController controllers = new SimpleController();
|
||||
controllers.Type = new ControllerDefinition();
|
||||
controllers.Type.Name = "NES Controller";
|
||||
/*
|
||||
* 01 Right
|
||||
* 02 Left
|
||||
|
@ -520,6 +623,12 @@ namespace BizHawk.MultiClient
|
|||
* 80 Start
|
||||
*/
|
||||
string[] buttons = new string[8] { "Right", "Left", "Up", "Down", "B", "A", "Select", "Start" };
|
||||
for (long frame = 1; frame <= frames; frame++)
|
||||
{
|
||||
byte controllerstate;
|
||||
SimpleController controllers = new SimpleController();
|
||||
controllers.Type = new ControllerDefinition();
|
||||
controllers.Type.Name = "NES Controller";
|
||||
/*
|
||||
Each frame consists of 1 or more bytes. Controller 1 takes 1 byte, controller 2 takes 1 byte, and the FDS
|
||||
data takes 1 byte. If all three exist, the frame is 3 bytes. For example, if the movie is a regular NES game
|
||||
|
@ -552,6 +661,8 @@ namespace BizHawk.MultiClient
|
|||
mg.SetSource(controllers);
|
||||
m.AppendFrame(mg.GetControllersAsMnemonic());
|
||||
}
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -577,8 +688,12 @@ namespace BizHawk.MultiClient
|
|||
if (signature != "NSS\x1A")
|
||||
{
|
||||
errorMsg = "This is not a valid .NMV file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -614,6 +729,8 @@ namespace BizHawk.MultiClient
|
|||
if (signature != "MMV\0")
|
||||
{
|
||||
errorMsg = "This is not a valid .MMV file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
// 0004: 4-byte little endian unsigned int: dega version
|
||||
|
@ -629,6 +746,8 @@ namespace BizHawk.MultiClient
|
|||
if (reset == 0)
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
// 0014: 4-byte little endian unsigned int: offset of state information
|
||||
|
@ -675,12 +794,6 @@ namespace BizHawk.MultiClient
|
|||
// 00e4-00f3: binary: rom MD5 digest
|
||||
string MD5 = BytesToString(r, 16, true);
|
||||
m.Header.SetHeaderLine("MD5", MD5);
|
||||
for (int frame = 0; frame < frameCount; frame++)
|
||||
{
|
||||
byte controllerstate;
|
||||
SimpleController controllers = new SimpleController();
|
||||
controllers.Type = new ControllerDefinition();
|
||||
controllers.Type.Name = "SMS Controller";
|
||||
/*
|
||||
76543210
|
||||
* bit 0 (0x01): up
|
||||
|
@ -693,6 +806,12 @@ namespace BizHawk.MultiClient
|
|||
* bit 7 (0x80): start (Game Gear)
|
||||
*/
|
||||
string[] buttons = new string[6] { "Up", "Down", "Left", "Right", "B1", "B2" };
|
||||
for (int frame = 1; frame <= frameCount; frame++)
|
||||
{
|
||||
byte controllerstate;
|
||||
SimpleController controllers = new SimpleController();
|
||||
controllers.Type = new ControllerDefinition();
|
||||
controllers.Type.Name = "SMS Controller";
|
||||
/*
|
||||
Controller data is made up of one input packet per frame. Each packet currently consists of 2 bytes. The
|
||||
first byte is for controller 1 and the second controller 2. The Game Gear only uses the controller 1 input
|
||||
|
@ -717,6 +836,8 @@ namespace BizHawk.MultiClient
|
|||
mg.SetSource(controllers);
|
||||
m.AppendFrame(mg.GetControllersAsMnemonic());
|
||||
}
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -734,6 +855,8 @@ namespace BizHawk.MultiClient
|
|||
if (signature.Substring(0, 3) != "SMV")
|
||||
{
|
||||
errorMsg = "This is not a valid .SMV file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -750,6 +873,8 @@ namespace BizHawk.MultiClient
|
|||
default:
|
||||
{
|
||||
errorMsg = "SMV version not recognized, 143, 151, and 152 are currently supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -799,11 +924,11 @@ namespace BizHawk.MultiClient
|
|||
//TODO: get extra rom info
|
||||
|
||||
r.BaseStream.Position = FrameDataOffset;
|
||||
for (int x = 0; x < frameCount; x++)
|
||||
for (int frame = 1; frame <= frameCount; frame++)
|
||||
{
|
||||
//TODO: FF FF for all controllers = Reset
|
||||
//string frame = "|0|";
|
||||
for (int y = 0; y < numControllers; y++)
|
||||
for (int controller = 1; controller <= numControllers; controller++)
|
||||
{
|
||||
ushort fd = r.ReadUInt16();
|
||||
}
|
||||
|
@ -842,6 +967,8 @@ namespace BizHawk.MultiClient
|
|||
if (signature != 0x56424D1A)
|
||||
{
|
||||
errorMsg = "This is not a valid .VBM file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -865,6 +992,8 @@ namespace BizHawk.MultiClient
|
|||
if (startfromquicksave & startfromsram)
|
||||
{
|
||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -894,6 +1023,8 @@ namespace BizHawk.MultiClient
|
|||
if (is_gb & is_gbc & is_gba & is_sgb)
|
||||
{
|
||||
errorMsg = "Not a valid .VBM platform type.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
//TODO: set platform in header
|
||||
|
@ -916,6 +1047,8 @@ namespace BizHawk.MultiClient
|
|||
if ((flags & 0x08) != 0)
|
||||
{
|
||||
errorMsg = "Invalid .VBM file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
if ((flags & 0x04) != 0) rtcenable = true;
|
||||
|
@ -983,6 +1116,8 @@ namespace BizHawk.MultiClient
|
|||
MnemonicsGenerator mg = new MnemonicsGenerator();
|
||||
mg.SetSource(controllers);
|
||||
m.AppendFrame(mg.GetControllersAsMnemonic());
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -999,8 +1134,12 @@ namespace BizHawk.MultiClient
|
|||
if (signature != "VirtuaNES MV")
|
||||
{
|
||||
errorMsg = "This is not a valid .VMV file.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
}
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue