Merge remote-tracking branch 'remotes/adituv-bizhawk/MovieReflection'

Conflicts:
	BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs
This commit is contained in:
zeromus 2015-10-03 17:38:42 -05:00
commit a92cdf4730
6 changed files with 580 additions and 62 deletions

View File

@ -158,6 +158,7 @@
<Compile Include="movie\bk2\Bk2Movie.HeaderApi.cs">
<DependentUpon>Bk2Movie.cs</DependentUpon>
</Compile>
<Compile Include="movie\import\PXMImport.cs" />
<Compile Include="movie\tasproj\StateManagerState.cs" />
<Compile Include="movie\tasproj\TasBranch.cs" />
<Compile Include="movie\tasproj\TasMovie.History.cs" />

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using BizHawk.Common;
using BizHawk.Common.BufferExtensions;
@ -53,7 +54,7 @@ namespace BizHawk.Client.Common
if (!string.IsNullOrWhiteSpace(warningMsg))
{
messageCallback(warningMsg);
}
else
{
@ -73,23 +74,72 @@ namespace BizHawk.Client.Common
warningMsg = string.Empty;
string ext = path != null ? Path.GetExtension(path).ToUpper() : string.Empty;
// TODO: reflect off the assembly and find an IMovieImporter with the appropriate ImportExtension metadata
//if (ext == ".FM2")
//{
// var result = new Fm2Import().Import(path);
// errorMsg = result.Errors.First();
// warningMsg = result.Errors.First();
// return result.Movie;
//}
if (ext == ".PJM")
if (UsesLegacyImporter(ext))
{
var result = new PJMImport().Import(path);
errorMsg = result.Errors.First();
warningMsg = result.Errors.First();
return result.Movie;
return LegacyImportFile(ext, path, out errorMsg, out warningMsg).ToBk2();
}
var importers = ImportersForExtension(ext);
var importerType = importers.FirstOrDefault();
if (importerType == default(Type))
{
errorMsg = "No importer found for file type " + ext;
return null;
}
// Create a new instance of the importer class using the no-argument constructor
IMovieImport importer = importerType.GetConstructor(new Type[] { })
.Invoke(new object[] { }) as IMovieImport;
Bk2Movie movie = null;
try
{
var result = importer.Import(path);
if (result.Errors.Count() > 0) errorMsg = result.Errors.First();
if (result.Warnings.Count() > 0) warningMsg = result.Warnings.First();
movie = result.Movie;
}
catch (Exception ex)
{
errorMsg = ex.ToString();
}
return movie;
}
private static IEnumerable<Type> ImportersForExtension(string ext)
{
var info = typeof(MovieImport).Module;
var importers = from t in info.GetTypes()
where typeof(IMovieImport).IsAssignableFrom(t)
&& TypeImportsExtension(t, ext)
select t;
return importers;
}
private static bool TypeImportsExtension(Type t, string ext)
{
var attrs = (ImportExtension[])t.GetCustomAttributes(typeof(ImportExtension), inherit: false);
if (attrs.Any(a => a.Extension.ToUpper() == ext.ToUpper()))
{
return true;
}
else
{
return false;
}
}
private static BkmMovie LegacyImportFile(string ext, string path, out string errorMsg, out string warningMsg)
{
errorMsg = string.Empty;
warningMsg = string.Empty;
BkmMovie m = new BkmMovie();
try
@ -149,16 +199,23 @@ namespace BizHawk.Client.Common
errorMsg = except.ToString();
}
// Hack
return m.ToBk2();
return m;
}
// Return whether or not the type of file provided can currently be imported.
public static bool IsValidMovieExtension(string extension)
{
// TODO: Other movie formats that don't use a legacy importer (PJM/PXM, etc),
// when those are implemented
return UsesLegacyImporter(extension);
}
// Return whether or not the type of file provided is currently imported by a legacy (i.e. to BKM not BK2) importer
public static bool UsesLegacyImporter(string extension)
{
string[] extensions =
{
"FCM", "FM2", "FMV", "GMV", "MCM", "MC2", "MMV", "NMV", "LSMV", "SMV", "VBM", "VMV", "YMV", "ZMV"
"BKM", "FCM", "FM2", "FMV", "GMV", "MCM", "MC2", "MMV", "NMV", "LSMV", "SMV", "VBM", "VMV", "YMV", "ZMV"
};
return extensions.Any(ext => extension.ToUpper() == "." + ext);
}
@ -213,7 +270,7 @@ namespace BizHawk.Client.Common
controller = "Saturn Controller";
break;
}
var controllers = new SimpleController {Type = new ControllerDefinition {Name = controller}};
var controllers = new SimpleController { Type = new ControllerDefinition { Name = controller } };
// Split up the sections of the frame.
string[] sections = line.Split('|');
if (ext == ".FM2" && sections.Length >= 2 && sections[1].Length != 0)
@ -643,7 +700,7 @@ namespace BizHawk.Client.Common
m.Header[HeaderKeys.AUTHOR] = author;
// Advance to first byte of input data.
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
string[] buttons = { "A", "B", "Select", "Start", "Up", "Down", "Left", "Right" };
bool fds = false;
bool fourscore = false;
@ -832,7 +889,7 @@ namespace BizHawk.Client.Common
else
{
FDS = false;
}
m.Header[HeaderKeys.PLATFORM] = "NES";
@ -874,7 +931,7 @@ namespace BizHawk.Client.Common
*/
m.Header[HeaderKeys.PAL] = "False";
// 090 frame data begins here
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
/*
* 01 Right
* 02 Left
@ -1378,7 +1435,7 @@ namespace BizHawk.Client.Common
r.ReadBytes(103);
// TODO: Verify if NTSC/"PAL" mode used for the movie can be detected or not.
// 100 variable Input data
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = name + " Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = name + " Controller" } };
int bytes = 256;
// The input stream consists of 1 byte for power-on and reset, and then X bytes per each input port per frame.
if (platform == "nes")
@ -1499,7 +1556,7 @@ namespace BizHawk.Client.Common
// 00e4-00f3: binary: rom MD5 digest
byte[] md5 = r.ReadBytes(16);
m.Header[MD5] = string.Format("{0:x8}", md5.BytesToHexString().ToLower());
var controllers = new SimpleController { Type = new ControllerDefinition { Name = "SMS Controller" }};
var controllers = new SimpleController { Type = new ControllerDefinition { Name = "SMS Controller" } };
/*
76543210
* bit 0 (0x01): up
@ -1724,7 +1781,7 @@ namespace BizHawk.Client.Common
// ... 4-byte little-endian unsigned int: length of controller data in bytes
uint length = r.ReadUInt32();
// ... (variable) controller data
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
/*
Standard controllers store data in the following format:
* 01: A
@ -1827,7 +1884,7 @@ namespace BizHawk.Client.Common
* bit 4: controller 5 in use
* other: reserved, set to 0
*/
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "SNES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "SNES Controller" } };
bool[] controllersUsed = new bool[5];
for (int controller = 1; controller <= controllersUsed.Length; controller++)
{
@ -1944,7 +2001,7 @@ namespace BizHawk.Client.Common
{
"Right", "Left", "Down", "Up", "Start", "Select", "Y", "B", "R", "L", "X", "A"
};
for (int frame = 0; frame <= frameCount; frame++)
{
controllers["Reset"] = true;
@ -2139,16 +2196,16 @@ namespace BizHawk.Client.Common
// bit 2: if "1", movie is for the SGB system
bool is_sgb = (((flags >> 2) & 0x1) != 0);
// other: reserved, set to 0
// (At most one of bits 0, 1, 2 can be "1")
//if (!(is_gba ^ is_gbc ^ is_sgb) && (is_gba || is_gbc || is_sgb)) //TODO: adelikat: this doesn't do what the comment above suggests it is trying to check for, it is always false!
//{
//errorMsg = "This is not a valid .VBM file.";
//r.Close();
//fs.Close();
//return null;
//errorMsg = "This is not a valid .VBM file.";
//r.Close();
//fs.Close();
//return null;
//}
// (If all 3 of these bits are "0", it is for regular GB.)
string platform = "GB";
if (is_gba)
@ -2238,7 +2295,7 @@ namespace BizHawk.Client.Common
string movieDescription = NullTerminated(r.ReadStringFixedAscii(128));
m.Comments.Add(COMMENT + " " + movieDescription);
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController {Type = new ControllerDefinition()};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition() };
if (platform != "GBA")
{
controllers.Type.Name = "Gameboy Controller";
@ -2268,7 +2325,7 @@ namespace BizHawk.Client.Common
* 00 40 Down motion sensor
* 00 80 Up motion sensor
*/
string[] other =
string[] other =
{
"Reset (old timing)" , "Reset (new timing since version 1.1)", "Left motion sensor",
"Right motion sensor", "Down motion sensor", "Up motion sensor"
@ -2416,7 +2473,7 @@ namespace BizHawk.Client.Common
return m;
}
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
/*
* 01 A
* 02 B
@ -2653,7 +2710,7 @@ namespace BizHawk.Client.Common
uint savestateSize = (uint)((r.ReadByte() | (r.ReadByte() << 8) | (r.ReadByte() << 16)) & 0x7FFFFF);
// Next follows a ZST format savestate.
r.ReadBytes((int)savestateSize);
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "SNES Controller"}};
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "SNES Controller" } };
/*
* bit 11: A
* bit 10: X

View File

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Cores.Sony.PSX;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace BizHawk.Client.Common
{
@ -11,7 +10,418 @@ namespace BizHawk.Client.Common
{
protected override void RunImport()
{
// TODO
Bk2Movie movie = Result.Movie;
MiscHeaderInfo info;
movie.HeaderEntries[HeaderKeys.PLATFORM] = "PSX";
using (var fs = SourceFile.OpenRead())
{
using (var br = new BinaryReader(fs))
{
info = parseHeader(movie, "PJM ", br);
fs.Seek(info.controllerDataOffset, SeekOrigin.Begin);
if (info.binaryFormat)
{
parseBinaryInputLog(br, movie, info);
}
else
{
parseTextInputLog(br, movie, info);
}
}
}
movie.Save();
}
protected MiscHeaderInfo parseHeader(Bk2Movie movie, string expectedMagic, BinaryReader br)
{
var info = new MiscHeaderInfo();
string magic = new string(br.ReadChars(4));
if (magic != expectedMagic)
{
Result.Errors.Add("Not a " + expectedMagic + "file: invalid magic number in file header.");
return info;
}
UInt32 movieVersionNumber = br.ReadUInt32();
if (movieVersionNumber != 2)
{
Result.Warnings.Add(String.Format("Unexpected movie version: got {0}, expecting 2", movieVersionNumber));
}
// 008: UInt32 emulator version.
br.ReadUInt32();
byte flags = br.ReadByte();
byte flags2 = br.ReadByte();
if ((flags & 0x02) != 0)
{
Result.Errors.Add("Movie starts from savestate; this is currently unsupported.");
}
if ((flags & 0x04) != 0)
{
movie.HeaderEntries[HeaderKeys.PAL] = "1";
}
if ((flags & 0x08) != 0)
{
Result.Errors.Add("Movie contains embedded memory cards; this is currently unsupported.");
}
if ((flags & 0x10) != 0)
{
Result.Errors.Add("Movie contains embedded cheat list; this is currently unsupported.");
}
if ((flags & 0x20) != 0 || (flags2 & 0x06) != 0)
{
Result.Errors.Add("Movie relies on emulator hacks; this is currently unsupported.");
}
if ((flags & 0x40) != 0)
{
info.binaryFormat = false;
}
if ((flags & 0x80) != 0 || (flags2 & 0x01) != 0)
{
Result.Errors.Add("Movie uses multitap; this is currently unsupported.");
return info;
}
// Player 1 controller type
switch (br.ReadByte())
{
// It seems to be inconsistent in the files I looked at which of these is used
// to mean no controller present.
case 0:
case 8:
info.player1Type = OctoshockDll.ePeripheralType.None;
break;
case 4:
info.player1Type = OctoshockDll.ePeripheralType.Pad;
break;
case 7:
info.player1Type = OctoshockDll.ePeripheralType.DualShock;
break;
default:
Result.Errors.Add("Movie has unrecognised controller type for Player 1.");
return info;
}
// Player 2 controller type
switch (br.ReadByte())
{
case 0:
case 8:
info.player1Type = OctoshockDll.ePeripheralType.None;
break;
case 4:
info.player1Type = OctoshockDll.ePeripheralType.Pad;
break;
case 7:
info.player1Type = OctoshockDll.ePeripheralType.DualShock;
break;
default:
Result.Errors.Add("Movie has unrecognised controller type for Player 2.");
return info;
}
Octoshock.SyncSettings syncsettings = new Octoshock.SyncSettings();
syncsettings.FIOConfig.Devices8 =
new[] {
info.player1Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,
info.player2Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None
};
// Annoying kludge to force the json serializer to serialize the type name for "o" object.
// For just the "o" object to have type information, it must be cast to a superclass such
// that the TypeNameHandling.Auto decides to serialize the type as well as the object
// contents. As such, the object cast is NOT redundant
var jsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
};
movie.SyncSettingsJson = JsonConvert.SerializeObject(new { o = (object)syncsettings }, jsonSettings);
info.frameCount = br.ReadUInt32();
UInt32 rerecordCount = br.ReadUInt32();
movie.HeaderEntries[HeaderKeys.RERECORDS] = rerecordCount.ToString();
// 018: UInt32 savestateOffset
// 01C: UInt32 memoryCard1Offset
// 020: UInt32 memoryCard2Offset
// 024: UInt32 cheatListOffset
// 028: UInt32 cdRomIdOffset
// Source format is just the first up-to-8 alphanumeric characters of the CD label,
// so not so useful.
br.ReadBytes(20);
info.controllerDataOffset = br.ReadUInt32();
UInt32 authorNameLength = br.ReadUInt32();
char[] authorName = br.ReadChars((int)authorNameLength);
movie.HeaderEntries[HeaderKeys.AUTHOR] = new string(authorName);
info.parseSuccessful = true;
return info;
}
protected void parseBinaryInputLog(BinaryReader br, Bk2Movie movie, MiscHeaderInfo info)
{
Octoshock.SyncSettings settings = new Octoshock.SyncSettings();
SimpleController controllers = new SimpleController();
settings.FIOConfig.Devices8 =
new[] {
info.player1Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,
info.player2Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None
};
controllers.Type = Octoshock.CreateControllerDefinition(settings);
string[] buttons = { "Select", "L3", "R3", "Start", "Up", "Right", "Down", "Left",
"L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross", "Square"};
bool isCdTrayOpen = false;
int cdNumber = 1;
for (int frame = 0; frame < info.frameCount; ++frame)
{
if (info.player1Type != OctoshockDll.ePeripheralType.None)
{
UInt16 controllerState = br.ReadUInt16();
// As L3 and R3 don't exist on a standard gamepad, handle them separately later. Unfortunately
// due to the layout, we handle select separately too first.
controllers["P1 Select"] = (controllerState & 0x1) != 0;
for (int button = 3; button < buttons.Length; button++)
{
controllers["P1 " + buttons[button]] = (((controllerState >> button) & 0x1) != 0);
if (((controllerState >> button) & 0x1) != 0 && button > 15)
{
continue;
}
}
if (info.player1Type == OctoshockDll.ePeripheralType.DualShock)
{
controllers["P1 L3"] = (controllerState & 0x2) != 0;
controllers["P1 R3"] = (controllerState & 0x4) != 0;
Tuple<string, float> leftX = new Tuple<string, float>("P1 LStick X", (float)br.ReadByte());
Tuple<string, float> leftY = new Tuple<string, float>("P1 LStick Y", (float)br.ReadByte());
Tuple<string, float> rightX = new Tuple<string, float>("P1 RStick X", (float)br.ReadByte());
Tuple<string, float> rightY = new Tuple<string, float>("P1 RStick Y", (float)br.ReadByte());
controllers.AcceptNewFloats(new[] { leftX, leftY, rightX, rightY });
}
}
if (info.player2Type != OctoshockDll.ePeripheralType.None)
{
UInt16 controllerState = br.ReadUInt16();
for (int button = 0; button < buttons.Length; button++)
{
controllers["P2 " + buttons[button]] = (((controllerState >> button) & 0x1) != 0);
if (((controllerState >> button) & 0x1) != 0 && button > 15)
{
continue;
}
}
if (info.player2Type == OctoshockDll.ePeripheralType.DualShock)
{
Tuple<string, float> leftX = new Tuple<string, float>("P2 LStick X", (float)br.ReadByte());
Tuple<string, float> leftY = new Tuple<string, float>("P2 LStick Y", (float)br.ReadByte());
Tuple<string, float> rightX = new Tuple<string, float>("P2 RStick X", (float)br.ReadByte());
Tuple<string, float> rightY = new Tuple<string, float>("P2 RStick Y", (float)br.ReadByte());
controllers.AcceptNewFloats(new[] { leftX, leftY, rightX, rightY });
}
}
byte controlState = br.ReadByte();
controllers["Reset"] = (controlState & 0x02) != 0;
if ((controlState & 0x04) != 0)
{
if (isCdTrayOpen)
{
controllers["Close"] = true;
cdNumber++;
}
else
{
controllers["Open"] = true;
}
isCdTrayOpen = !isCdTrayOpen;
}
else
{
controllers["Close"] = false;
controllers["Open"] = false;
}
Tuple<string, float> discSelect = new Tuple<string, float>("Disc Select", cdNumber);
controllers.AcceptNewFloats(new[] { discSelect });
if ((controlState & 0xFC) != 0)
{
Result.Warnings.Add("Ignored toggle hack flag on frame " + frame.ToString());
}
movie.AppendFrame(controllers);
}
}
protected void parseTextInputLog(BinaryReader br, Bk2Movie movie, MiscHeaderInfo info)
{
Octoshock.SyncSettings settings = new Octoshock.SyncSettings();
SimpleController controllers = new SimpleController();
settings.FIOConfig.Devices8 =
new[] {
info.player1Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,
info.player2Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None
};
controllers.Type = Octoshock.CreateControllerDefinition(settings);
string[] buttons = { "Select", "L3", "R3", "Start", "Up", "Right", "Down", "Left",
"L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross", "Square"};
bool isCdTrayOpen = false;
int cdNumber = 1;
for (int frame = 0; frame < info.frameCount; ++frame)
{
if (info.player1Type != OctoshockDll.ePeripheralType.None)
{
// As L3 and R3 don't exist on a standard gamepad, handle them separately later. Unfortunately
// due to the layout, we handle select separately too first.
controllers["P1 Select"] = br.ReadChar() != '.';
if (info.player1Type == OctoshockDll.ePeripheralType.DualShock)
{
controllers["P1 L3"] = br.ReadChar() != '.';
controllers["P1 R3"] = br.ReadChar() != '.';
}
for (int button = 3; button < buttons.Length; button++)
{
controllers["P1 " + buttons[button]] = br.ReadChar() != '.';
}
if (info.player1Type == OctoshockDll.ePeripheralType.DualShock)
{
// The analog controls are encoded as four space-separated numbers with a leading space
string leftXRaw = new string(br.ReadChars(4)).Trim();
string leftYRaw = new string(br.ReadChars(4)).Trim();
string rightXRaw = new string(br.ReadChars(4)).Trim();
string rightYRaw = new string(br.ReadChars(4)).Trim();
Tuple<string, float> leftX = new Tuple<string, float>("P1 LStick X", float.Parse(leftXRaw));
Tuple<string, float> leftY = new Tuple<string, float>("P1 LStick Y", float.Parse(leftYRaw));
Tuple<string, float> rightX = new Tuple<string, float>("P1 RStick X", float.Parse(rightXRaw));
Tuple<string, float> rightY = new Tuple<string, float>("P1 RStick Y", float.Parse(rightYRaw));
controllers.AcceptNewFloats(new[] { leftX, leftY, rightX, rightY });
}
}
// Each controller is terminated with a pipeline.
br.ReadChar();
if (info.player2Type != OctoshockDll.ePeripheralType.None)
{
// As L3 and R3 don't exist on a standard gamepad, handle them separately later. Unfortunately
// due to the layout, we handle select separately too first.
controllers["P2 Select"] = br.ReadChar() != '.';
if (info.player2Type == OctoshockDll.ePeripheralType.DualShock)
{
controllers["P2 L3"] = br.ReadChar() != '.';
controllers["P2 R3"] = br.ReadChar() != '.';
}
for (int button = 3; button < buttons.Length; button++)
{
controllers["P2 " + buttons[button]] = br.ReadChar() != '.';
}
if (info.player2Type == OctoshockDll.ePeripheralType.DualShock)
{
// The analog controls are encoded as four space-separated numbers with a leading space
string leftXRaw = new string(br.ReadChars(4)).Trim();
string leftYRaw = new string(br.ReadChars(4)).Trim();
string rightXRaw = new string(br.ReadChars(4)).Trim();
string rightYRaw = new string(br.ReadChars(4)).Trim();
Tuple<string, float> leftX = new Tuple<string, float>("P2 LStick X", float.Parse(leftXRaw));
Tuple<string, float> leftY = new Tuple<string, float>("P2 LStick Y", float.Parse(leftYRaw));
Tuple<string, float> rightX = new Tuple<string, float>("P2 RStick X", float.Parse(rightXRaw));
Tuple<string, float> rightY = new Tuple<string, float>("P2 RStick Y", float.Parse(rightYRaw));
controllers.AcceptNewFloats(new[] { leftX, leftY, rightX, rightY });
}
}
// Each controller is terminated with a pipeline.
br.ReadChar();
byte controlState = br.ReadByte();
controllers["Reset"] = (controlState & 0x02) != 0;
if ((controlState & 0x04) != 0)
{
if (isCdTrayOpen)
{
controllers["Close"] = true;
cdNumber++;
}
else
{
controllers["Open"] = true;
}
isCdTrayOpen = !isCdTrayOpen;
}
else
{
controllers["Close"] = false;
controllers["Open"] = false;
}
Tuple<string, float> discSelect = new Tuple<string, float>("Disc Select", cdNumber);
controllers.AcceptNewFloats(new[] { discSelect });
if ((controlState & 0xFC) != 0)
{
Result.Warnings.Add("Ignored toggle hack flag on frame " + frame.ToString());
}
// Each controller is terminated with a pipeline.
br.ReadChar();
movie.AppendFrame(controllers);
}
}
protected class MiscHeaderInfo
{
public bool binaryFormat = true;
public UInt32 controllerDataOffset;
public UInt32 frameCount;
public OctoshockDll.ePeripheralType player1Type;
public OctoshockDll.ePeripheralType player2Type;
public bool parseSuccessful = false;
}
}
}

View File

@ -0,0 +1,44 @@
using System.IO;
namespace BizHawk.Client.Common.movie.import
{
// PXM files are directly compatible with binary-format PJM files, with the only
// difference being fewer flags implemented in the header, hence just calling the
// base class methods via a subclass.
//
// However, the magic number/file signature is slightly different, requiring some
// refactoring to avoid PXM-specific code in the PJMImport class.
[ImportExtension(".pxm")]
class PXMImport : PJMImport
{
protected override void RunImport()
{
Bk2Movie movie = Result.Movie;
MiscHeaderInfo info;
movie.HeaderEntries[HeaderKeys.PLATFORM] = "PSX";
using (var fs = SourceFile.OpenRead())
{
using (var br = new BinaryReader(fs))
{
info = parseHeader(movie, "PXM ", br);
fs.Seek(info.controllerDataOffset, SeekOrigin.Begin);
if (info.binaryFormat)
{
parseBinaryInputLog(br, movie, info);
}
else
{
parseTextInputLog(br, movie, info);
}
}
}
movie.Save();
}
}
}

View File

@ -455,7 +455,7 @@ namespace BizHawk.Client.EmuHawk
InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId),
Multiselect = true,
Filter = FormatFilter(
"Movie Files", "*.fm2;*.mc2;*.mcm;*.mmv;*.gmv;*.vbm;*.lsmv;*.fcm;*.fmv;*.vmv;*.nmv;*.smv;*.ymv;*.zmv;*.bkm",
"Movie Files", "*.fm2;*.mc2;*.mcm;*.mmv;*.gmv;*.vbm;*.lsmv;*.fcm;*.fmv;*.vmv;*.nmv;*.smv;*.ymv;*.zmv;*.bkm;*.pjm;*.pxm",
"FCEUX", "*.fm2",
"PCEjin/Mednafen", "*.mc2;*.mcm",
"Dega", "*.mmv",
@ -469,6 +469,8 @@ namespace BizHawk.Client.EmuHawk
"Snes9x", "*.smv",
"Yabause", "*.ymv",
"ZSNES", "*.zmv",
"PSXjin", "*.pjm",
"PCSX", "*.pxm",
"BizHawk Bkm", "*.bkm",
"All Files", "*.*"),
RestoreDirectory = false

View File

@ -36,21 +36,18 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
{
public string SystemId { get { return "PSX"; } }
private void SetControllerButtons()
public static ControllerDefinition CreateControllerDefinition(SyncSettings syncSettings)
{
ControllerDefinition = new ControllerDefinition();
ControllerDefinition.Name = "PSX DualShock Controller"; // <-- for compatibility
ControllerDefinition definition = new ControllerDefinition();
definition.Name = "PSX DualShock Controller"; // <-- for compatibility
//ControllerDefinition.Name = "PSX FrontIO"; // TODO - later rename to this, I guess, so it's less misleading. don't want to wreck keybindings yet.
ControllerDefinition.BoolButtons.Clear();
ControllerDefinition.FloatControls.Clear();
var cfg = _SyncSettings.FIOConfig.ToLogical();
var cfg = syncSettings.FIOConfig.ToLogical();
for (int i = 0; i < cfg.NumPlayers; i++)
{
int pnum = i + 1;
ControllerDefinition.BoolButtons.AddRange(new[]
definition.BoolButtons.AddRange(new[]
{
"P" + pnum + " Up",
"P" + pnum + " Down",
@ -72,11 +69,11 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
if (type == OctoshockDll.ePeripheralType.DualShock || type == OctoshockDll.ePeripheralType.DualAnalog)
{
ControllerDefinition.BoolButtons.Add("P" + pnum + " L3");
ControllerDefinition.BoolButtons.Add("P" + pnum + " R3");
ControllerDefinition.BoolButtons.Add("P" + pnum + " MODE");
definition.BoolButtons.Add("P" + pnum + " L3");
definition.BoolButtons.Add("P" + pnum + " R3");
definition.BoolButtons.Add("P" + pnum + " MODE");
ControllerDefinition.FloatControls.AddRange(new[]
definition.FloatControls.AddRange(new[]
{
"P" + pnum + " LStick X",
"P" + pnum + " LStick Y",
@ -84,27 +81,34 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
"P" + pnum + " RStick Y"
});
ControllerDefinition.FloatRanges.Add(new[] { 0.0f, 128.0f, 255.0f });
ControllerDefinition.FloatRanges.Add(new[] { 255.0f, 128.0f, 0.0f });
ControllerDefinition.FloatRanges.Add(new[] { 0.0f, 128.0f, 255.0f });
ControllerDefinition.FloatRanges.Add(new[] { 255.0f, 128.0f, 0.0f });
definition.FloatRanges.Add(new[] { 0.0f, 128.0f, 255.0f });
definition.FloatRanges.Add(new[] { 255.0f, 128.0f, 0.0f });
definition.FloatRanges.Add(new[] { 0.0f, 128.0f, 255.0f });
definition.FloatRanges.Add(new[] { 255.0f, 128.0f, 0.0f });
}
}
ControllerDefinition.BoolButtons.AddRange(new[]
definition.BoolButtons.AddRange(new[]
{
"Open",
"Close",
"Reset"
});
ControllerDefinition.FloatControls.Add("Disc Select");
definition.FloatControls.Add("Disc Select");
ControllerDefinition.FloatRanges.Add(
definition.FloatRanges.Add(
//new[] {-1f,-1f,-1f} //this is carefully chosen so that we end up with a -1 disc by default (indicating that it's never been set)
//hmm.. I don't see why this wouldn't work
new[] { 0f, 1f, 1f }
);
return definition;
}
private void SetControllerButtons()
{
ControllerDefinition = CreateControllerDefinition(_SyncSettings);
}
public string BoardName { get { return null; } }