Convert mc2 to new import style, properly support pcecd flag, and number of controller ports
This commit is contained in:
parent
ced5b313a5
commit
c1516de259
|
@ -156,6 +156,7 @@
|
|||
<Compile Include="movie\bk2\StringLogs.cs" />
|
||||
<Compile Include="movie\import\FcmImport.cs" />
|
||||
<Compile Include="movie\import\LsmvImport.cs" />
|
||||
<Compile Include="movie\import\Mc2Import.cs" />
|
||||
<Compile Include="movie\import\PxmImport.cs" />
|
||||
<Compile Include="movie\tasproj\IStateManager.cs" />
|
||||
<Compile Include="movie\tasproj\StateManagerDecay.cs" />
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
|
||||
namespace BizHawk.Client.Common.movie.import
|
||||
{
|
||||
// MC2 file format: http://code.google.com/p/pcejin/wiki/MC2
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
[ImportExtension(".mc2")]
|
||||
public class Mc2Import : MovieImporter
|
||||
{
|
||||
private PceControllerDeck _deck;
|
||||
|
||||
protected override void RunImport()
|
||||
{
|
||||
var ss = new PCEngine.PCESyncSettings
|
||||
{
|
||||
Port1 = PceControllerType.Unplugged,
|
||||
Port2 = PceControllerType.Unplugged,
|
||||
Port3 = PceControllerType.Unplugged,
|
||||
Port4 = PceControllerType.Unplugged,
|
||||
Port5 = PceControllerType.Unplugged
|
||||
};
|
||||
|
||||
_deck = new PceControllerDeck(
|
||||
ss.Port1,
|
||||
ss.Port2,
|
||||
ss.Port3,
|
||||
ss.Port4,
|
||||
ss.Port5);
|
||||
|
||||
Result.Movie.HeaderEntries[HeaderKeys.PLATFORM] = "PCE";
|
||||
using var sr = SourceFile.OpenText();
|
||||
string line;
|
||||
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] == '|')
|
||||
{
|
||||
ImportTextFrame(line);
|
||||
}
|
||||
else if (line.ToLower()
|
||||
.StartsWith("ports"))
|
||||
{
|
||||
var portNumStr = ParseHeader(line, "ports");
|
||||
if (int.TryParse(portNumStr, out int ports))
|
||||
{
|
||||
// Ugh
|
||||
if (ports > 0)
|
||||
{
|
||||
ss.Port1 = PceControllerType.GamePad;
|
||||
}
|
||||
|
||||
if (ports > 1)
|
||||
{
|
||||
ss.Port2 = PceControllerType.GamePad;
|
||||
}
|
||||
|
||||
if (ports > 2)
|
||||
{
|
||||
ss.Port3 = PceControllerType.GamePad;
|
||||
}
|
||||
|
||||
if (ports > 3)
|
||||
{
|
||||
ss.Port4 = PceControllerType.GamePad;
|
||||
}
|
||||
|
||||
if (ports > 4)
|
||||
{
|
||||
ss.Port5 = PceControllerType.GamePad;
|
||||
}
|
||||
|
||||
_deck = new PceControllerDeck(
|
||||
ss.Port1,
|
||||
ss.Port2,
|
||||
ss.Port3,
|
||||
ss.Port4,
|
||||
ss.Port5);
|
||||
}
|
||||
}
|
||||
else if (line.ToLower().StartsWith("pcecd"))
|
||||
{
|
||||
Result.Movie.HeaderEntries[HeaderKeys.PLATFORM] = "PCECD";
|
||||
}
|
||||
else if (line.ToLower().StartsWith("emuversion"))
|
||||
{
|
||||
Result.Movie.Comments.Add($"{EmulationOrigin} Mednafen/PCEjin version {ParseHeader(line, "emuVersion")}");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("version"))
|
||||
{
|
||||
string version = ParseHeader(line, "version");
|
||||
Result.Movie.Comments.Add($"{MovieOrigin} .mc2 version {version}");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("romfilename"))
|
||||
{
|
||||
Result.Movie.HeaderEntries[HeaderKeys.GAMENAME] = ParseHeader(line, "romFilename");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("cdgamename"))
|
||||
{
|
||||
Result.Movie.HeaderEntries[HeaderKeys.GAMENAME] = ParseHeader(line, "cdGameName");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("comment author"))
|
||||
{
|
||||
Result.Movie.HeaderEntries[HeaderKeys.AUTHOR] = ParseHeader(line, "comment author");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("rerecordcount"))
|
||||
{
|
||||
int rerecordCount;
|
||||
|
||||
// Try to parse the re-record count as an integer, defaulting to 0 if it fails.
|
||||
try
|
||||
{
|
||||
rerecordCount = int.Parse(ParseHeader(line, "rerecordCount"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
rerecordCount = 0;
|
||||
}
|
||||
|
||||
Result.Movie.Rerecords = (ulong)rerecordCount;
|
||||
}
|
||||
else if (line.ToLower().StartsWith("startsfromsavestate"))
|
||||
{
|
||||
// If this movie starts from a savestate, we can't support it.
|
||||
if (ParseHeader(line, "StartsFromSavestate") == "1")
|
||||
{
|
||||
Result.Errors.Add("Movies that begin with a savestate are not supported.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything not explicitly defined is treated as a comment.
|
||||
Result.Movie.Comments.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(ss);
|
||||
}
|
||||
|
||||
// Import a frame from a text-based format.
|
||||
private void ImportTextFrame(string line)
|
||||
{
|
||||
var buttons = new[] { "Up", "Down", "Left", "Right", "B1", "B2", "Run", "Select" };
|
||||
|
||||
var controllers = new SimpleController { Definition = _deck.Definition };
|
||||
|
||||
// Split up the sections of the frame.
|
||||
string[] sections = line.Split('|');
|
||||
|
||||
/*
|
||||
Skip the first two sections of the split, which consist of everything before the starting | and the command.
|
||||
Do not use the section after the last |. In other words, get the sections for the players.
|
||||
*/
|
||||
int start = 2;
|
||||
int end = sections.Length - 1;
|
||||
int playerOffset = -1;
|
||||
|
||||
for (int section = start; section < end; section++)
|
||||
{
|
||||
// The player number is one less than the section number for the reasons explained above.
|
||||
int player = section + playerOffset;
|
||||
string prefix = $"P{player} ";
|
||||
|
||||
// Only count lines with that have the right number of buttons and are for valid players.
|
||||
if (
|
||||
sections[section].Length == buttons.Length)
|
||||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
// Consider the button pressed so long as its spot is not occupied by a ".".
|
||||
controllers[prefix + buttons[button]] = sections[section][button] != '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the data for the controllers to a mnemonic and add it as a frame.
|
||||
Result.Movie.AppendFrame(controllers);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -145,9 +145,6 @@ namespace BizHawk.Client.Common
|
|||
case ".GMV":
|
||||
m = ImportGmv(path, out errorMsg, out warningMsg);
|
||||
break;
|
||||
case ".MC2":
|
||||
m = ImportMc2(path, out errorMsg, out warningMsg);
|
||||
break;
|
||||
case ".MMV":
|
||||
m = ImportMmv(path, out errorMsg, out warningMsg);
|
||||
break;
|
||||
|
@ -205,40 +202,11 @@ namespace BizHawk.Client.Common
|
|||
return extensions.Any(ext => extension.ToUpper() == $".{ext}");
|
||||
}
|
||||
|
||||
// Reduce all whitespace to single spaces.
|
||||
private static string SingleSpaces(string line)
|
||||
{
|
||||
line = line.Replace("\t", " ");
|
||||
line = line.Replace("\n", " ");
|
||||
line = line.Replace("\r", " ");
|
||||
line = line.Replace("\r\n", " ");
|
||||
string prev;
|
||||
do
|
||||
{
|
||||
prev = line;
|
||||
line = line.Replace(" ", " ");
|
||||
}
|
||||
while (prev != line);
|
||||
return line;
|
||||
}
|
||||
|
||||
// Import a frame from a text-based format.
|
||||
private static BkmMovie ImportTextFrame(string line, int lineNum, BkmMovie m, string path, string platform, ref string warningMsg)
|
||||
{
|
||||
string[] buttons = { };
|
||||
var controller = "";
|
||||
var ext = path != null ? Path.GetExtension(path).ToUpper() : "";
|
||||
switch (ext)
|
||||
{
|
||||
case ".MC2":
|
||||
buttons = new[] { "Up", "Down", "Left", "Right", "B1", "B2", "Run", "Select" };
|
||||
controller = "PC Engine Controller";
|
||||
break;
|
||||
case ".YMV":
|
||||
buttons = new[] { "Left", "Right", "Up", "Down", "Start", "A", "B", "C", "X", "Y", "Z", "L", "R" };
|
||||
controller = "Saturn Controller";
|
||||
break;
|
||||
}
|
||||
var buttons = new[] { "Left", "Right", "Up", "Down", "Start", "A", "B", "C", "X", "Y", "Z", "L", "R" };
|
||||
var controller = "Saturn Controller";
|
||||
|
||||
var controllers = new SimpleController { Definition = new ControllerDefinition { Name = controller } };
|
||||
|
||||
|
@ -258,12 +226,6 @@ namespace BizHawk.Client.Common
|
|||
// The player number is one less than the section number for the reasons explained above.
|
||||
int player = section + playerOffset;
|
||||
string prefix = $"P{player} ";
|
||||
|
||||
// Gameboy doesn't currently have a prefix saying which player the input is for.
|
||||
if (controllers.Definition.Name == "Gameboy Controller")
|
||||
{
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
// Only count lines with that have the right number of buttons and are for valid players.
|
||||
if (
|
||||
|
@ -283,47 +245,16 @@ namespace BizHawk.Client.Common
|
|||
return m;
|
||||
}
|
||||
|
||||
// Import a subtitle from a text-based format.
|
||||
private static BkmMovie ImportTextSubtitle(string line, BkmMovie m, string path)
|
||||
{
|
||||
line = SingleSpaces(line);
|
||||
|
||||
// The header name, frame, and message are separated by whitespace.
|
||||
int first = line.IndexOf(' ');
|
||||
int second = line.IndexOf(' ', first + 1);
|
||||
if (first != -1 && second != -1)
|
||||
{
|
||||
// Concatenate the frame and message with default values for the additional fields.
|
||||
var frame = line.Substring(0, first);
|
||||
var length = line.Substring(first + 1, second - first - 1);
|
||||
|
||||
string message = line.Substring(second + 1).Trim();
|
||||
m.Subtitles.AddFromString($"subtitle {frame} 0 0 {length} FFFFFFFF {message}");
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
// Import a text-based movie format. This works for .MC2 and .YMV.
|
||||
private static BkmMovie ImportText(string path, out string errorMsg, out string warningMsg)
|
||||
// YMV file format: https://code.google.com/p/yabause-rr/wiki/YMVfileformat
|
||||
private static BkmMovie ImportYmv(string path, out string errorMsg, out string warningMsg)
|
||||
{
|
||||
errorMsg = warningMsg = "";
|
||||
var m = new BkmMovie(path);
|
||||
var file = new FileInfo(path);
|
||||
var sr = file.OpenText();
|
||||
var emulator = "";
|
||||
var platform = "";
|
||||
switch (Path.GetExtension(path).ToUpper())
|
||||
{
|
||||
case ".MC2":
|
||||
emulator = "Mednafen/PCEjin";
|
||||
platform = "PCE";
|
||||
break;
|
||||
case ".YMV":
|
||||
emulator = "Yabause";
|
||||
platform = "Sega Saturn";
|
||||
break;
|
||||
}
|
||||
|
||||
var emulator = "Yabause";
|
||||
var platform = "Sega Saturn";
|
||||
|
||||
m.Header[HeaderKeys.PLATFORM] = platform;
|
||||
int lineNum = 0;
|
||||
|
@ -345,10 +276,6 @@ namespace BizHawk.Client.Common
|
|||
return null;
|
||||
}
|
||||
}
|
||||
else if (line.ToLower().StartsWith("sub"))
|
||||
{
|
||||
m = ImportTextSubtitle(line, m, path);
|
||||
}
|
||||
else if (line.ToLower().StartsWith("emuversion"))
|
||||
{
|
||||
m.Comments.Add($"{EMULATIONORIGIN} {emulator} version {ParseHeader(line, "emuVersion")}");
|
||||
|
@ -362,10 +289,6 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
m.Header[HeaderKeys.GAMENAME] = ParseHeader(line, "romFilename");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("cdgamename"))
|
||||
{
|
||||
m.Header[HeaderKeys.GAMENAME] = ParseHeader(line, "cdGameName");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("comment author"))
|
||||
{
|
||||
m.Header[HeaderKeys.AUTHOR] = ParseHeader(line, "comment author");
|
||||
|
@ -396,11 +319,6 @@ namespace BizHawk.Client.Common
|
|||
return null;
|
||||
}
|
||||
}
|
||||
else if (line.ToLower().StartsWith("palflag"))
|
||||
{
|
||||
bool pal = ParseHeader(line, "palFlag") == "1";
|
||||
m.Header[HeaderKeys.PAL] = pal.ToString();
|
||||
}
|
||||
else if (line.ToLower().StartsWith("ispal"))
|
||||
{
|
||||
bool pal = ParseHeader(line, "isPal") == "1";
|
||||
|
@ -739,12 +657,6 @@ namespace BizHawk.Client.Common
|
|||
return m;
|
||||
}
|
||||
|
||||
// MC2 file format: http://code.google.com/p/pcejin/wiki/MC2
|
||||
private static BkmMovie ImportMc2(string path, out string errorMsg, out string warningMsg)
|
||||
{
|
||||
return ImportText(path, out errorMsg, out warningMsg);
|
||||
}
|
||||
|
||||
// MMV file format: http://tasvideos.org/MMV.html
|
||||
private static BkmMovie ImportMmv(string path, out string errorMsg, out string warningMsg)
|
||||
{
|
||||
|
@ -1471,11 +1383,5 @@ namespace BizHawk.Client.Common
|
|||
fs.Close();
|
||||
return m;
|
||||
}
|
||||
|
||||
// YMV file format: https://code.google.com/p/yabause-rr/wiki/YMVfileformat
|
||||
private static BkmMovie ImportYmv(string path, out string errorMsg, out string warningMsg)
|
||||
{
|
||||
return ImportText(path, out errorMsg, out warningMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue